/// <summary> /// Loads a value of a specified variable. If the variable is of type <see cref="PhpReference"/>, it is dereferenced. /// </summary> internal void LoadLocal(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName) { ILEmitter il = codeGenerator.IL; Debug.Assert(variable == null ^ variableName == null); if (variable != null) { // LOAD DEREF <variable>; variable.Variable.EmitLoad(il); if (variable.IsPhpReference) il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value); } else { // LOAD Operators.GetVariable[Unchecked](<script context>, <local variables table>, <variable name>); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); il.Ldloc(variableName); if (codeGenerator.ChainBuilder.QuietRead) il.Emit(OpCodes.Call, Methods.Operators.GetVariableUnchecked); else il.Emit(OpCodes.Call, Methods.Operators.GetVariable); } }
/// <summary> /// Loads a specified reference local variable. /// </summary> internal void LoadLocalRef(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName) { ILEmitter il = codeGenerator.IL; Debug.Assert(variable == null ^ variableName == null); if (variable != null) { Debug.Assert(variable.IsPhpReference); variable.Variable.EmitLoad(il); } else { codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); il.Ldloc(variableName); il.Emit(OpCodes.Call, Methods.Operators.GetVariableRef); } }
internal override void EmitLoadRef(CodeGenerator codeGenerator) { ILEmitter il = codeGenerator.IL; if (codeGenerator.OptimizedLocals) { // For IndirectVarUse emit switch over all variables. EmitSwitch(codeGenerator, new SwitchMethod(LoadLocalRef)); } else { // Template: // PhpReference Operators.GetVariableRef(IDictionary table, string name) //returns variable value; variable is of type PhpReference codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); EmitName(codeGenerator); il.Emit(OpCodes.Call, Methods.Operators.GetVariableRef); } }
internal override void EmitStoreRefPrepare(CodeGenerator codeGenerator) { ILEmitter il = codeGenerator.IL; if (codeGenerator.OptimizedLocals) { // Switch over all variables // /*copypaste bug*/EmitSwitch(codeGenerator, new SwitchMethod(StoreLocalPrepare)); } else { // Template: // void Operators.SetVariable(table, "x", PhpVariable.Copy(Operators.getValue(table, "x"), CopyReason.Assigned)); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); EmitName(codeGenerator); // now load value the call Operators.SetVariable in EmitVariableStoreAssignFromTable } }
internal override void EmitUnset(CodeGenerator codeGenerator) { //Template: "unset($$x)" $$x = null; //Template: "unset(x)" x = null Debug.Assert(access == AccessType.Read); // Cases 1, 4, 5, 6, 9 never reached Debug.Assert(codeGenerator.ChainBuilder.IsMember == false); // Case 3 never reached Debug.Assert(codeGenerator.ChainBuilder.IsArrayItem == false); codeGenerator.ChainBuilder.QuietRead = true; // 2, 7, 8 if (this.isMemberOf != null) { // 2: $b->$a // 8: b[]->$a codeGenerator.ChainBuilder.Create(); codeGenerator.ChainBuilder.Begin(); EmitUnsetField(codeGenerator); codeGenerator.ChainBuilder.End(); return; } // 7: $a // Unset this variable //codeGenerator.EmitVariableUnset(this); ILEmitter il = codeGenerator.IL; if (codeGenerator.OptimizedLocals) { // /*copypaste bug*/EmitSwitch(codeGenerator, new SwitchMethod(StoreLocalPrepare)); EmitSwitch(codeGenerator, new SwitchMethod(UnsetLocal)); } else { // CALL Operators.UnsetVariable(<script context>, <local variable table>, <variable name>); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); EmitName(codeGenerator); il.Emit(OpCodes.Call, Methods.Operators.UnsetVariable); } }
/// <summary> /// Emits IL instructions that load the variable onto the evaluation stack. /// </summary> /// <param name="codeGenerator"></param> /// <remarks><B>$this</B> cannot be accessed indirectly.</remarks> internal override PhpTypeCode EmitLoad(CodeGenerator codeGenerator) { ILEmitter il = codeGenerator.IL; if (codeGenerator.OptimizedLocals) { // Switch over all local variables and dereference those being of type PhpReference EmitSwitch(codeGenerator, new SwitchMethod(LoadLocal)); } else { // LOAD Operators.GetVariable[Unchecked](<script context>, <local variables table>, <variable name>); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); EmitName(codeGenerator); if (codeGenerator.ChainBuilder.QuietRead) il.Emit(OpCodes.Call, Methods.Operators.GetVariableUnchecked); else il.Emit(OpCodes.Call, Methods.Operators.GetVariable); } return PhpTypeCode.Object; }
/// <summary> /// Stores the value represented by <see cref="TabledLocalAddressStorage"/> to the runtime variables table and /// returns the <see cref="TabledLocalAddressStorage"/> back to <see cref="ILEmitter.temporaryLocals"/>. /// Duplicates the value if requested. /// </summary> /// <param name="codeGenerator">Currently used <see cref="CodeGenerator"/>.</param> /// <param name="duplicate_value">If <c>true</c>, the value of specified local is left on the evaluation stack. /// </param> internal virtual void StoreTabledVariableBack(CodeGenerator codeGenerator, bool duplicate_value) { ILEmitter il = codeGenerator.IL; // CALL Operators.SetVariable(<local variables table>,<name>,<TabledLocalAddressStorage>); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); EmitName(codeGenerator); il.Ldloc(TabledLocalAddressStorage); il.Emit(OpCodes.Call, Methods.Operators.SetVariable); // If requested, load the changed value on the evaluation stack if (duplicate_value) il.Ldloc(this.TabledLocalAddressStorage); // Release temporary local il.ReturnTemporaryLocal(this.TabledLocalAddressStorage); }
/// <summary> /// Emits dynamic inclusion. /// </summary> private PhpTypeCode EmitDynamicInclusion(CodeGenerator/*!*/ codeGenerator) { // do not generate dynamic auto inclusions: if (InclusionTypesEnum.IsAutoInclusion(inclusionType)) return PhpTypeCode.Void; ILEmitter il = codeGenerator.IL; // CALL context.DynamicInclude(<file name>,<relative includer source path>,variables,self,includer); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitConversion(fileNameEx, PhpTypeCode.String); il.Emit(OpCodes.Ldstr, codeGenerator.SourceUnit.SourceFile.RelativePath.ToString()); codeGenerator.EmitLoadRTVariablesTable(); codeGenerator.EmitLoadSelf(); codeGenerator.EmitLoadClassContext(); il.LoadLiteral(inclusionType); il.Emit(OpCodes.Call, Methods.ScriptContext.DynamicInclude); return PhpTypeCode.Object; }
/// <summary> /// Emit load of variable named <paramref name="varName"/>. /// </summary> internal static PhpTypeCode EmitLoad(CodeGenerator codeGenerator, VariableName varName) { ILEmitter il = codeGenerator.IL; // Check if the variable is auto-global if (codeGenerator.VariableIsAutoGlobal(varName)) { codeGenerator.EmitAutoGlobalLoad(varName); return PhpTypeCode.Object; } // Variable is local if (codeGenerator.OptimizedLocals) { // Template: // ldloc loc // ***** // If the specidied variable is of type PhpReference // ldfld PhpReference.value // ***** VariablesTable.Entry entry = codeGenerator.CurrentVariablesTable[varName]; entry.Variable.EmitLoad(il); if (entry.IsPhpReference) il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value); return PhpTypeCode.Object; } // LOAD Operators.GetVariable[Unchecked](<script context>, <local variable table>, <name>); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); il.Emit(OpCodes.Ldstr, varName.Value); if (codeGenerator.ChainBuilder.QuietRead) il.Emit(OpCodes.Call, Methods.Operators.GetVariableUnchecked); else il.Emit(OpCodes.Call, Methods.Operators.GetVariable); return PhpTypeCode.Object; }
/// <summary> /// Emit reference load of variable named <paramref name="varName"/>. /// </summary> internal static void EmitLoadRef(CodeGenerator/*!*/ codeGenerator, VariableName varName) { ILEmitter il = codeGenerator.IL; // Check if the variable is auto-global if (codeGenerator.VariableIsAutoGlobal(varName)) { codeGenerator.EmitAutoGlobalLoadRef(varName); return; } if (codeGenerator.OptimizedLocals) { // Template: for DirectVarUse // "LOAD ref $x;" // // ldloc loc // Local variable should be of type PhpReference VariablesTable.Entry entry = codeGenerator.CurrentVariablesTable[varName]; entry.Variable.EmitLoad(il); } else { // Template: // PhpReference Operators.GetVariableRef(IDictionary table, string name) codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); il.Emit(OpCodes.Ldstr, varName.Value); il.Emit(OpCodes.Call, Methods.Operators.GetVariableRef); } }
internal override void EmitUnset(CodeGenerator codeGenerator) { //Template: "unset(x)" x = null Debug.Assert(access == AccessType.Read); // Cases 1, 4, 5, 6, 9 never reached Debug.Assert(codeGenerator.ChainBuilder.IsMember == false); // Case 3 never reached Debug.Assert(codeGenerator.ChainBuilder.IsArrayItem == false); codeGenerator.ChainBuilder.QuietRead = true; // 2, 7, 8 if (this.isMemberOf != null) { // 2: $b->a // 8: b[]->a codeGenerator.ChainBuilder.Create(); codeGenerator.ChainBuilder.Begin(); codeGenerator.ChainBuilder.QuietRead = true; EmitUnsetField(codeGenerator); codeGenerator.ChainBuilder.End(); return; } // 7: $a // Check if the variable is auto-global ILEmitter il = codeGenerator.IL; if (codeGenerator.VariableIsAutoGlobal(varName)) { codeGenerator.EmitAutoGlobalStorePrepare(varName); il.Emit(OpCodes.Ldnull); codeGenerator.EmitAutoGlobalStoreAssign(); return; } // Unset this variable if (codeGenerator.OptimizedLocals) { // Template: // unset(x) x = null // unset(p) p.value = null <- this case isn't valid. When p is reference just create a new PhpReference VariablesTable.Entry entry = codeGenerator.CurrentVariablesTable[varName]; if (entry.IsPhpReference) { il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void); entry.Variable.EmitStore(il); } else { il.Emit(OpCodes.Ldnull); entry.Variable.EmitStore(il); } } else { // CALL Operators.UnsetVariable(<script context>, <local variable table>, <variable name>); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); EmitName(codeGenerator); il.Emit(OpCodes.Call, Methods.Operators.UnsetVariable); } }
internal override void EmitStoreRefPrepare(CodeGenerator codeGenerator) { ILEmitter il = codeGenerator.IL; if (varName.IsThisVariableName) { // error throwing code will be emitted in EmitVariableStoreRefAssign } else if (codeGenerator.VariableIsAutoGlobal(varName)) { // Check if the variable is auto-global codeGenerator.EmitAutoGlobalStoreRefPrepare(varName); } else if (codeGenerator.OptimizedLocals) { // Template: // WRITE ref ($x,value); // DO NOTHING !!!! // now load the value then store to local variable } else { // Template: // WRITE ref ($x,value); // by Martin // // ldarg.1 // ldstr "name" // LOAD value // call instance IDictionary.set_Item(object) codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); EmitName(codeGenerator); // now load value, then call EmitVariableStoreRefAssignGlobalContext() to emit stfld ... } }
internal override void EmitStorePrepare(CodeGenerator codeGenerator) { ILEmitter il = codeGenerator.IL; if (varName.IsThisVariableName) { // Error throwing code will be emitted in EmitVariableStoreAssign } else if (codeGenerator.VariableIsAutoGlobal(varName)) { // Check if the variable is auto-global codeGenerator.EmitAutoGlobalStorePrepare(varName); } else if (codeGenerator.OptimizedLocals) { // Template: // "WRITE($x,value);" // **** // if specified variable is of type PhpReference // ldloc local // **** // Otherwise do nothing VariablesTable.Entry entry = codeGenerator.CurrentVariablesTable[varName]; if (entry.IsPhpReference) { entry.Variable.EmitLoad(il); } // Otherwise do nothing // Now load the value, then call EmitVariableStoreAssignOptimized() to store the value ... } else { // Template: // void Operators.SetVariable(table, "x", PhpVariable.Copy(Operators.getValue(table, "x"), CopyReason.Assigned)); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); EmitName(codeGenerator); // Now load the value, then call SetVariable() to store the value ... } }
///// <summary> ///// Prepares local variable for a store operation. ///// </summary> //internal void StoreLocalPrepare(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName) //{ // Debug.Assert(variable == null ^ variableName == null); //} /// <summary> /// Unsets a specified variable. /// </summary> internal void UnsetLocal(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName) { ILEmitter il = codeGenerator.IL; Debug.Assert(variable == null ^ variableName == null); if (variable != null) { if (variable.IsPhpReference) { // <variable> = new PhpReference(); il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void); variable.Variable.EmitStore(il); } else { il.Emit(OpCodes.Ldnull); variable.Variable.EmitStore(il); } } else { // CALL Operators.SetVariable(<local variables table>,<name>,null); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); il.Ldloc(variableName); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Call, Methods.Operators.SetVariable); } }
/// <summary> /// Loads the value represented by this object from the runtime variables table, /// stores it to a local variable and loads the address of this local. /// </summary> /// <remarks>This method is used only in non-optimized user functions and global code. /// Specified local variable is obtained from current <see cref="ILEmitter"/> by /// <see cref="ILEmitter.GetTemporaryLocal"/> and stored to <see cref="TabledLocalAddressStorage"/> /// for later use. Once the local become useless, <see cref="ILEmitter.ReturnTemporaryLocal"/> /// should be called. /// </remarks> /// <param name="codeGenerator">Currently used <see cref="CodeGenerator"/>.</param> internal virtual void LoadTabledVariableAddress(CodeGenerator codeGenerator) { // This function should be call only once on every SimpleVarUse object // TODO: ASSERTION FAILS (e.g. PhpMyAdmin, common.lib.php) // Debug.Assert(this.TabledLocalAddressStorage == null); ILEmitter il = codeGenerator.IL; // Load the value represented by this node from the runtime variables table // LOAD Operators.GetVariableUnchecked(<script context>, <local variables table>, <variable name>); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); EmitName(codeGenerator); codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.GetVariableUnchecked); // Get local from ILEmitter this.TabledLocalAddressStorage = il.GetTemporaryLocal(Types.Object[0]); // Store the value il.Stloc(this.TabledLocalAddressStorage); // Load the address il.Ldloca(this.TabledLocalAddressStorage); }
/// <summary> /// Stores a reference on the top of the stack to a specified variable. /// </summary> internal void StoreLocalRefAssign(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName) { ILEmitter il = codeGenerator.IL; Debug.Assert(variable == null ^ variableName == null); if (variable != null) { Debug.Assert(variable.IsPhpReference); variable.Variable.EmitStore(il); } else { // temp = STACK LocalBuilder temp = il.GetTemporaryLocal(Types.PhpReference[0], true); il.Stloc(temp); // CALL Operators.SetVariableRef(<local variables table>,<name>,temp); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); il.Ldloc(variableName); il.Ldloc(temp); il.Emit(OpCodes.Call, Methods.Operators.SetVariableRef); } }
/// <summary> /// Emits a static inclusion. /// </summary> private PhpTypeCode EmitStaticInclusion(CodeGenerator/*!*/ codeGenerator) { ILEmitter il = codeGenerator.IL; Label endif_label = il.DefineLabel(); Label else_label = il.DefineLabel(); MethodInfo method; // if the expression should be emitted: if (characteristic == Characteristic.StaticArgEvaluated) { if (!(fileNameEx is StringLiteral || fileNameEx is BinaryStringLiteral)) { // emits expression evaluation and ignores the result: fileNameEx.Emit(codeGenerator); il.Emit(OpCodes.Pop); } } if (characteristic == Characteristic.StaticAutoInclusion) { // calls the Main routine only if this script is the main one: il.Ldarg(ScriptBuilder.ArgIsMain); } else { RelativePath relativePath = new RelativePath(inclusion.Includee.RelativeSourcePath); // normalize the relative path // CALL context.StaticInclude(<relative included script source path>,<this script type>,<inclusion type>); codeGenerator.EmitLoadScriptContext(); il.Emit(OpCodes.Ldc_I4, (int)relativePath.Level); il.Emit(OpCodes.Ldstr, relativePath.Path); il.Emit(OpCodes.Ldtoken, inclusion.Includee.ScriptClassType); il.LoadLiteral(inclusionType); il.Emit(OpCodes.Call, Methods.ScriptContext.StaticInclude); } // IF (STACK) il.Emit(OpCodes.Brfalse, else_label); if (true) { // emits a call to the main helper of the included script: method = inclusion.Includee.MainHelper; // CALL <Main>(context, variables, self, includer, false): codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitLoadRTVariablesTable(); codeGenerator.EmitLoadSelf(); codeGenerator.EmitLoadClassContext(); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Call, method); il.Emit(OpCodes.Br, endif_label); } // ELSE il.MarkLabel(else_label); if (true) { // LOAD <PhpScript.SkippedIncludeReturnValue>; il.LoadLiteral(ScriptModule.SkippedIncludeReturnValue); il.Emit(OpCodes.Box, ScriptModule.SkippedIncludeReturnValue.GetType()); } il.MarkLabel(endif_label); // END IF return PhpTypeCode.Object; }