public EmitConvert ( |
||
expr | ||
to | TypeSymbol | |
return | void |
internal override void Generate(CodeGenerator cg) { Contract.ThrowIfNull(Condition); if (IsLoop) // perf { cg.Builder.EmitBranch(ILOpCode.Br, this.Condition); // { cg.GenerateScope(TrueTarget, NextBlock.Ordinal); // } // if (Condition) cg.EmitSequencePoint(this.Condition.PhpSyntax); cg.Builder.MarkLabel(this.Condition); cg.EmitConvert(this.Condition, cg.CoreTypes.Boolean); cg.Builder.EmitBranch(ILOpCode.Brtrue, TrueTarget); } else { // if (Condition) cg.EmitSequencePoint(this.Condition.PhpSyntax); cg.EmitConvert(this.Condition, cg.CoreTypes.Boolean); cg.Builder.EmitBranch(ILOpCode.Brfalse, FalseTarget); // { cg.GenerateScope(TrueTarget, NextBlock.Ordinal); // } } cg.Scope.ContinueWith(FalseTarget); }
/// <summary> /// Emit runtime chain. /// </summary> /// <returns>Runtime chain value type pushed on top of the stack.</returns> public TypeSymbol EmitRuntimeChain(CodeGenerator cg) { // create and initialize the chain struct var chaintmp = cg.GetTemporaryLocal(this.Type, true); cg.Builder.EmitLocalAddress(chaintmp); cg.Builder.EmitOpCode(ILOpCode.Initobj); cg.Builder.EmitSymbolToken(cg.Module, cg.Diagnostics, this.Type, null); // fill in the fields for (var element = this; element != null; element = element.Next) { Debug.Assert(element.Type.IsValueType); if (element.Fields != null) { foreach (var pair in element.Fields) { // Template: ADDR chain.Next[.Next] cg.Builder.EmitLocalAddress(chaintmp); for (var x = this; x != element; x = x.Next) { var nextfield = new FieldPlace_Raw((FieldSymbol)x.Type.GetMembers("Next").Single(), cg.Module); nextfield.EmitLoadAddress(cg.Builder); } // Template: .<Field> = <Value> var valuefield = new FieldPlace_Raw((FieldSymbol)element.Type.GetMembers(pair.Key).Single(), cg.Module); valuefield.EmitStorePrepare(cg.Builder); if (pair.Value is BoundExpression valueexpr) { cg.EmitConvert(valueexpr, valuefield.Type); } else if (pair.Value is BoundVariableName nameexpr) { cg.EmitConvert(nameexpr.EmitVariableName(cg), 0, valuefield.Type); } else { throw Peachpie.CodeAnalysis.Utilities.ExceptionUtilities.UnexpectedValue(pair.Value); } valuefield.EmitStore(cg.Builder); } } } // cg.Builder.EmitLocalLoad(chaintmp); // return(this.Type); }
/// <summary> /// Generates ghost method body that calls <c>this</c> method. /// </summary> static void GenerateGhostBody(PEModuleBuilder module, DiagnosticBag diagnostic, MethodSymbol method, SynthesizedMethodSymbol ghost) { var containingtype = ghost.ContainingType; var body = MethodGenerator.GenerateMethodBody(module, ghost, (il) => { // $this var thisPlace = ghost.HasThis ? new ArgPlace(containingtype, 0) : null; // Context var ctxPlace = thisPlace != null && ghost.ContainingType is SourceTypeSymbol sourcetype ? (sourcetype.ContextStore != null ? new FieldPlace(thisPlace, sourcetype.ContextStore, module) : null) : (IPlace) new ArgPlace(module.Compilation.CoreTypes.Context, 0); // .callvirt bool callvirt = ghost.ExplicitOverride != null && ghost.ExplicitOverride.ContainingType.IsInterface; // implementing interface, otherwise we should be able to call specific method impl. non-virtually via ghost var cg = new CodeGenerator(il, module, diagnostic, module.Compilation.Options.OptimizationLevel, false, containingtype, ctxPlace, thisPlace) { DebugRoutine = ghost, }; // return (T){routine}(p0, ..., pN); cg.EmitConvert(cg.EmitForwardCall(method, ghost, callvirt: callvirt), 0, ghost.ReturnType); cg.EmitRet(ghost.ReturnType); }, null, diagnostic, false); module.SetMethodBody(ghost, body); }
/// <summary> /// Generates ghost method body that calls <c>this</c> method. /// </summary> static void GenerateGhostBody(PEModuleBuilder module, DiagnosticBag diagnostic, MethodSymbol method, SynthesizedMethodSymbol ghost) { var containingtype = ghost.ContainingType; var body = MethodGenerator.GenerateMethodBody(module, ghost, (il) => { // $this var thisPlace = ghost.HasThis ? new ArgPlace(containingtype, 0) : null; // Context var ctxPlace = thisPlace != null && ghost.ContainingType is SourceTypeSymbol sourcetype ? new FieldPlace(thisPlace, sourcetype.ContextStore) : (IPlace) new ArgPlace(module.Compilation.CoreTypes.Context, 0); var cg = new CodeGenerator(il, module, diagnostic, module.Compilation.Options.OptimizationLevel, false, containingtype, ctxPlace, thisPlace); // return (T){routine}(p0, ..., pN); cg.EmitConvert(cg.EmitForwardCall(method, ghost), 0, ghost.ReturnType); cg.EmitRet(ghost.ReturnType); }, null, diagnostic, false); module.SetMethodBody(ghost, body); }
public TypeSymbol EmitLoad(ILBuilder il) { if (_loc != null) { il.EmitLocalLoad(_loc); } else { // <temporary>[name] Debug.Assert(_cg.TemporalLocalsPlace != null); Debug.Assert(_tempName != null); _cg.TemporalLocalsPlace.EmitLoad(il); _cg.EmitIntStringKey(_tempName); _cg.EmitConvert(_cg.EmitCall(System.Reflection.Metadata.ILOpCode.Callvirt, _cg.CoreMethods.PhpArray.GetItemValue_IntStringKey), 0, Type); } return(Type); }
internal void EmitInit(CodeGenerator cg) { var fldplace = new FieldPlace(IsStatic ? null : new ArgPlace(ContainingType, 0), this); if (this.Initializer != null) { // fld = <initializer> fldplace.EmitStorePrepare(cg.Builder); cg.EmitConvert(this.Initializer, this.Type); fldplace.EmitStore(cg.Builder); } else { // fld = default(type) cg.EmitInitializePlace(fldplace); } }
/// <summary> /// Emits name of bound type. /// </summary> /// <param name="cg"></param> internal void EmitClassName(CodeGenerator cg) { if (TypeExpression != null) { cg.EmitConvert(TypeExpression, cg.CoreTypes.String); } else { if (_typeRef is PrimitiveTypeRef) { throw new InvalidOperationException(); } else if (_typeRef is TranslatedTypeRef || _typeRef is ClassTypeRef) { var classname = ((INamedTypeRef)_typeRef).ClassName; cg.Builder.EmitStringConstant(classname.ToString()); } else { throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(_typeRef); } } }
internal override void Emit(CodeGenerator cg) { cg.EmitSequencePoint(this.PhpSyntax); var rtype = cg.Routine.ReturnType; var rvoid = rtype.SpecialType == SpecialType.System_Void; // if (this.Returned == null) { if (rvoid) { // <void> } else { // <default> cg.EmitLoadDefault(rtype, cg.Routine.ResultTypeMask); } } else { if (rvoid) { // <expr>; cg.EmitPop(this.Returned.Emit(cg)); } else { // return (T)<expr>; cg.EmitConvert(this.Returned, rtype); } } // .ret cg.EmitRet(rtype); }
internal override TypeSymbol Emit(CodeGenerator cg) { // new PhpString() cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpString); // TODO: overload for 2, 3, 4 parameters directly // <PhpString>.Append(<expr>) foreach (var x in this.ArgumentsInSourceOrder) { var expr = x.Value; if (IsEmpty(expr)) continue; // cg.Builder.EmitOpCode(ILOpCode.Dup); // PhpString var t = cg.Emit(expr); if (t == cg.CoreTypes.PhpString) { cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpString.Append_PhpString); } else { // TODO: PhpValue -> PhpString (instead of String) cg.EmitConvert(t, 0, cg.CoreTypes.String); cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpString.Append_String); } // cg.Builder.EmitOpCode(ILOpCode.Nop); } // return cg.CoreTypes.PhpString; }
public void EmitStore(CodeGenerator cg, TypeSymbol valueType) { var type = _place.TypeOpt; // Write Ref if (_access.IsWriteRef) { if (valueType != cg.CoreTypes.PhpAlias) { Debug.Assert(false, "caller should get aliased value"); cg.EmitConvertToPhpValue(valueType, 0); valueType = cg.Emit_PhpValue_MakeAlias(); } // if (type == cg.CoreTypes.PhpAlias) { // <place> = <alias> _place.EmitStore(cg.Builder); } else if (type == cg.CoreTypes.PhpValue) { // <place> = PhpValue.Create(<alias>) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.Create_PhpAlias); _place.EmitStore(cg.Builder); } else { Debug.Assert(false, "Assigning alias to non-aliasable variable."); cg.EmitConvert(valueType, 0, type); _place.EmitStore(cg.Builder); } } else if (_access.IsUnset) { Debug.Assert(valueType == null); // <place> = if (type == cg.CoreTypes.PhpAlias) { // new PhpAlias(void) cg.Emit_PhpValue_Void(); cg.Emit_PhpValue_MakeAlias(); } else if (type.IsReferenceType) { // null cg.Builder.EmitNullConstant(); } else { // default(T) cg.EmitLoadDefaultOfValueType(type); } _place.EmitStore(cg.Builder); } else { // if (type == cg.CoreTypes.PhpAlias) { // <place>.Value = <value> cg.EmitConvertToPhpValue(valueType, 0); cg.Emit_PhpAlias_SetValue(); } else if (type == cg.CoreTypes.PhpValue) { if (_thint.IsRef) { // Operators.SetValue(ref <place>, (PhpValue)<value>); cg.EmitConvertToPhpValue(valueType, 0); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.SetValue_PhpValueRef_PhpValue); } else { // <place> = <value> cg.EmitConvertToPhpValue(valueType, 0); _place.EmitStore(cg.Builder); } } else { cg.EmitConvert(valueType, 0, type); _place.EmitStore(cg.Builder); } } }
/// <summary> /// Emits check for values equality. /// Lefts <c>bool</c> on top of evaluation stack. /// </summary> internal static TypeSymbol EmitEquality(CodeGenerator cg, TypeSymbol xtype, BoundExpression right) { TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Boolean: // bool == y.ToBoolean() cg.EmitConvert(right, cg.CoreTypes.Boolean); cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; case SpecialType.System_Int32: // i4 -> i8 cg.Builder.EmitOpCode(ILOpCode.Conv_i8); goto case SpecialType.System_Int64; case SpecialType.System_Int64: ytype = cg.Emit(right); // if (ytype.SpecialType == SpecialType.System_Int32) { cg.Builder.EmitOpCode(ILOpCode.Conv_i8); // i4 -> i8 ytype = cg.CoreTypes.Long; } // if (ytype.SpecialType == SpecialType.System_Int64) { // i8 == i8 cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 == r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_double) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Boolean) { // i8 == bool return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_bool) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_String) { // i8 == string return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_string) .Expect(SpecialType.System_Boolean); } // value ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(i8, value) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_long_value); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|long|int -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 == r8 cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if (ytype.SpecialType == SpecialType.System_String) { // r8 == string return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_double_string) .Expect(SpecialType.System_Boolean); } // value ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(double, value) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_double_value); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; case SpecialType.System_String: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Int32) { // i4 -> i8 cg.Builder.EmitOpCode(ILOpCode.Conv_i8); ytype = cg.CoreTypes.Long; } if (ytype.SpecialType == SpecialType.System_Int64) { // string == i8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_long) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Boolean) { // string == bool return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_bool) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Double) { // string == r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_double) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_String) { // compare(string, string) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_string).Expect(SpecialType.System_Int32); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; } // value ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(string, value) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_value); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; //case SpecialType.System_Object: // goto default; default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // number == i8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_long) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Double) { // number == r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_double) .Expect(SpecialType.System_Boolean); } else if (ytype == cg.CoreTypes.PhpNumber) { // number == number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_number) .Expect(SpecialType.System_Boolean); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // number == value return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_PhpValue) .Expect(SpecialType.System_Boolean); } } else { // TODO: xtype: PhpArray, ... xtype = cg.EmitConvertToPhpValue(xtype, 0); // TODO: overloads for type of <right> ytype = cg.EmitConvertToPhpValue(cg.Emit(right), right.TypeRefMask); // value == value return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.Eq_PhpValue_PhpValue) .Expect(SpecialType.System_Boolean); } } }
/// <summary> /// Emits binary boolean operation (AND or OR). /// </summary> /// <param name="cg">A code generator.</param> /// <param name="isAnd">Whether to emit AND, otherwise OR.</param> /// <returns>A type code of the result.</returns> TypeSymbol EmitBinaryBooleanOperation(CodeGenerator cg, bool isAnd) { var boolean = cg.CoreTypes.Boolean; // typeof(bool) var il = cg.Builder; var partial_eval_label = new object(); var end_label = new object(); // IF [!]<(bool) Left> THEN GOTO partial_eval; cg.EmitConvert(Left, cg.CoreTypes.Boolean); il.EmitBranch(isAnd ? ILOpCode.Brfalse : ILOpCode.Brtrue, partial_eval_label); // <RESULT> = <(bool) Right>; cg.EmitConvert(Right, cg.CoreTypes.Boolean); // GOTO end; il.EmitBranch(ILOpCode.Br, end_label); il.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder // partial_eval: il.MarkLabel(partial_eval_label); il.EmitOpCode(isAnd ? ILOpCode.Ldc_i4_0 : ILOpCode.Ldc_i4_1, 1); // end: il.MarkLabel(end_label); // return boolean; }
internal static TypeSymbol EmitBitOr(CodeGenerator cg, BoundExpression left, BoundExpression right) { // most common cases: if (cg.IsLongOnly(left.TypeRefMask) || cg.IsLongOnly(right.TypeRefMask)) { // i64 | i64 : i64 cg.EmitConvert(left, cg.CoreTypes.Long); cg.EmitConvert(right, cg.CoreTypes.Long); cg.Builder.EmitOpCode(ILOpCode.Or); return cg.CoreTypes.Long; } // return EmitBitOr(cg, cg.Emit(left), right); }
internal override TypeSymbol Emit(CodeGenerator cg) { // new PhpArray(count) cg.Builder.EmitIntConstant(_items.Length); var result = cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpArray_int) .Expect(cg.CoreTypes.PhpArray); foreach (var x in _items) { // <PhpArray> cg.Builder.EmitOpCode(ILOpCode.Dup); // key if (x.Key != null) { cg.EmitIntStringKey(x.Key); } // value | alias Debug.Assert(x.Value != null); var byref = x.Value.Access.IsReadRef; var valuetype = byref ? cg.CoreTypes.PhpAlias : cg.CoreTypes.PhpValue; cg.EmitConvert(x.Value, valuetype); if (x.Key != null) { if (byref) // .SetItemAlias( key, PhpAlias ) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.SetItemAlias_IntStringKey_PhpAlias); else // .SetItemValue( key, PhpValue ) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.SetItemValue_IntStringKey_PhpValue); } else { if (byref) // PhpValue.Create( PhpAlias ) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.Create_PhpAlias); // .AddValue( PhpValue ) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.AddValue_PhpValue); } } // return result; }
static TypeSymbol EmitAppend(CodeGenerator cg, TypeSymbol xtype, BoundExpression y) { if (xtype == cg.CoreTypes.PhpString) { // x.Append(y); return x; cg.Builder.EmitOpCode(ILOpCode.Dup); cg.EmitConvert(y, cg.CoreTypes.String); cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpString.Append_String); // return xtype; } else { // concat(x, y) cg.EmitConvert(xtype, 0, cg.CoreTypes.String); cg.EmitConvert(y, cg.CoreTypes.String); return cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpString_string_string); } }
internal static TypeSymbol EmitDiv(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, TypeSymbol resultTypeOpt = null) { var il = cg.Builder; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> int64 TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { il.EmitOpCode(ILOpCode.Div); return xtype; // r8 } // double / value : double cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_double_PhpValue); case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype == cg.CoreTypes.PhpNumber) { // long / number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Division_long_number) .Expect(cg.CoreTypes.PhpNumber); } // long / value : number cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_long_PhpValue); default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype == cg.CoreTypes.PhpNumber) { // nmumber / number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Division_number_number) .Expect(cg.CoreTypes.PhpNumber); } } // x -> PhpValue xtype = cg.EmitConvertToPhpValue(xtype, 0); cg.EmitConvert(right, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // value / value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_PhpValue_PhpValue); } }
/// <summary> /// Emits comparison operator pushing <c>bool</c> (<c>i4</c> of value <c>0</c> or <c>1</c>) onto the evaluation stack. /// </summary> /// <returns>Resulting type code pushed onto the top of evaliuation stack.</returns> internal static TypeSymbol EmitLtGt(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, bool lt) { TypeSymbol ytype; var il = cg.Builder; switch (xtype.SpecialType) { case SpecialType.System_Void: // Operators.CompareNull(value) throw new NotImplementedException(); case SpecialType.System_Int32: // i4 -> i8 il.EmitOpCode(ILOpCode.Conv_i8); goto case SpecialType.System_Int64; case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype.SpecialType == SpecialType.System_Int64) { il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 <> r8 return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.Operators.Clt_long_double : cg.CoreMethods.Operators.Cgt_long_double); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(i8, value) <> 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_long_value); il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } return cg.CoreTypes.Boolean; case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 <> r8 il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } else { // compare(r8, value) ytype = cg.EmitConvertToPhpValue(ytype, 0); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_double_value); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } return cg.CoreTypes.Boolean; case SpecialType.System_String: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_String) { // compare(string, string) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_string); } else if (ytype.SpecialType == SpecialType.System_Int64) { // compare(string, long) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_long); } else if (ytype.SpecialType == SpecialType.System_Double) { // compare(string, double) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_double); } else { // compare(string, value) ytype = cg.EmitConvertToPhpValue(ytype, 0); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_value); } // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; case SpecialType.System_Boolean: cg.EmitConvert(right, cg.CoreTypes.Boolean); ytype = cg.CoreTypes.Boolean; // compare(bool, bool) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_bool_bool); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype.SpecialType == SpecialType.System_Int64) { // number <> i8 return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.PhpNumber.lt_number_long : cg.CoreMethods.PhpNumber.gt_number_long) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Double) { // number <> r8 return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.PhpNumber.lt_number_double : cg.CoreMethods.PhpNumber.gt_number_double) .Expect(SpecialType.System_Boolean); } else if (ytype == cg.CoreTypes.PhpNumber) { // number <> number return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.PhpNumber.lt_number_number : cg.CoreMethods.PhpNumber.gt_number_number) .Expect(SpecialType.System_Boolean); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(number, value) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_number_value); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); // +1 on stack il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; } } else { xtype = cg.EmitConvertToPhpValue(xtype, 0); ytype = cg.Emit(right); // TODO: if (ytype.SpecialType == SpecialType.System_Boolean) ... // TODO: if (ytype.SpecialType == SpecialType.System_Int64) ... // TODO: if (ytype.SpecialType == SpecialType.System_String) ... // TODO: if (ytype.SpecialType == SpecialType.System_Double) ... // compare(value, value) ytype = cg.EmitConvertToPhpValue(ytype, right.TypeRefMask); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_value_value); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; } } }
public void EmitStorePrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt = null) { if (_lazyStoreCallSite == null) _lazyStoreCallSite = cg.Factory.StartCallSite("set_" + this.NameValueOpt); // callsite.Target callsite _lazyStoreCallSite.EmitLoadTarget(cg.Builder); _lazyStoreCallSite.Place.EmitLoad(cg.Builder); // instance InstanceCacheHolder.EmitInstance(instanceOpt, cg, Instance); // NameExpression in case of indirect call if (!_name.IsDirect) { cg.EmitConvert(_name.NameExpression, cg.CoreTypes.String); } }
public TypeSymbol EmitLoad(CodeGenerator cg) { // resolve actual return type TypeSymbol return_type; if (Access.EnsureObject) return_type = cg.CoreTypes.Object; else if (Access.EnsureArray) return_type = cg.CoreTypes.IPhpArray; else if (Access.IsReadRef) return_type = cg.CoreTypes.PhpAlias; else return_type = Access.TargetType ?? cg.CoreTypes.PhpValue; var args = new List<TypeSymbol>(); // NameExpression in case of indirect call if (!_name.IsDirect) { cg.EmitConvert(_name.NameExpression, cg.CoreTypes.String); args.Add(cg.CoreTypes.String); } // Target() var functype = cg.Factory.GetCallSiteDelegateType( cg.CoreTypes.PhpTypeInfo, RefKind.None, args.AsImmutable(), default(ImmutableArray<RefKind>), null, return_type); cg.EmitCall(ILOpCode.Callvirt, functype.DelegateInvokeMethod); if (_boundref.IsClassConstant) { throw new NotImplementedException(); } // _lazyLoadCallSite.Construct(functype, cctor => { // new GetFieldBinder(field_name, context, return, flags) // TODO: class constants cctor.Builder.EmitStringConstant(this.NameValueOpt); cctor.EmitLoadToken(cg.Routine.ContainingType, null); cctor.EmitLoadToken(return_type, null); cctor.Builder.EmitIntConstant((int)Access.AccessFlags); cctor.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Dynamic.GetFieldBinder_ctor); }); // return return_type; }
/// <summary> /// Emits name as string. Caches the result if holder is provided, or loads evaluated name if holder was initialized already. /// </summary> public static void EmitName(InstanceCacheHolder holderOrNull, CodeGenerator cg, BoundExpression name) { Contract.ThrowIfNull(cg); Contract.ThrowIfNull(name); if (holderOrNull != null) { holderOrNull.EmitName(cg, name); } else { cg.EmitConvert(name, cg.CoreTypes.String); } }
internal override void Generate(CodeGenerator cg) { // four cases: // 1. just single or none case label that can be replaced with single IF // 2. switch over integers, using native CIL switch // 3. switch over strings, using C# static Dictionary and CIL switch // 4. PHP style switch which is just a bunch of IFs if (this.CaseBlocks.Length == 0 || this.CaseBlocks[0].IsDefault) { Debug.Assert(this.CaseBlocks.Length <= 1); // no SWITCH or IF needed cg.EmitPop(this.SwitchValue.WithAccess(BoundAccess.None).Emit(cg)); // None Access, also using BoundExpression.Emit directly to avoid CodeGenerator type specialization which is not needed if (this.CaseBlocks.Length == 1) { cg.GenerateScope(this.CaseBlocks[0], NextBlock.Ordinal); } } else { // CIL Switch: bool allconsts = this.CaseBlocks.All(c => c.IsDefault || c.CaseValue.ConstantValue.HasValue); bool allconstints = allconsts && this.CaseBlocks.All(c => c.IsDefault || IsInt32(c.CaseValue.ConstantValue.Value)); //bool allconststrings = allconsts && this.CaseBlocks.All(c => c.IsDefault || IsString(c.CaseValue.ConstantValue.Value)); var default_block = this.DefaultBlock; // <switch_loc> = <SwitchValue>; TypeSymbol switch_type; LocalDefinition switch_loc; // Switch Header if (allconstints) { switch_type = cg.CoreTypes.Int32; cg.EmitSequencePoint(this.SwitchValue.PhpSyntax); cg.EmitConvert(this.SwitchValue, switch_type); switch_loc = cg.GetTemporaryLocal(switch_type); cg.Builder.EmitLocalStore(switch_loc); // switch (labels) cg.Builder.EmitIntegerSwitchJumpTable(GetSwitchCaseLabels(CaseBlocks), default_block ?? NextBlock, switch_loc, switch_type.PrimitiveTypeCode); } //else if (allconststrings) //{ //} else { // legacy jump table // IF (case_i) GOTO label_i; cg.EmitSequencePoint(this.SwitchValue.PhpSyntax); switch_type = cg.Emit(this.SwitchValue); switch_loc = cg.GetTemporaryLocal(switch_type); cg.Builder.EmitLocalStore(switch_loc); // for (int i = 0; i < this.CaseBlocks.Length; i++) { var this_block = this.CaseBlocks[i]; if (this_block.CaseValue != null) { // <CaseValue>: cg.EmitSequencePoint(this_block.CaseValue.PhpSyntax); // if (<switch_loc> == c.CaseValue) goto this_block; cg.Builder.EmitLocalLoad(switch_loc); BoundBinaryEx.EmitEquality(cg, switch_type, this_block.CaseValue); cg.Builder.EmitBranch(ILOpCode.Brtrue, this_block); } } // default: cg.Builder.EmitBranch(ILOpCode.Br, default_block ?? NextBlock); } // FREE <switch_loc> cg.ReturnTemporaryLocal(switch_loc); // Switch Body this.CaseBlocks.ForEach((i, this_block) => { var next_case = (i + 1 < this.CaseBlocks.Length) ? this.CaseBlocks[i + 1] : null; // { cg.GenerateScope(this_block, (next_case ?? NextBlock).Ordinal); // } }); } // cg.Scope.ContinueWith(NextBlock); }
internal override TypeSymbol Emit(CodeGenerator cg) { TypeSymbol result; var isvoid = this.Access.IsNone; Debug.Assert(_arguments.Length == 1); Debug.Assert(_arguments[0].Value.Access.IsRead); Debug.Assert(Access.IsRead || Access.IsNone); var method = this.Target; if (method != null) // => IsResolved { // emit condition for include_once/require_once if (IsOnceSemantic) { var tscript = method.ContainingType; result = isvoid ? cg.CoreTypes.Void.Symbol : cg.DeclaringCompilation.GetTypeFromTypeRef(cg.Routine.TypeRefContext, this.TypeRefMask); // Template: (<ctx>.CheckIncludeOnce<TScript>()) ? <Main>() : TRUE // Template<isvoid>: if (<ctx>.CheckIncludeOnce<TScript>()) <Main>() var falseLabel = new object(); var endLabel = new object(); cg.EmitLoadContext(); cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.Context.CheckIncludeOnce_TScript.Symbol.Construct(tscript)); cg.Builder.EmitBranch(ILOpCode.Brfalse, falseLabel); // ? (PhpValue)<Main>(...) cg.EmitCallMain(method); if (isvoid) { cg.EmitPop(method.ReturnType); } else { cg.EmitConvert(method.ReturnType, 0, result); } cg.Builder.EmitBranch(ILOpCode.Br, endLabel); if (!isvoid) { cg.Builder.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder } // : PhpValue.Create(true) cg.Builder.MarkLabel(falseLabel); if (!isvoid) { cg.Builder.EmitBoolConstant(true); cg.EmitConvert(cg.CoreTypes.Boolean, 0, result); } // cg.Builder.MarkLabel(endLabel); } else { // <Main> result = cg.EmitCallMain(method); } } else { Debug.Assert(cg.LocalsPlaceOpt != null); // Template: <ctx>.Include(dir, path, locals, @this, bool once = false, bool throwOnError = false) cg.EmitLoadContext(); cg.Builder.EmitStringConstant(cg.Routine.ContainingFile.DirectoryRelativePath); cg.EmitConvert(_arguments[0].Value, cg.CoreTypes.String); cg.LocalsPlaceOpt.EmitLoad(cg.Builder); // scope of local variables, corresponds to $GLOBALS in global scope. cg.EmitThisOrNull(); // $this cg.Builder.EmitBoolConstant(IsOnceSemantic); cg.Builder.EmitBoolConstant(IsRequireSemantic); return cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.Context.Include_string_string_PhpArray_object_bool_bool); } // return result; }
internal override TypeSymbol Emit(CodeGenerator cg) { var target_place = this.Target.BindPlace(cg); Debug.Assert(target_place != null); Debug.Assert(target_place.TypeOpt == null || target_place.TypeOpt.SpecialType != SpecialType.System_Void); // T tmp; // in case access is Read var t_value = target_place.TypeOpt; if (t_value == cg.CoreTypes.PhpAlias || t_value == cg.CoreTypes.PhpValue) t_value = null; // no inplace conversion LocalDefinition tmp = null; // <target> = <value> target_place.EmitStorePrepare(cg); // TODO: load value & dereference eventually if (t_value != null) cg.EmitConvert(this.Value, t_value); // TODO: do not convert here yet else t_value = cg.Emit(this.Value); switch (this.Access.Flags) { case AccessMask.Read: tmp = cg.GetTemporaryLocal(t_value, false); cg.Builder.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(tmp); break; case AccessMask.None: break; default: throw ExceptionUtilities.UnexpectedValue(this.Access); } target_place.EmitStore(cg, t_value); // switch (this.Access.Flags) { case AccessMask.None: t_value = cg.CoreTypes.Void; break; case AccessMask.Read: cg.Builder.EmitLocalLoad(tmp); break; default: throw ExceptionUtilities.UnexpectedValue(this.Access); } if (tmp != null) { cg.ReturnTemporaryLocal(tmp); } // return t_value; }
internal static TypeSymbol EmitPow(CodeGenerator cg, TypeSymbol xtype, FlowAnalysis.TypeRefMask xtype_hint, BoundExpression right) { var il = cg.Builder; TypeSymbol ytype; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> long switch (xtype.SpecialType) { case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // int|bool -> long if (ytype.SpecialType == SpecialType.System_Int64) { // i8 ** i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_long); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 ** r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_double); } else if (ytype == cg.CoreTypes.PhpNumber) { // i8 ** number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_number); } // y -> PhpValue cg.EmitConvert(ytype, right.TypeRefMask, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // i8 ** value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_value); case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // int|bool|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 ** r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_double_double); } // y -> PhpValue cg.EmitConvert(ytype, right.TypeRefMask, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // r8 ** value : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_double_value); default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // int|bool -> long if (ytype == cg.CoreTypes.Double) { // number ** r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_double); } if (ytype.SpecialType == SpecialType.System_Int64) { // y -> number ytype = cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Create_Long); } if (ytype == cg.CoreTypes.PhpNumber) { // number ** number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_number); } // y -> PhpValue ytype = cg.EmitConvertToPhpValue(ytype, right.TypeRefMask); // number ** value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_value); } // x -> PhpValue xtype = cg.EmitConvertToPhpValue(xtype, xtype_hint); cg.EmitConvert(right, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // value ** value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_value_value); } }
internal override TypeSymbol Emit(CodeGenerator cg) { var result_type = cg.DeclaringCompilation.GetTypeFromTypeRef(cg.Routine, this.TypeRefMask); if (this.IfTrue != null) { object trueLbl = new object(); object endLbl = new object(); // Cond ? True : False cg.EmitConvert(this.Condition, cg.CoreTypes.Boolean); // i4 cg.Builder.EmitBranch(ILOpCode.Brtrue, trueLbl); // false: cg.EmitConvert(this.IfFalse, result_type); cg.Builder.EmitBranch(ILOpCode.Br, endLbl); cg.Builder.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder // trueLbl: cg.Builder.MarkLabel(trueLbl); cg.EmitConvert(this.IfTrue, result_type); // endLbl: cg.Builder.MarkLabel(endLbl); } else { object trueLbl = new object(); object endLbl = new object(); // Cond ?: False // <stack> = <cond_var> = Cond var cond_type = cg.Emit(this.Condition); var cond_var = cg.GetTemporaryLocal(cond_type); cg.Builder.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(cond_var); cg.EmitConvertToBool(cond_type, this.Condition.TypeRefMask); cg.Builder.EmitBranch(ILOpCode.Brtrue, trueLbl); // false: cg.EmitConvert(this.IfFalse, result_type); cg.Builder.EmitBranch(ILOpCode.Br, endLbl); cg.Builder.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder // trueLbl: cg.Builder.MarkLabel(trueLbl); cg.Builder.EmitLocalLoad(cond_var); cg.EmitConvert(cond_type, this.Condition.TypeRefMask, result_type); // endLbl: cg.Builder.MarkLabel(endLbl); // cg.ReturnTemporaryLocal(cond_var); } // if (Access.IsNone) { cg.EmitPop(result_type); result_type = cg.CoreTypes.Void; } // return result_type; }
internal override TypeSymbol Emit(CodeGenerator cg) { Debug.Assert(Access.IsRead || Access.IsNone); TypeSymbol returned_type; switch (this.Operation) { case Operations.AtSign: // special arrangement // Template: // context.DisableErrorReporting(); // s; // context.EnableErrorReporting(); returned_type = cg.EmitWithDisabledErrorReporting(Operand); break; case Operations.BitNegation: //Template: "~x" Operators.BitNot(x) returned_type = EmitBitNot(cg); break; case Operations.Clone: // Template: clone x Debug.WriteLine("TODO: clone(object)"); returned_type = cg.Emit(Operand); // TODO: clone break; case Operations.LogicNegation: //Template: !(bool)(x); cg.EmitConvertToBool(this.Operand, true); returned_type = cg.CoreTypes.Boolean; break; case Operations.Minus: //Template: "-x" returned_type = EmitMinus(cg); break; case Operations.Plus: //Template: "+x" returned_type = EmitPlus(cg); break; case Operations.ObjectCast: //Template: "(object)x" cg.EmitConvert(this.Operand, cg.CoreTypes.Object); returned_type = cg.CoreTypes.Object; break; case Operations.Print: cg.EmitEcho(this.Operand); if (Access.IsRead) { // Always returns 1 cg.Builder.EmitLongConstant(1); returned_type = cg.CoreTypes.Long; } else { // nobody reads the result anyway returned_type = cg.CoreTypes.Void; } break; case Operations.BoolCast: //Template: "(bool)x" cg.EmitConvert(this.Operand, cg.CoreTypes.Boolean); returned_type = cg.CoreTypes.Boolean; break; case Operations.Int8Cast: case Operations.Int16Cast: case Operations.Int32Cast: case Operations.UInt8Cast: case Operations.UInt16Cast: case Operations.UInt64Cast: case Operations.UInt32Cast: case Operations.Int64Cast: cg.EmitConvert(this.Operand, cg.CoreTypes.Long); returned_type = cg.CoreTypes.Long; break; case Operations.DecimalCast: case Operations.DoubleCast: case Operations.FloatCast: cg.EmitConvert(this.Operand, cg.CoreTypes.Double); returned_type = cg.CoreTypes.Double; break; case Operations.UnicodeCast: // TODO case Operations.StringCast: // (string)x cg.EmitConvert(this.Operand, cg.CoreTypes.String); // TODO: to String or PhpString ? to not corrupt single-byte string return cg.CoreTypes.String; case Operations.BinaryCast: //if ((returned_typecode = node.Expr.Emit(codeGenerator)) != PhpTypeCode.PhpBytes) //{ // codeGenerator.EmitBoxing(returned_typecode); // //codeGenerator.EmitLoadClassContext(); // il.Emit(OpCodes.Call, Methods.Convert.ObjectToPhpBytes); // returned_typecode = PhpTypeCode.PhpBytes; //} //break; throw new NotImplementedException(); case Operations.ArrayCast: //Template: "(array)x" cg.EmitConvert(this.Operand, cg.CoreTypes.PhpArray); // TODO: EmitArrayCast() returned_type = cg.CoreTypes.PhpArray; break; case Operations.UnsetCast: // Template: "(unset)x" null cg.EmitPop(cg.Emit(this.Operand)); if (this.Access.IsRead) { cg.Builder.EmitNullConstant(); returned_type = cg.CoreTypes.Object; } else { returned_type = cg.CoreTypes.Void; } break; default: throw ExceptionUtilities.Unreachable; } switch (Access.Flags) { case AccessMask.Read: Debug.Assert(returned_type.SpecialType != SpecialType.System_Void); // do nothing break; case AccessMask.None: // pop operation's result value from stack cg.EmitPop(returned_type); returned_type = cg.CoreTypes.Void; break; default: throw ExceptionUtilities.UnexpectedValue(Access); } return returned_type; }
internal override TypeSymbol Emit(CodeGenerator cg) { cg.EmitConvert(this.Variable, cg.CoreTypes.PhpValue); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.IsEmpty_PhpValue) .Expect(SpecialType.System_Boolean); }
void IBoundReference.EmitStore(CodeGenerator cg, TypeSymbol valueType) { var rtype = cg.CoreTypes.IPhpArray; cg.EmitConvert(valueType, 0, rtype); var tmp = cg.GetTemporaryLocal(rtype); cg.Builder.EmitLocalStore(tmp); // NOTE: since PHP7, variables are assigned from left to right var vars = this.Variables; for (int i = 0; i < vars.Length; i++) { var target = vars[i]; if (target == null) continue; var boundtarget = target.BindPlace(cg); boundtarget.EmitStorePrepare(cg); // LOAD IPhpArray.GetItemValue(IntStringKey{i}) cg.Builder.EmitLocalLoad(tmp); cg.EmitIntStringKey(i); var itemtype = cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.IPhpArray.GetItemValue_IntStringKey); // STORE vars[i] boundtarget.EmitStore(cg, itemtype); } // cg.ReturnTemporaryLocal(tmp); }
internal static TypeSymbol EmitBitOr(CodeGenerator cg, TypeSymbol xtype, BoundExpression right) { switch (xtype.SpecialType) { case SpecialType.System_Void: case SpecialType.System_Int32: case SpecialType.System_Boolean: case SpecialType.System_Double: cg.EmitConvert(xtype, 0, cg.CoreTypes.Long); goto case SpecialType.System_Int64; case SpecialType.System_Int64: cg.EmitConvert(right, cg.CoreTypes.Long); cg.Builder.EmitOpCode(ILOpCode.Or); return cg.CoreTypes.Long; case SpecialType.System_String: throw new NotImplementedException(); // string | string or string | long default: if (right.ResultType != null && right.ResultType.SpecialType != SpecialType.System_String) { // value | !string -> long | long -> long cg.EmitConvert(xtype, 0, cg.CoreTypes.Long); goto case SpecialType.System_Int64; } cg.EmitConvert(xtype, 0, cg.CoreTypes.PhpValue); cg.EmitConvert(right, cg.CoreTypes.PhpValue); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.BitwiseOr_PhpValue_PhpValue) .Expect(cg.CoreTypes.PhpValue); } }
internal virtual TypeSymbol EmitCallsiteCall(CodeGenerator cg) { // callsite var nameOpt = this.CallsiteName; var callsite = cg.Factory.StartCallSite("call_" + nameOpt); var callsiteargs = new List<TypeSymbol>(_arguments.Length); var return_type = this.Access.IsRead ? this.Access.IsReadRef ? cg.CoreTypes.PhpAlias.Symbol : (this.Access.TargetType ?? cg.CoreTypes.PhpValue.Symbol) : cg.CoreTypes.Void.Symbol; // callsite var fldPlace = callsite.Place; // LOAD callsite.Target callsite.EmitLoadTarget(cg.Builder); // LOAD callsite arguments // (callsite, [target], ctx, [name], ...) fldPlace.EmitLoad(cg.Builder); if (Instance != null) { callsiteargs.Add(cg.Emit(Instance)); // instance } else if (TypeNameExpr != null) { cg.EmitConvert(TypeNameExpr, cg.CoreTypes.String); callsiteargs.Add(cg.CoreTypes.String); // type } callsiteargs.Add(cg.EmitLoadContext()); // ctx if (RoutineNameExpr != null) { callsiteargs.Add(cg.Emit(RoutineNameExpr)); // name } foreach (var a in _arguments) { callsiteargs.Add(cg.Emit(a.Value)); } // Target() var functype = cg.Factory.GetCallSiteDelegateType( null, RefKind.None, callsiteargs.AsImmutable(), default(ImmutableArray<RefKind>), null, return_type); cg.EmitCall(ILOpCode.Callvirt, functype.DelegateInvokeMethod); // Create CallSite ... callsite.Construct(functype, cctor_cg => BuildCallsiteCreate(cctor_cg, return_type)); // return return_type; }
/// <summary> /// Emits binary operation XOR. /// </summary> TypeSymbol EmitBinaryXor(CodeGenerator cg) { // LOAD <(bool) leftSon> == <(bool) rightSon>; cg.EmitConvert(Left, cg.CoreTypes.Boolean); cg.EmitConvert(Right, cg.CoreTypes.Boolean); cg.EmitOpCode(ILOpCode.Ceq); cg.EmitOpCode(ILOpCode.Ldc_i4_0); cg.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; }
internal override TypeSymbol EmitCallsiteCall(CodeGenerator cg) { if (_name.IsDirect) { return base.EmitCallsiteCall(cg); } else { Debug.Assert(_name.NameExpression != null); // faster to emit PhpCallback.Invoke // NameExpression.AsCallback().Invoke(Context, PhpValue[]) cg.EmitConvert(_name.NameExpression, cg.CoreTypes.IPhpCallable); // (IPhpCallable)Name cg.EmitLoadContext(); // Context cg.Emit_NewArray(cg.CoreTypes.PhpValue, _arguments.Select(a => a.Value).ToArray()); // PhpValue[] return cg.EmitCall(ILOpCode.Callvirt, cg.CoreTypes.IPhpCallable.Symbol.LookupMember<MethodSymbol>("Invoke")); } }
TypeSymbol EmitBitNot(CodeGenerator cg) { var il = cg.Builder; var t = cg.Emit(this.Operand); switch (t.SpecialType) { case SpecialType.System_Double: case SpecialType.System_Int32: // r8|i4 -> i8 il.EmitOpCode(ILOpCode.Conv_i8); goto case SpecialType.System_Int64; case SpecialType.System_Int64: il.EmitOpCode(ILOpCode.Not); // ~i64 : i64 return cg.CoreTypes.Long; case SpecialType.System_Boolean: throw new NotImplementedException(); // Err default: if (t == cg.CoreTypes.PhpArray) { // ERR } // ~ PhpValue cg.EmitConvert(t, Operand.TypeRefMask, cg.CoreTypes.PhpValue); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.BitwiseNot_PhpValue); } }
/// <summary> /// Emits name as string, uses cached variable. /// </summary> void EmitName(CodeGenerator cg, BoundExpression name) { Contract.ThrowIfNull(cg); Contract.ThrowIfNull(name); if (_name_loc != null) { cg.Builder.EmitLocalLoad(_name_loc); } else { _cg = cg; // return (<loc> = <name>) _name_loc = cg.GetTemporaryLocal(cg.CoreTypes.String); cg.EmitConvert(name, cg.CoreTypes.String); cg.Builder.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(_name_loc); } }