internal override void Emit(GlobalStmt node, CodeGenerator codeGenerator) { Statistics.AST.AddNode("GlobalStmt"); foreach (SimpleVarUse variable in node.VarList) { variable.Emit(codeGenerator); // CALL Operators.GetItemRef(<string variable name>, ref context.AutoGlobals.GLOBALS); SimpleVarUseHelper.EmitName(variable, codeGenerator); codeGenerator.EmitAutoGlobalLoadAddress(new VariableName(VariableName.GlobalsName)); codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.GetItemRef.String); SimpleVarUseHelper.EmitAssign(variable, codeGenerator); } }
private void EmitNodeWriteAssign(IndirectVarUse node, CodeGenerator codeGenerator) { ChainBuilder chain = codeGenerator.ChainBuilder; // Note that for cases 1,3,4,5,6,9 EmitAssign is never called!!! // 2,7,8 if (chain.IsMember) { // 2,8 if (chain.Exists) { // 8: b[]->$a chain.EmitSetObjectField(); } else { // 2: $b->a Debug.Assert(node.IsMemberOf is SimpleVarUse || node.IsMemberOf is FunctionCall); if (node.IsMemberOf is FunctionCall) { codeGenerator.ChainBuilder.LoadAddressOfFunctionReturnValue = true; } assignmentCallback(codeGenerator, PhpTypeCode.Object); SimpleVarUse svu = node.IsMemberOf as SimpleVarUse; if (svu != null) { SimpleVarUseHelper.EmitLoadAddress_StoreBack(svu, codeGenerator); } // else do nothing } chain.End(); } else { // 7: $a //codeGenerator.EmitVariableStoreAssign(this); this.EmitStoreAssign(node, codeGenerator); } }
/// <summary> /// Emits the catch-block. /// </summary> /// <param name="node">Instance.</param> /// <param name="codeGenerator">A code generator.</param> /// <param name="exceptionLocal">A local variable containing an instance of <see cref="Library.SPL.Exception"/>.</param> /// <param name="endLabel">A label in IL stream where the processing of the try-catch blocks ends.</param> /// <param name="nextCatchLabel">A label in IL stream where the next catch block processing begins.</param> public void Emit(CatchItem /*!*/ node, CodeGenerator /*!*/ codeGenerator, LocalBuilder /*!*/ exceptionLocal, Label endLabel, Label nextCatchLabel) { ILEmitter il = codeGenerator.IL; codeGenerator.MarkSequencePoint(node.Variable); // IF !InstanceOf(<class name>) GOTO next_catch; il.Ldloc(exceptionLocal); resolvedType.EmitInstanceOf(codeGenerator, null); il.Emit(OpCodes.Brfalse, nextCatchLabel); // variable = exception; node.Variable.Emit(codeGenerator); il.Ldloc(exceptionLocal); SimpleVarUseHelper.EmitAssign(node.Variable, codeGenerator); node.Statements.Emit(codeGenerator); // LEAVE end; il.Emit(OpCodes.Leave, endLabel); }
public void Emit(StaticVarDecl /*!*/ node, CodeGenerator codeGenerator) { ILEmitter il = codeGenerator.IL; string id = codeGenerator.GetLocationId(); if (id == null) { // we are in global code -> just assign the iniVal to the variable node.Variable.Emit(codeGenerator); if (node.Initializer != null) { codeGenerator.EmitBoxing(node.Initializer.Emit(codeGenerator)); il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object); } else { il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void); } // continue ... } else { // cache the integer index of static local variable to access its value fast from within the array // unique static local variable string ID id = String.Format("{0}${1}${2}", id, node.Variable.VarName, node.Span.Start); // create static field for static local index: private static int <id>; var type = codeGenerator.IL.TypeBuilder; Debug.Assert(type != null, "The method does not have declaring type! (global code in pure mode?)"); var field_id = type.DefineField(id, Types.Int[0], System.Reflection.FieldAttributes.Private | System.Reflection.FieldAttributes.Static); // we are in a function or method -> try to retrieve the local value from ScriptContext node.Variable.Emit(codeGenerator); // <context>.GetStaticLocal( <field> ) codeGenerator.EmitLoadScriptContext(); // <context> il.Emit(OpCodes.Ldsfld, field_id); // <field> il.Emit(OpCodes.Callvirt, Methods.ScriptContext.GetStaticLocal); // GetStaticLocal il.Emit(OpCodes.Dup); // ?? <context>.AddStaticLocal( <field> != 0 ? <field> : ( <field> = ScriptContext.GetStaticLocalId(<id>) ), <initializer> ) if (true) { // if (GetStaticLocal(<field>) == null) Label local_initialized = il.DefineLabel(); il.Emit(OpCodes.Brtrue /*not .S, initializer can emit really long code*/, local_initialized); il.Emit(OpCodes.Pop); // <field> != 0 ? <field> : ( <field> = ScriptContext.GetStaticLocalId(<id>) ) il.Emit(OpCodes.Ldsfld, field_id); // <field> if (true) { // if (<field> == 0) Label id_initialized = il.DefineLabel(); il.Emit(OpCodes.Brtrue_S, id_initialized); // <field> = GetStaticLocalId( <id> ) il.Emit(OpCodes.Ldstr, id); il.Emit(OpCodes.Call, Methods.ScriptContext.GetStaticLocalId); il.Emit(OpCodes.Stsfld, field_id); il.MarkLabel(id_initialized); } // <context>.AddStaticLocal(<field>,<initialize>) codeGenerator.EmitLoadScriptContext(); // <context> il.Emit(OpCodes.Ldsfld, field_id); // <field> if (node.Initializer != null) { codeGenerator.EmitBoxing(node.Initializer.Emit(codeGenerator)); // <initializer> } else { il.Emit(OpCodes.Ldnull); } il.Emit(OpCodes.Callvirt, Methods.ScriptContext.AddStaticLocal); // AddStaticLocal // il.MarkLabel(local_initialized); } // continue ... } // stores value from top of the stack to the variable: SimpleVarUseHelper.EmitAssign(node.Variable, codeGenerator); }
internal override PhpTypeCode EmitAssign(ItemUse node, CodeGenerator codeGenerator) { var chain = codeGenerator.ChainBuilder; PhpTypeCode result; switch (access) { case AccessType.WriteAndReadRef: case AccessType.WriteAndReadUnknown: case AccessType.ReadAndWrite: case AccessType.ReadAndWriteAndReadRef: case AccessType.ReadAndWriteAndReadUnknown: case AccessType.Write: case AccessType.WriteRef: { bool reference = access == AccessType.WriteRef; // Note that some work was done in Emit() ! // In cases 3, 4, 5 EmitAssign is not called if (node.IsMemberOf != null || (node.IsMemberOf == null && (node.Array is DirectStFldUse || node.Array is IndirectStFldUse || node.Array is ItemUse))) { // 2, 6, 7 chain.EmitSetArrayItem(indexTypeCode, node.Index, reference); chain.End(); } else { // Note: The value which should be stored is already loaded on the evaluation stack. // Push the destination array and index and call the operator // 1: a_[x]_ Debug.Assert(node.Array is SimpleVarUse); chain.IsArrayItem = true; chain.IsLastMember = true; indexTypeCode = codeGenerator.EmitArrayKey(chain, node.Index); node.Array.Emit(codeGenerator); chain.EmitSetItem(indexTypeCode, node.Index, reference); // Store the changed variable into table of variables (do nothing in optimalized functions) SimpleVarUseHelper.EmitLoadAddress_StoreBack((SimpleVarUse)node.Array, codeGenerator); } result = PhpTypeCode.Void; break; } case AccessType.None: // do nothing result = PhpTypeCode.Void; break; case AccessType.Read: // do nothing result = PhpTypeCode.Object; break; case AccessType.ReadRef: // Do nothing result = PhpTypeCode.PhpReference; break; default: Debug.Fail(null); result = PhpTypeCode.Invalid; break; } return(result); }