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); }
internal override void Emit(CodeGenerator cg) { cg.EmitSequencePoint(this.PhpSyntax); // var t = cg.Emit(Thrown); if (t.IsReferenceType) { if (!t.IsEqualToOrDerivedFrom(cg.CoreTypes.Exception)) { throw new NotImplementedException(); // Wrap to System.Exception } } else { //if (t == cg.CoreTypes.PhpValue) //{ //} throw new NotImplementedException(); // Wrap to System.Exception } // throw <stack>; cg.Builder.EmitThrow(false); }
internal override void EmitInit(CodeGenerator cg) { if (cg.HasUnoptimizedLocals) { return; } // declare variable in global scope var il = cg.Builder; var def = il.LocalSlotManager.DeclareLocal( (Cci.ITypeReference)_symbol.Type, _symbol as ILocalSymbolInternal, this.Name, SynthesizedLocalKind.UserDefined, LocalDebugId.None, 0, LocalSlotConstraints.None, false, default(ImmutableArray<TypedConstant>), false); _place = new LocalPlace(def); il.AddLocalToScope(def); // if (_symbol is SynthesizedLocalSymbol) return; // Initialize local variable with void. // This is mandatory since even assignments reads the target value to assign properly to PhpAlias. // TODO: Once analysis tells us, the target cannot be alias, this step won't be necessary. // TODO: only if the local will be used uninitialized cg.EmitInitializePlace(_place); }
public void Construct(NamedTypeSymbol functype, Action<CodeGenerator> binder_builder) { var callsitetype = _factory.CallSite_T.Construct(functype); // TODO: check if it wasn't constructed already _target.SetContainingType((SubstitutedNamedTypeSymbol)callsitetype); _fld.SetFieldType(callsitetype); _callsite_create = (MethodSymbol)_factory.CallSite_T_Create.SymbolAsMember(callsitetype); // create callsite // static .cctor { var cctor = _factory.CctorBuilder; // fld = CallSite<T>.Create( <BINDER> ) var fldPlace = this.Place; fldPlace.EmitStorePrepare(cctor); var cctor_cg = new CodeGenerator(cctor, _factory._cg.Module, _factory._cg.Diagnostics, _factory._cg.DeclaringCompilation.Options.OptimizationLevel, false, _factory._container, null, null); binder_builder(cctor_cg); cctor.EmitCall(_factory._cg.Module, _factory._cg.Diagnostics, ILOpCode.Call, this.CallSite_Create); fldPlace.EmitStore(cctor); // } }
void EmitInit(Emit.PEModuleBuilder module) { // void Init(Context) var tt = DeclaringCompilation.CoreTypes; var diagnostic = DiagnosticBag.GetInstance(); // override IStaticInit.Init(Context) { .. } var initMethod = new SynthesizedMethodSymbol(this, "Init", false, true, tt.Void, Accessibility.Public); initMethod.SetParameters(new SynthesizedParameterSymbol(initMethod, tt.Context, 0, RefKind.None, "ctx")); var body = MethodGenerator.GenerateMethodBody(module, initMethod, (il) => { var cg = new CodeGenerator(il, module, diagnostic, OptimizationLevel.Release, false, this, new ArgPlace(tt.Context, 1), new ArgPlace(this, 0)); foreach (var fld in this.Fields) { if (fld.RequiresContext) { fld.EmitInit(cg); } } // il.EmitRet(true); }, null, diagnostic, false); module.SetMethodBody(initMethod, body); module.SynthesizedManager.AddMethod(this, initMethod); }
internal override void Generate(CodeGenerator cg) { if (cg.IsDebug && this.PhpSyntax != null) { cg.EmitSequencePoint(this.PhpSyntax); cg.Builder.EmitOpCode(ILOpCode.Nop); } cg.Scope.ContinueWith(NextBlock); }
internal virtual void Emit(CodeGenerator cg) { // emit contained statements if (_statements.Count != 0) { _statements.ForEach(cg.Generate); } // cg.Generate(this.NextEdge); }
internal static MethodBody GenerateMethodBody( PEModuleBuilder moduleBuilder, SourceRoutineSymbol routine, int methodOrdinal, //ImmutableArray<LambdaDebugInfo> lambdaDebugInfo, //ImmutableArray<ClosureDebugInfo> closureDebugInfo, //StateMachineTypeSymbol stateMachineTypeOpt, VariableSlotAllocator variableSlotAllocatorOpt, DiagnosticBag diagnostics, //ImportChain importChainOpt, bool emittingPdb) { return GenerateMethodBody(moduleBuilder, routine, (builder) => { DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance(); var optimization = moduleBuilder.Compilation.Options.OptimizationLevel; var codeGen = new CodeGenerator(routine, builder, moduleBuilder, diagnosticsForThisMethod, optimization, emittingPdb); //if (diagnosticsForThisMethod.HasAnyErrors()) //{ // // we are done here. Since there were errors we should not emit anything. // return null; //} // We need to save additional debugging information for MoveNext of an async state machine. //var stateMachineMethod = method as SynthesizedStateMachineMethod; //bool isStateMachineMoveNextMethod = stateMachineMethod != null && method.Name == WellKnownMemberNames.MoveNextMethodName; //if (isStateMachineMoveNextMethod && stateMachineMethod.StateMachineType.KickoffMethod.IsAsync) //{ // int asyncCatchHandlerOffset; // ImmutableArray<int> asyncYieldPoints; // ImmutableArray<int> asyncResumePoints; // codeGen.Generate(out asyncCatchHandlerOffset, out asyncYieldPoints, out asyncResumePoints); // var kickoffMethod = stateMachineMethod.StateMachineType.KickoffMethod; // // The exception handler IL offset is used by the debugger to treat exceptions caught by the marked catch block as "user unhandled". // // This is important for async void because async void exceptions generally result in the process being terminated, // // but without anything useful on the call stack. Async Task methods on the other hand return exceptions as the result of the Task. // // So it is undesirable to consider these exceptions "user unhandled" since there may well be user code that is awaiting the task. // // This is a heuristic since it's possible that there is no user code awaiting the task. // asyncDebugInfo = new Cci.AsyncMethodBodyDebugInfo(kickoffMethod, kickoffMethod.ReturnsVoid ? asyncCatchHandlerOffset : -1, asyncYieldPoints, asyncResumePoints); //} //else { codeGen.Generate(); } }, variableSlotAllocatorOpt, diagnostics, emittingPdb); }
/// <summary> /// Emits load of statics holder. /// </summary> internal TypeSymbol EmitLoadStatics(CodeGenerator cg) { var statics = TryGetStatics(); if (statics != null && statics.GetMembers().OfType<IFieldSymbol>().Any()) { // Template: <ctx>.GetStatics<_statics>() cg.EmitLoadContext(); return cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.Context.GetStatic_T.Symbol.Construct(statics)) .Expect(statics); } return null; }
void EmitFieldsCctor(Emit.PEModuleBuilder module) { var sflds = GetMembers().OfType<SourceFieldSymbol>().Where(f => f.IsStatic && !f.RequiresHolder).ToList(); if (sflds.Count != 0) { // emit initialization of app static fields // note, their initializers do not have Context available, since they are not bound to a Context var cctor = module.GetStaticCtorBuilder(this); var cg = new CodeGenerator(cctor, module, DiagnosticBag.GetInstance(), OptimizationLevel.Release, false, this, null, null); foreach (var f in sflds) { f.EmitInit(cg); } } }
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 load of <c>PhpTypeInfo</c>. /// </summary> /// <param name="cg">Code generator instance.</param> /// <param name="throwOnError">Emits PHP error in case type is not declared.</param> /// <remarks>Emits <c>NULL</c> in case type is not declared.</remarks> internal void EmitLoadTypeInfo(CodeGenerator cg, bool throwOnError = false) { Debug.Assert(cg != null); Debug.Assert(throwOnError == false, "Not Implemented!"); // TODO: if (throwOnError) { if (DUP == null) PhpException.TypeNotDeclared(<typename>) if (this.ResolvedType != null) { // CALL GetPhpTypeInfo<T>() cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Dynamic.GetPhpTypeInfo_T.Symbol.Construct(this.ResolvedType)); } else { // CALL <ctx>.GetDeclaredType(<typename>) cg.EmitLoadContext(); this.EmitClassName(cg); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Context.GetDeclaredType_string); } }
internal void EmitCtors(Emit.PEModuleBuilder module) { bool requiresInit = false; // .ctor() var tt = DeclaringCompilation.CoreTypes; var diagnostic = DiagnosticBag.GetInstance(); var ctor = new SynthesizedCtorSymbol(this); var body = MethodGenerator.GenerateMethodBody(module, ctor, (il) => { var cg = new CodeGenerator(il, module, diagnostic, OptimizationLevel.Release, false, this, null, new ArgPlace(this, 0)); foreach (var fld in this.Fields) { if (fld.RequiresContext) { requiresInit = true; } else { fld.EmitInit(cg); } } // il.EmitRet(true); }, null, diagnostic, false); module.SetMethodBody(ctor, body); module.SynthesizedManager.AddMethod(this, ctor); // if (requiresInit) { EmitInit(module); } }
/// <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); }
/// <summary> /// Emits check for values equality. /// Lefts <c>bool</c> on top of evaluation stack. /// </summary> TypeSymbol EmitEquality(CodeGenerator cg) { // x == y return EmitEquality(cg, Left, Right); }
/// <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; }
/// <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, 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 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); }
/// <summary> /// Emits subtraction operator. /// </summary> internal static TypeSymbol EmitSub(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_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // i8 - i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 - r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_double) .Expect(cg.CoreTypes.Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // i8 - number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_number) .Expect(cg.CoreTypes.PhpNumber); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // i8 - value : value return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_value) .Expect(cg.CoreTypes.PhpNumber); } case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 - r8 : r8 il.EmitOpCode(ILOpCode.Sub); return cg.CoreTypes.Double; } throw new NotImplementedException($"Sub(double, {ytype.Name})"); default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // number - i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_number_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // number - r8 : double return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_number_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // number - number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_number_number) .Expect(cg.CoreTypes.PhpNumber); } throw new NotImplementedException($"Sub(PhpNumber, {ytype.Name})"); } else if (xtype == cg.CoreTypes.PhpValue) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // value - i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // value - r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // value - number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // value - value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_value) .Expect(cg.CoreTypes.PhpNumber); } throw new NotImplementedException($"Sub(PhpValue, {ytype.Name})"); } throw new NotImplementedException($"Sub({xtype.Name},...)"); } }
internal override TypeSymbol Emit(CodeGenerator cg) { Debug.Assert(this.Access.IsRead || this.Access.IsNone); // TypeSymbol returned_type; if (UsesOperatorMethod) { throw new NotImplementedException(); // call this.Operator(Left, Right) } switch (this.Operation) { #region Arithmetic Operations case Operations.Add: returned_type = (cg.IsLongOnly(this.TypeRefMask)) ? cg.CoreTypes.Long.Symbol : this.Access.TargetType; returned_type = EmitAdd(cg, Left, Right, returned_type); break; case Operations.Sub: //Template: "x - y" Operators.Subtract(x,y) [overloads] returned_type = EmitSub(cg, Left, Right, this.Access.TargetType); break; case Operations.Div: //Template: "x / y" returned_type = EmitDivision(cg); break; case Operations.Mul: //Template: "x * y" returned_type = EmitMultiply(cg); break; case Operations.Pow: //Template: "x ** y" returned_type = EmitPow(cg); break; case Operations.Mod: //Template: "x % y" Operators.Remainder(x,y) //codeGenerator.EmitBoxing(node.LeftExpr.Emit(codeGenerator)); //ro_typecode = node.RightExpr.Emit(codeGenerator); //switch (ro_typecode) //{ // case PhpTypeCode.Integer: // returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Int32); // break; // default: // codeGenerator.EmitBoxing(ro_typecode); // returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Object); // break; //} //break; throw new NotImplementedException(); case Operations.ShiftLeft: //// LOAD Operators.ShiftLeft(box left, box right); //codeGenerator.EmitBoxing(node.LeftExpr.Emit(codeGenerator)); //codeGenerator.EmitBoxing(node.RightExpr.Emit(codeGenerator)); //returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftLeft); //break; throw new NotImplementedException(); case Operations.ShiftRight: //// LOAD Operators.ShiftRight(box left, box right); //codeGenerator.EmitBoxing(node.LeftExpr.Emit(codeGenerator)); //codeGenerator.EmitBoxing(node.RightExpr.Emit(codeGenerator)); //returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftRight); //break; throw new NotImplementedException(); #endregion #region Boolean and Bitwise Operations case Operations.And: returned_type = EmitBinaryBooleanOperation(cg, true); break; case Operations.Or: returned_type = EmitBinaryBooleanOperation(cg, false); break; case Operations.Xor: returned_type = EmitBinaryXor(cg); break; case Operations.BitAnd: returned_type = EmitBitAnd(cg, Left, Right); break; case Operations.BitOr: returned_type = EmitBitOr(cg, Left, Right); break; case Operations.BitXor: //returned_typecode = EmitBitOperation(node, codeGenerator, Operators.BitOp.Xor); //break; throw new NotImplementedException(); #endregion #region Comparing Operations case Operations.Equal: returned_type = EmitEquality(cg); break; case Operations.NotEqual: EmitEquality(cg); cg.EmitLogicNegation(); returned_type = cg.CoreTypes.Boolean; break; case Operations.GreaterThan: returned_type = EmitLtGt(cg, false); break; case Operations.LessThan: returned_type = EmitLtGt(cg, true); break; case Operations.GreaterThanOrEqual: // template: !(LessThan) returned_type = EmitLtGt(cg, true); cg.EmitLogicNegation(); break; case Operations.LessThanOrEqual: // template: !(GreaterThan) returned_type = EmitLtGt(cg, false); cg.EmitLogicNegation(); break; case Operations.Identical: // Left === Right returned_type = EmitStrictEquality(cg); break; case Operations.NotIdentical: // ! (Left === Right) returned_type = EmitStrictEquality(cg); cg.EmitLogicNegation(); break; #endregion default: throw ExceptionUtilities.Unreachable; } // switch (Access.Flags) { case AccessMask.Read: // Result is read, do nothing. Debug.Assert(returned_type.SpecialType != SpecialType.System_Void); break; case AccessMask.None: // Result is not read, pop the result cg.EmitPop(returned_type); returned_type = cg.CoreTypes.Void; break; } // return returned_type; }
internal override TypeSymbol Emit(CodeGenerator cg) { var end_label = new object(); var vars = this.VarReferences; for (int i = 0; i < vars.Length; i++) { if (i > 0) { cg.Builder.EmitOpCode(ILOpCode.Pop); } var t = cg.Emit(vars[i]); // t.IsSet if (t == cg.CoreTypes.PhpValue) { // IsSet(value) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.IsSet_PhpValue); } else if (t.IsReferenceType) { // object != null cg.Builder.EmitNullConstant(); // .ldnull cg.Builder.EmitOpCode(ILOpCode.Cgt_un); // .cgt.un } else { // value type => true cg.EmitPop(t); cg.Builder.EmitBoolConstant(true); } if (i + 1 < vars.Length) { // if (result == false) goto end_label; cg.Builder.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitBranch(ILOpCode.Brfalse, end_label); } } // cg.Builder.MarkLabel(end_label); // return cg.CoreTypes.Boolean; }
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); }
internal static TypeSymbol EmitStrictEquality(CodeGenerator cg, BoundExpression left, BoundExpression right) => EmitStrictEquality(cg, cg.Emit(left), right);
/// <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); } } }
TypeSymbol EmitStrictEquality(CodeGenerator cg) => EmitStrictEquality(cg, Left, Right);
/// <summary> /// Emits subtraction operator. /// </summary> internal static TypeSymbol EmitSub(CodeGenerator cg, BoundExpression left, BoundExpression right, TypeSymbol resultTypeOpt = null) { return EmitSub(cg, cg.Emit(left), right, resultTypeOpt); }
internal static TypeSymbol EmitStrictEquality(CodeGenerator cg, TypeSymbol xtype, BoundExpression right) { TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Boolean: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Boolean) { // bool == bool cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if ( ytype.SpecialType == SpecialType.System_Double || ytype.SpecialType == SpecialType.System_Int32 || ytype.SpecialType == SpecialType.System_Int64 || ytype.SpecialType == SpecialType.System_String || ytype.IsOfType(cg.CoreTypes.IPhpArray) || ytype == cg.CoreTypes.PhpString || ytype == cg.CoreTypes.Object) { // bool == something else => false cg.EmitPop(ytype); cg.EmitPop(xtype); cg.Builder.EmitBoolConstant(false); return cg.CoreTypes.Boolean; } else { // bool == PhpValue cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_bool_PhpValue) .Expect(SpecialType.System_Boolean); } case SpecialType.System_Int32: cg.Builder.EmitOpCode(ILOpCode.Conv_i8); // i4 -> 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_Boolean || ytype.SpecialType == SpecialType.System_String || ytype.SpecialType == SpecialType.System_Double || ytype.IsOfType(cg.CoreTypes.IPhpArray) || ytype == cg.CoreTypes.Object || ytype == cg.CoreTypes.PhpString) { // i8 == something else => false cg.EmitPop(ytype); cg.EmitPop(xtype); cg.Builder.EmitBoolConstant(false); return cg.CoreTypes.Boolean; } else { // i8 == PhpValue cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_long_PhpValue) .Expect(SpecialType.System_Boolean); } case SpecialType.System_Double: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Double) { // r8 == r8 cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if ( ytype.SpecialType == SpecialType.System_Boolean || ytype.SpecialType == SpecialType.System_String || ytype.SpecialType == SpecialType.System_Int64 || ytype.SpecialType == SpecialType.System_Int32 || ytype.IsOfType(cg.CoreTypes.IPhpArray) || ytype == cg.CoreTypes.Object || ytype == cg.CoreTypes.PhpString) { // r8 == something else => false cg.EmitPop(ytype); cg.EmitPop(xtype); cg.Builder.EmitBoolConstant(false); return cg.CoreTypes.Boolean; } else { // r8 == PhpValue cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_double_PhpValue) .Expect(SpecialType.System_Boolean); } default: // TODO: PhpArray, Object === ... xtype = cg.EmitConvertToPhpValue(xtype, 0); ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Boolean) { // PhpValue == bool return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_PhpValue_bool) .Expect(SpecialType.System_Boolean); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // PhpValue == PhpValue return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_PhpValue_PhpValue) .Expect(SpecialType.System_Boolean); } } }
internal override TypeSymbol Emit(CodeGenerator cg) { Debug.Assert(!Access.IsWrite); if (this.Access.IsNone) { return cg.CoreTypes.Void; } if (this.ConstantValue.HasValue) { return cg.EmitLoadConstant(this.ConstantValue.Value, this.Access.TargetType); } if (_boundExpressionOpt != null) { _boundExpressionOpt.EmitLoadPrepare(cg); return _boundExpressionOpt.EmitLoad(cg); } var idxfield = cg.Module.SynthesizedManager .GetOrCreateSynthesizedField(cg.Module.ScriptType, cg.CoreTypes.Int32, $"c<{this.Name}>idx", Accessibility.Internal, true, false); // <ctx>.GetConstant(<name>, ref <Index of constant>) cg.EmitLoadContext(); cg.Builder.EmitStringConstant(this.Name); cg.EmitFieldAddress(idxfield); return cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.Context.GetConstant_string_int32) .Expect(cg.CoreTypes.PhpValue); }