internal void EmitHelpers() { CompilationUnit unit = this.CompilationUnit; ILEmitter il = new ILEmitter(DeclareHelperBuilder); IndexedPlace script_context_place = new IndexedPlace(PlaceHolder.Argument, 0); foreach (PhpFunction function in unit.GetDeclaredFunctions()) { if (function.IsDefinite) { CodeGenerator.EmitDeclareFunction(il, script_context_place, function); } } foreach (PhpType type in unit.GetDeclaredTypes()) { if (type.IsDefinite) { // CALL <context>.DeclareType(<type desc>, <name>); type.EmitAutoDeclareOnScriptContext(il, script_context_place); } else if (!type.IsComplete) { if (type.IncompleteClassDeclareMethodInfo != null) { // check whether base class is known at this point of execution, // if so, declare this incomplete class immediately. As PHP does. type.EmitDeclareIncompleteOnScriptContext(il, script_context_place); } } } foreach (GlobalConstant constant in unit.GetDeclaredConstants()) { if (constant.IsDefinite) { var field = constant.RealField; Debug.Assert(field != null); Debug.Assert(field.IsStatic); // CALL <context>.DeclareConstant(<name>, <value>); script_context_place.EmitLoad(il); il.Emit(OpCodes.Ldstr, constant.FullName); il.LoadLiteralBox(constant.Value); //il.Emit(OpCodes.Ldsfld, field); // const field cannot be referenced in IL il.Emit(OpCodes.Call, Methods.ScriptContext.DeclareConstant); } } il.Emit(OpCodes.Ret); }
/// <summary> /// Emits helper declaring all single-declared functions and classes in the script being built. /// </summary> /// <remarks> /// For each function and class emits a call to <see cref="ApplicationContext.DeclareFunction"/> and /// <see cref="ApplicationContext.DeclareType"/>, respectively, which declares it. /// The helper is called as the first instruction of Main helper. /// </remarks> private void EmitDeclareHelper() { PureCompilationUnit unit = this.PureCompilationUnit; ILEmitter il = new ILEmitter(declareHelperBuilder); IndexedPlace app_context_place = new IndexedPlace(PlaceHolder.Argument, 0); TypeBuilder publicsContainer = null; // container type for public stubs of global declarations (which are inaccessible from other assemblies) foreach (PhpFunction function in unit.GetDeclaredFunctions()) { if (function.IsDefinite) { app_context_place.EmitLoad(il); // NEW RoutineDelegate(<static method>); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldftn, function.ArgLessInfo); il.Emit(OpCodes.Newobj, Constructors.RoutineDelegate); // LOAD <full name>; il.Emit(OpCodes.Ldstr, function.FullName); // LOAD <attributes>; il.LdcI4((int)function.MemberDesc.MemberAttributes); // LOAD <argfull> if (function.ArgFullInfo != null) CodeGenerator.EmitLoadMethodInfo( il, (function.ArgFullInfo.DeclaringType != null) ? function.ArgFullInfo : EmitPhpFunctionPublicStub(ref publicsContainer, function) // function.ArgFullInfo is real global method not accessible from other assemblies, must be wrapped /*, AssemblyBuilder.DelegateBuilder*/); else il.Emit(OpCodes.Ldnull); // CALL <application context>.DeclareFunction(<stub>, <name>, <member attributes>, <argfull>) il.Emit(OpCodes.Call, Methods.ApplicationContext.DeclareFunction); } } foreach (PhpType type in unit.GetDeclaredTypes()) { if (type.IsDefinite) { // CALL <application context>.DeclareType(<type desc>, <name>); type.EmitAutoDeclareOnApplicationContext(il, app_context_place); } } foreach (GlobalConstant constant in unit.GetDeclaredConstants()) { if (constant.IsDefinite) { app_context_place.EmitLoad(il); // CALL <application context>.DeclareConstant(<name>, <value>); il.Emit(OpCodes.Ldstr, constant.FullName); //il.Emit(OpCodes.Ldsfld, constant.RealField); //if (constant.RealField.FieldType.IsValueType) il.Emit(OpCodes.Box, constant.RealField.FieldType); il.LoadLiteralBox(constant.Value); il.Emit(OpCodes.Call, Methods.ApplicationContext.DeclareConstant); } } il.Emit(OpCodes.Ret); // complete the publicsContainer type, if created: if (publicsContainer != null) publicsContainer.CreateType(); }
/// <summary> /// Called when a <see cref="PHP.Core.AST.ConstantDecl"/> AST node is visited during the emit phase. /// </summary> /// <param name="constant">The constant.</param> /// <remarks> /// Even interface constants are permitted in PHP. These are implemented by <B>static</B> <B>initonly</B> /// fields in the interface, which causes some complaints in the .NET Framework 1.1 verifier. /// However it is rather a verifier bug - .NET Framework 2.0 verifier is fixed and verifies it OK. /// </remarks> public void InitializeClassConstant(ClassConstant/*!*/ constant) { Debug.Assert(constant != null); // real constant definition if (constant.RealField.IsLiteral) { Debug.Assert(constant.RealFieldBuilder != null); constant.RealFieldBuilder.SetConstant(constant.Value); return; } // class constant initialization is emitted into the static constructor ILEmitter old_il = il; IPlace old_sc_emitter = ScriptContextPlace; try { // set il and SC-emitter appropriately if (constant.HasValue) { il = constant.DeclaringPhpType.Builder.StaticCtorEmitter; il.LoadLiteralBox(constant.Value); } else { il = new ILEmitter(constant.DeclaringPhpType.StaticFieldInitMethodBuilder); ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, ScriptBuilder.ArgContext); // emit the expression evaluating code EmitBoxing(constant.Node.Initializer.Emit(this)); } // store it in the field il.Emit(OpCodes.Stsfld, constant.RealField); } finally { // restore the saved il and SC-emitter il = old_il; ScriptContextPlace = old_sc_emitter; } }