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 Generate(CodeGenerator cg) { if (cg.IsDebug && this.PhpSyntax != null) { cg.EmitSequencePoint(this.PhpSyntax); cg.Builder.EmitOpCode(ILOpCode.Nop); } cg.Scope.ContinueWith(NextBlock); }
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 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 void Generate(CodeGenerator cg) { Debug.Assert(this.Enumeree != null); // get the enumerator, // bind actual MoveNext() and CurrentValue and CurrentKey // Template: using( // a) enumerator = enumeree.GetEnumerator() // b) enumerator = Operators.GetEnumerator(enumeree) // ) ... cg.EmitSequencePoint(this.Enumeree.PhpSyntax); var enumereeType = cg.Emit(this.Enumeree); Debug.Assert(enumereeType.SpecialType != SpecialType.System_Void); var getEnumeratorMethod = enumereeType.LookupMember<MethodSymbol>(WellKnownMemberNames.GetEnumeratorMethodName); TypeSymbol enumeratorType; if (enumereeType.IsOfType(cg.CoreTypes.PhpArray)) { cg.Builder.EmitBoolConstant(_aliasedValues); // PhpArray.GetForeachtEnumerator(bool) enumeratorType = cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpArray.GetForeachEnumerator_Boolean); // TODO: IPhpArray } // TODO: IPhpEnumerable // TODO: IPhpArray // TODO: Iterator else if (getEnumeratorMethod != null && getEnumeratorMethod.ParameterCount == 0 && enumereeType.IsReferenceType) { // enumeree.GetEnumerator() enumeratorType = cg.EmitCall(getEnumeratorMethod.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call, getEnumeratorMethod); } else { cg.EmitConvertToPhpValue(enumereeType, 0); cg.Builder.EmitBoolConstant(_aliasedValues); cg.EmitCallerRuntimeTypeHandle(); // Operators.GetForeachEnumerator(PhpValue, bool, RuntimeTypeHandle) enumeratorType = cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.GetForeachEnumerator_PhpValue_Bool_RuntimeTypeHandle); } // _current = enumeratorType.LookupMember<PropertySymbol>(WellKnownMemberNames.CurrentPropertyName); // TODO: Err if no Current _currentValue = enumeratorType.LookupMember<PropertySymbol>(_aliasedValues ? "CurrentValueAliased" : "CurrentValue"); _currentKey = enumeratorType.LookupMember<PropertySymbol>("CurrentKey"); _disposeMethod = enumeratorType.LookupMember<MethodSymbol>("Dispose", m => m.ParameterCount == 0 && !m.IsStatic); // _enumeratorLoc = cg.GetTemporaryLocal(enumeratorType); cg.Builder.EmitLocalStore(_enumeratorLoc); // bind methods _moveNextMethod = enumeratorType.LookupMember<MethodSymbol>(WellKnownMemberNames.MoveNextMethodName); // TODO: Err if there is no MoveNext() Debug.Assert(_moveNextMethod.ReturnType.SpecialType == SpecialType.System_Boolean); Debug.Assert(_moveNextMethod.IsStatic == false); if (_disposeMethod != null) { /* Template: try { body } finally { enumerator.Dispose } */ // try { cg.Builder.AssertStackEmpty(); cg.Builder.OpenLocalScope(ScopeType.TryCatchFinally); cg.Builder.OpenLocalScope(ScopeType.Try); // EmitBody(cg); // } cg.Builder.CloseLocalScope(); // /Try // finally { cg.Builder.OpenLocalScope(ScopeType.Finally); // enumerator.Dispose() & cleanup EmitDisposeAndClean(cg); // } cg.Builder.CloseLocalScope(); // /Finally cg.Builder.CloseLocalScope(); // /TryCatchFinally } else { EmitBody(cg); EmitDisposeAndClean(cg); } }
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 Emit(CodeGenerator cg) { cg.EmitSequencePoint(this.PhpSyntax); cg.EmitPop(this.Expression.Emit(cg)); }
internal override void Emit(CodeGenerator cg) { cg.EmitSequencePoint(this.PhpSyntax); this.VarReferences.ForEach(cg.EmitUnset); }
internal override void Emit(CodeGenerator cg) { cg.EmitSequencePoint(this.PhpSyntax); foreach (var v in _variables) { var getmethod = cg.CoreMethods.Context.GetStatic_T.Symbol.Construct(v._holder); var place = v._holderPlace; // Template: x = ctx.GetStatic<holder_x>() place.EmitStorePrepare(cg.Builder); cg.EmitLoadContext(); cg.EmitCall(ILOpCode.Callvirt, getmethod); place.EmitStore(cg.Builder); // holder initialization routine EmitInit(cg.Module, cg.Diagnostics, cg.DeclaringCompilation, v._holder, (BoundExpression)v.InitialValue); } }
internal override void Emit(CodeGenerator cg) { cg.EmitSequencePoint(this.TypeDecl.HeadingSpan); // <ctx>.DeclareType<T>() cg.EmitDeclareType(this.Type); }
internal override void Emit(CodeGenerator cg) { cg.EmitSequencePoint(this.FunctionDecl.HeadingSpan); // <ctx>.DeclareFunction ... cg.EmitDeclareFunction(this.Function); }
internal override void Emit(CodeGenerator cg) { // first brace sequence point var body = cg.Routine.Syntax.BodySpanOrInvalid(); if (body.IsValid && cg.IsDebug) { cg.EmitSequencePoint(new Span(body.Start, 1)); cg.EmitOpCode(ILOpCode.Nop); } else { cg.Builder.DefineInitialHiddenSequencePoint(); } // if (cg.IsDebug) { if (cg.Routine.IsStatic) { // Debug.Assert(<context> != null); cg.EmitDebugAssertNotNull(cg.ContextPlaceOpt, "Context cannot be null."); } // TODO: emit parameters checks } // var locals = cg.Routine.LocalsTable; // in case of script, declare the script, functions and types if (cg.Routine is Symbols.SourceGlobalMethodSymbol) { // <ctx>.OnInclude<TScript>() cg.EmitLoadContext(); cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.Context.OnInclude_TScript.Symbol.Construct(cg.Routine.ContainingType)); // <ctx>.DeclareFunction() cg.Routine.ContainingFile.Functions .Where(f => !f.IsConditional) .ForEach(cg.EmitDeclareFunction); // <ctx>.DeclareType() cg.DeclaringCompilation.SourceSymbolTables.GetTypes() .OfType<Symbols.SourceTypeSymbol>() .Where(t => !t.Syntax.IsConditional && t.ContainingFile == cg.Routine.ContainingFile) // non conditional declaration within this file .ForEach(cg.EmitDeclareType); } else { if (cg.HasUnoptimizedLocals) { // <locals> = new PhpArray(HINTCOUNT) cg.LocalsPlaceOpt.EmitStorePrepare(cg.Builder); cg.Builder.EmitIntConstant(locals.Count); // HINTCOUNT cg.EmitCall(ILOpCode.Newobj, cg.CoreMethods.Ctors.PhpArray_int); cg.LocalsPlaceOpt.EmitStore(cg.Builder); } } // variables/parameters initialization foreach (var loc in locals.Variables) { loc.EmitInit(cg); } // base.Emit(cg); }