context
/// <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; }
/// <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 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) { if (TargetMethod != null) { return EmitDirectCall(cg, ILOpCode.Newobj, TargetMethod); } else { if (_typeref.ResolvedType != null) { // context.Create<T>(params) var create_t = cg.CoreTypes.Context.Symbol.GetMembers("Create") .OfType<MethodSymbol>() .Where(s => s.Arity == 1 && s.ParameterCount == 1 && s.Parameters[0].IsParams) .Single() .Construct(_typeref.ResolvedType); cg.EmitLoadContext(); // Context cg.Emit_NewArray(cg.CoreTypes.PhpValue, _arguments.Select(a => a.Value).ToArray()); // PhpValue[] return cg.EmitCall(ILOpCode.Call, create_t); } else { // ctx.Create(classname, params) var create = cg.CoreTypes.Context.Symbol.GetMembers("Create") .OfType<MethodSymbol>() .Where(s => s.Arity == 0 && s.ParameterCount == 2 && s.Parameters[0].Type.PrimitiveTypeCode == Microsoft.Cci.PrimitiveTypeCode.String && s.Parameters[1].IsParams && ((ArrayTypeSymbol)s.Parameters[1].Type).ElementType == cg.CoreTypes.PhpValue) .Single(); cg.EmitLoadContext(); // Context _typeref.EmitClassName(cg); // String cg.Emit_NewArray(cg.CoreTypes.PhpValue, _arguments.Select(a => a.Value).ToArray()); // PhpValue[] return cg.EmitCall(ILOpCode.Call, create); } } }
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")); } }
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; }
void EmitInvoke(MethodSymbol invoke, Emit.PEModuleBuilder module) { if (invoke == null) { return; } module.SetMethodBody(invoke, MethodGenerator.GenerateMethodBody(module, invoke, il => { var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), OptimizationLevel.Release, false, this, new ParamPlace(invoke.Parameters[0]), new ArgPlace(this, 0)); //var __invoke = (MethodSymbol)GetMembers(Pchp.Syntax.Name.SpecialMethodNames.Invoke.Value).Single(s => s is MethodSymbol); // TODO: call __invoke() directly // context.Call<T>(T, TypeMethods.MagicMethods, params PhpValue[]) var call_t = cg.CoreTypes.Context.Symbol.GetMembers("Call") .OfType<MethodSymbol>() .Where(s => s.Arity == 1 && s.ParameterCount == 3 && s.Parameters[2].IsParams) .Single() .Construct(this); // return context.Call<T>(this, __invoke, args) cg.EmitLoadContext(); cg.EmitThis(); cg.Builder.EmitIntConstant((int)Core.Reflection.TypeMethods.MagicMethods.__invoke); cg.Builder.EmitLoadArgumentOpcode(2); cg.EmitCall(ILOpCode.Call, call_t); cg.EmitRet(invoke.ReturnType); }, null, DiagnosticBag.GetInstance(), false)); }
/// <summary> /// Emits the given conversion. 'from' and 'to' matches the classified conversion. /// </summary> public static void EmitConversion(this CodeGenerator cg, CommonConversion conversion, TypeSymbol from, TypeSymbol to, TypeSymbol op = null, bool @checked = false) { // {from}, {op} is loaded on stack // if (conversion.Exists == false) { throw cg.NotImplementedException($"Conversion from '{from}' to '{to}' "); } if (conversion.IsNullable) { if (from.IsNullableType(out var ttype)) { if (op != null) { // TODO throw new ArgumentException(nameof(op)); } var lbltrue = new NamedLabel("has value"); var lblend = new NamedLabel("end"); var tmp = cg.GetTemporaryLocal(from, true); cg.Builder.EmitLocalStore(tmp); // Template: tmp.HasValue ? convert(tmp.Value) : default cg.Builder.EmitLocalAddress(tmp); cg.EmitCall(ILOpCode.Call, cg.DeclaringCompilation.System_Nullable_T_HasValue(from)); cg.Builder.EmitBranch(ILOpCode.Brtrue, lbltrue); // default: cg.EmitLoadDefault(to); cg.Builder.EmitBranch(ILOpCode.Br, lblend); // cg.Builder.AdjustStack(-1); // ? // lbltrue: cg.Builder.MarkLabel(lbltrue); // Template: convert( tmp.GetValueOrDefault() ) cg.Builder.EmitLocalAddress(tmp); cg.EmitCall(ILOpCode.Call, cg.DeclaringCompilation.System_Nullable_T_GetValueOrDefault(from)).Expect(ttype); EmitConversion(cg, conversion.WithIsNullable(false), ttype, to, op, @checked); // lblend: cg.Builder.MarkLabel(lblend); return; } if (to.IsNullableType(out ttype)) // NOTE: not used yet { // new Nullable<TType>( convert(from) ) EmitConversion(cg, conversion.WithIsNullable(false), from, ttype, op, @checked); cg.EmitCall(ILOpCode.Newobj, ((NamedTypeSymbol)to).InstanceConstructors[0]); // new Nullable<T>( STACK ) return; } throw Roslyn.Utilities.ExceptionUtilities.Unreachable; } if (conversion.IsIdentity) { if (op != null) { throw new ArgumentException(nameof(op)); } if (to.SpecialType == SpecialType.System_Void) { // POP cg.EmitPop(from); } // nop } else if (conversion.IsNumeric) { if (op != null) { throw new ArgumentException(nameof(op)); } EmitNumericConversion(cg, from, to, @checked: @checked); } else if (conversion.IsReference) { if (op != null) { throw new ArgumentException(nameof(op)); } // TODO: ensure from/to is a valid reference type cg.EmitCastClass(to); } else if (conversion.IsUserDefined) { var method = (MethodSymbol)conversion.MethodSymbol; var ps = method.Parameters; int pconsumed = 0; if (method.HasThis) { if (from.IsValueType) { if (op != null || from.IsVoid()) { throw new ArgumentException(nameof(op)); } cg.EmitStructAddr(from); } } else { if (ps[0].RefKind != RefKind.None) { throw new InvalidOperationException(); } if (from != ps[0].Type) { if (op != null) { if (!ps[0].Type.IsAssignableFrom(from)) { throw new ArgumentException(nameof(op)); } } else { EmitImplicitConversion(cg, from, ps[0].Type, @checked: @checked); } } pconsumed++; } if (op != null) { if (ps.Length > pconsumed) { EmitImplicitConversion(cg, op, ps[pconsumed].Type, @checked: @checked); } pconsumed++; } // Context ctx, if (ps.Length > pconsumed && SpecialParameterSymbol.IsContextParameter(ps[pconsumed])) { cg.EmitLoadContext(); pconsumed++; } if (ps.Length != pconsumed) { throw new InvalidOperationException(); } EmitImplicitConversion(cg, cg.EmitCall(method.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call, method), to, @checked: true); } else { throw new NotImplementedException(); } }
/// <summary> /// Emits the given conversion. 'from' and 'to' matches the classified conversion. /// </summary> public static void EmitConversion(this CodeGenerator cg, CommonConversion conversion, TypeSymbol from, TypeSymbol to, TypeSymbol op = null, bool @checked = false) { // {from}, {op} is loaded on stack // if (conversion.Exists == false) { throw cg.NotImplementedException($"Conversion from '{from}' to '{to}' "); } if (conversion.IsIdentity) { if (op != null) { throw new ArgumentException(nameof(op)); } if (to.SpecialType == SpecialType.System_Void) { // POP cg.EmitPop(from); } // nop } else if (conversion.IsNumeric) { if (op != null) { throw new ArgumentException(nameof(op)); } EmitNumericConversion(cg, from, to, @checked: @checked); } else if (conversion.IsReference) { if (op != null) { throw new ArgumentException(nameof(op)); } // TODO: ensure from/to is a valid reference type cg.EmitCastClass(to); } else if (conversion.IsUserDefined) { var method = (MethodSymbol)conversion.MethodSymbol; var ps = method.Parameters; int pconsumed = 0; if (method.HasThis) { if (from.IsValueType) { if (op != null) { throw new ArgumentException(nameof(op)); } cg.EmitStructAddr(from); } } else { if (ps[0].RefKind != RefKind.None) { throw new InvalidOperationException(); } if (from != ps[0].Type) { if (op != null) { if (!ps[0].Type.IsAssignableFrom(from)) { throw new ArgumentException(nameof(op)); } } else { EmitImplicitConversion(cg, from, ps[0].Type, @checked: @checked); } } pconsumed++; } if (op != null) { if (ps.Length > pconsumed) { EmitImplicitConversion(cg, op, ps[pconsumed].Type, @checked: @checked); } pconsumed++; } // Context ctx, if (ps.Length > pconsumed && SpecialParameterSymbol.IsContextParameter(ps[pconsumed])) { cg.EmitLoadContext(); pconsumed++; } if (ps.Length != pconsumed) { throw new InvalidOperationException(); } EmitImplicitConversion(cg, cg.EmitCall(method.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call, method), to, @checked: true); } else { throw new NotImplementedException(); } }
public void EmitStorePrepare(CodeGenerator cg, InstanceCacheHolder instanceOpt = null) { // Context cg.EmitLoadContext(); }
public TypeSymbol EmitLoad(CodeGenerator cg) { cg.EmitLoadContext(); return cg.EmitCall(ILOpCode.Call, ResolveSuperglobalProperty(cg).GetMethod); }
public TypeSymbol EmitLoad(CodeGenerator cg) { Debug.Assert(Access.IsRead); var type = Field.Type; // Ensure Object (..->Field->.. =) if (Access.EnsureObject) { if (type == cg.CoreTypes.PhpAlias) { EmitOpCode_Load(cg); // PhpAlias return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpAlias.EnsureObject) .Expect(SpecialType.System_Object); } else if (type == cg.CoreTypes.PhpValue) { EmitOpCode_LoadAddress(cg); // &PhpValue return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureObject) .Expect(SpecialType.System_Object); } else { if (type.IsReferenceType) { // TODO: ensure it is not null EmitOpCode_Load(cg); return type; } else { // return new stdClass(ctx) throw new NotImplementedException(); } } } // Ensure Array (xxx->Field[] =) else if (Access.EnsureArray) { if (type == cg.CoreTypes.PhpAlias) { EmitOpCode_Load(cg); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpAlias.EnsureArray) .Expect(cg.CoreTypes.IPhpArray); } else if (type == cg.CoreTypes.PhpValue) { EmitOpCode_LoadAddress(cg); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureArray) .Expect(cg.CoreTypes.IPhpArray); } else if (type.IsOfType(cg.CoreTypes.IPhpArray)) { EmitOpCode_LoadAddress(cg); // ensure value is not null if (type == cg.CoreTypes.PhpArray) { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.EnsureArray_PhpArrayRef) .Expect(cg.CoreTypes.PhpArray); } else { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.EnsureArray_IPhpArrayRef) .Expect(cg.CoreTypes.IPhpArray); } } throw new NotImplementedException(); } // Ensure Alias (&...->Field) else if (Access.IsReadRef) { if (type == cg.CoreTypes.PhpAlias) { // TODO: <place>.AddRef() EmitOpCode_Load(cg); return type; } else if (type == cg.CoreTypes.PhpValue) { // return <place>.EnsureAlias() EmitOpCode_LoadAddress(cg); // &PhpValue return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureAlias) .Expect(cg.CoreTypes.PhpAlias); } else { Debug.Assert(false, "value cannot be aliased"); // new PhpAlias((PhpValue)<place>, 1) EmitOpCode_Load(cg); cg.EmitConvertToPhpValue(type, 0); return cg.Emit_PhpValue_MakeAlias(); } } // Read (...->Field) & Dereference eventually else { if (type == cg.CoreTypes.PhpAlias) { EmitOpCode_Load(cg); if (Access.TargetType != null) { // convert PhpValue to target type without loading whole value and storing to temporary variable switch (Access.TargetType.SpecialType) { default: if (Access.TargetType == cg.CoreTypes.PhpArray) { // <PhpAlias>.Value.ToArray() cg.Builder.EmitOpCode(ILOpCode.Ldflda); cg.EmitSymbolToken(cg.CoreMethods.PhpAlias.Value, null); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToArray); } break; } } return cg.Emit_PhpAlias_GetValue(); } else if (type == cg.CoreTypes.PhpValue) { if (Access.TargetType != null) { // convert PhpValue to target type without loading whole value and storing to temporary variable switch (Access.TargetType.SpecialType) { case SpecialType.System_Double: EmitOpCode_LoadAddress(cg); // &PhpValue.ToDouble() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToDouble); case SpecialType.System_Int64: EmitOpCode_LoadAddress(cg); // &PhpValue.ToLong() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToLong); case SpecialType.System_Boolean: EmitOpCode_LoadAddress(cg); // &PhpValue.ToBoolean() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToBoolean); case SpecialType.System_String: EmitOpCode_LoadAddress(cg); // &PhpValue.ToString(ctx) cg.EmitLoadContext(); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToString_Context); case SpecialType.System_Object: EmitOpCode_LoadAddress(cg); // &PhpValue.ToClass() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToClass); default: if (Access.TargetType == cg.CoreTypes.PhpArray) { EmitOpCode_LoadAddress(cg); // &PhpValue.ToArray() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToArray); } break; } } // TODO: dereference if applicable (=> PhpValue.Alias.Value) EmitOpCode_Load(cg); return type; } else { EmitOpCode_Load(cg); return type; } } }
protected override TypeSymbol LoadVariablesArray(CodeGenerator cg) { if (cg.IsGlobalScope) { // <locals> Debug.Assert(cg.LocalsPlaceOpt != null); return cg.LocalsPlaceOpt.EmitLoad(cg.Builder) .Expect(cg.CoreTypes.PhpArray); } else { // $GLOBALS cg.EmitLoadContext(); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Context.Globals.Getter); // <ctx>.Globals } }
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 TypeSymbol Emit(CodeGenerator cg) { switch (this.Type) { case PseudoConstUse.Types.File: // <ctx>.FilePath<TScript>() cg.EmitLoadContext(); return cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.Context.ScriptPath_TScript.Symbol.Construct(cg.Routine.ContainingFile)) .Expect(SpecialType.System_String); default: // the other pseudoconstants should be resolved by flow analysis throw ExceptionUtilities.Unreachable; } }
void EmitPhpNew(SynthesizedPhpNewMethodSymbol phpnew, Emit.PEModuleBuilder module) { if (phpnew == null) return; // static class module.SetMethodBody(phpnew, MethodGenerator.GenerateMethodBody(module, phpnew, (Action<Microsoft.CodeAnalysis.CodeGen.ILBuilder>)(il => { Debug.Assert(SpecialParameterSymbol.IsContextParameter(phpnew.Parameters[0])); var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), OptimizationLevel.Release, false, this, new ParamPlace(phpnew.Parameters[0]), new ArgPlace(this, 0)); // initialize <ctx> field, // if field is declared within this type var ctxField = this.ContextStore; if (ctxField != null && object.ReferenceEquals((object)ctxField.ContainingType, this)) { var ctxFieldPlace = new FieldPlace(cg.ThisPlaceOpt, (IFieldSymbol)ctxField); // Debug.Assert(<ctx> != null) cg.EmitDebugAssertNotNull(cg.ContextPlaceOpt, "Context cannot be null."); // <this>.<ctx> = <ctx> ctxFieldPlace.EmitStorePrepare(il); cg.EmitLoadContext(); ctxFieldPlace.EmitStore(il); } // initialize class fields foreach (var fld in this.GetFieldsToEmit().OfType<SourceFieldSymbol>().Where(fld => !fld.RequiresHolder && !fld.IsStatic && !fld.IsConst)) { fld.EmitInit(cg); } // base..phpnew ?? base..ctor var basenew = phpnew.BasePhpNew; Debug.Assert(basenew != null); cg.EmitPop(cg.EmitThisCall(basenew, phpnew)); Debug.Assert(phpnew.ReturnsVoid); cg.EmitRet(phpnew.ReturnType); }), null, DiagnosticBag.GetInstance(), false)); }
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); }
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); }