private void EmitNodeWriteAssign(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(this.isMemberOf is SimpleVarUse || this.isMemberOf is FunctionCall); if (this.isMemberOf is FunctionCall) { codeGenerator.ChainBuilder.LoadAddressOfFunctionReturnValue = true; } assignmentCallback(codeGenerator, PhpTypeCode.Object); SimpleVarUse svu = this.isMemberOf as SimpleVarUse; if (svu != null) { svu.EmitLoadAddress_StoreBack(codeGenerator); } // else do nothing } chain.End(); } else { // 7: $a //codeGenerator.EmitVariableStoreAssign(this); this.EmitStoreAssign(codeGenerator); } }
/// <summary> /// Emits IL instructions that read the value of an instance field. /// </summary> /// <param name="codeGenerator">The current <see cref="CodeGenerator"/>.</param> /// <param name="wantRef">If <B>false</B> the field value should be left on the evaluation stack, /// if <B>true</B> the <see cref="PhpReference"/> should be left on the evaluation stack.</param> /// <returns> /// Nothing is expected on the evaluation stack. A <see cref="PhpReference"/> (if <paramref name="wantRef"/> /// is <B>true</B>) or the field value itself (if <paramref name="wantRef"/> is <B>false</B>) is left on the /// evaluation stack. /// </returns> internal virtual PhpTypeCode EmitReadField(CodeGenerator codeGenerator, bool wantRef) { ILEmitter il = codeGenerator.IL; DirectVarUse direct_instance = isMemberOf as DirectVarUse; if (direct_instance != null && direct_instance.IsMemberOf == null && direct_instance.VarName.IsThisVariableName) { return(EmitReadFieldOfThis(codeGenerator, wantRef)); } if (!wantRef) { //codeGenerator.ChainBuilder.Lengthen(); //PhpTypeCode type_code = isMemberOf.Emit(codeGenerator); //Debug.Assert(type_code == PhpTypeCode.Object || type_code == PhpTypeCode.DObject); //// CALL Operators.GetProperty(STACK,<field name>,<type desc>,<quiet>); //EmitName(codeGenerator); //codeGenerator.EmitLoadClassContext(); //il.LoadBool(codeGenerator.ChainBuilder.QuietRead); //il.Emit(OpCodes.Call, Methods.Operators.GetProperty); //return PhpTypeCode.Object; string fieldName = (this is DirectVarUse) ? ((DirectVarUse)this).VarName.Value : null; Expression fieldNameExpr = (this is IndirectVarUse) ? ((IndirectVarUse)this).VarNameEx : null; bool quietRead = wantRef ? false : codeGenerator.ChainBuilder.QuietRead; return(codeGenerator.CallSitesBuilder.EmitGetProperty( codeGenerator, wantRef, isMemberOf, null, null, null, fieldName, fieldNameExpr, quietRead)); } // call GetProperty/GetObjectPropertyRef codeGenerator.ChainBuilder.Lengthen(); // loads the variable which field is gotten: PhpTypeCode var_type_code = isMemberOf.Emit(codeGenerator); if (codeGenerator.ChainBuilder.Exists) { Debug.Assert(var_type_code == PhpTypeCode.DObject); // CALL Operators.GetObjectPropertyRef(STACK,<field name>,<type desc>); EmitName(codeGenerator); codeGenerator.EmitLoadClassContext(); il.Emit(OpCodes.Call, Methods.Operators.GetObjectPropertyRef); } else { Debug.Assert(var_type_code == PhpTypeCode.ObjectAddress); // CALL Operators.GetPropertyRef(ref STACK,<field name>,<type desc>,<script context>); EmitName(codeGenerator); codeGenerator.EmitLoadClassContext(); codeGenerator.EmitLoadScriptContext(); il.Emit(OpCodes.Call, Methods.Operators.GetPropertyRef); // stores the value of variable back: SimpleVarUse simple_var = isMemberOf as SimpleVarUse; if (simple_var != null) { simple_var.EmitLoadAddress_StoreBack(codeGenerator); } } return(PhpTypeCode.PhpReference); }
/// <summary> /// Emits IL instructions that ensure that the specified variable is an instance of <see cref="PhpObject"/>. /// </summary> /// <param name="variable">Variable that should be examined.</param> /// <remarks> /// This method is used in operators chains. Nothing is expected on the evaluation stack. /// If the specified variable is an instance of <see cref="PhpObject"/> /// it is left on the evaluation stack. Otherwise the control is transfered to the end of /// the chain. /// </remarks> public void EmitEnsureVariableIsObject(SimpleVarUse variable) { ILEmitter il = codeGenerator.IL; DirectVarUse direct_variable = variable as DirectVarUse; if (direct_variable != null && direct_variable.VarName.IsThisVariableName) { // special treatment of $this switch (codeGenerator.LocationStack.LocationType) { case LocationTypes.GlobalCode: { // load $this from one of Main's arguments and check for null Label this_non_null = il.DefineLabel(); codeGenerator.EmitLoadSelf(); il.Emit(OpCodes.Brtrue_S, this_non_null); codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext); il.Emit(OpCodes.Br, TopChain.ErrorLabel); il.MarkLabel(this_non_null, true); codeGenerator.EmitLoadSelf(); break; } case LocationTypes.FunctionDecl: { // always throws error codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext); il.Emit(OpCodes.Br, TopChain.ErrorLabel); break; } case LocationTypes.MethodDecl: { CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl(); if (context.Method.IsStatic) { // always throws error codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext); il.Emit(OpCodes.Br, TopChain.ErrorLabel); } else { // arg0 or <proxy> in instance methods codeGenerator.EmitLoadSelf(); } break; } default: Debug.Assert(false, "Invalid location type."); break; } } else { // Template: PhpObject EnsureVariableIsObject(ref object,ScriptContext) // Load variable's address // if (variable is FunctionCall) // { // variable.Emit(this); // EmitLoadScriptContext(); // il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsObject); // // Store the changed destVar into table of variables (do nothing in optimalized functions) // } // else // { variable.EmitLoadAddress(codeGenerator); codeGenerator.EmitLoadScriptContext(); il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsObject); // Store the changed destVar into table of variables (do nothing in optimalized functions) variable.EmitLoadAddress_StoreBack(codeGenerator); // } EmitErrorCheck(false); } }
/// <summary> /// Emits IL instructions that ensure that the specified variable is an instance of <see cref="PhpArray"/>. /// </summary> /// <param name="variable">Variable's name-index to a table of identifiers.</param> /// <remarks> /// This method is used in operators chains. Nothing is expected on the evaluation stack. /// If the specified variable is an instance of <see cref="PhpArray"/> /// it is left on the evaluation stack. Otherwise the control is transfered to the end of /// the chain. /// </remarks> public void EmitEnsureVariableIsArray(SimpleVarUse variable) { // Template: PhpArray EnsureVariableIsArray(ref object) // Load variable's address //this.EmitVariableLoadAddress(variable); variable.EmitLoadAddress(codeGenerator); codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsArray); // Store the changed destVar into table of variables (do nothing in optimalized functions) variable.EmitLoadAddress_StoreBack(codeGenerator); EmitErrorCheck(true); }
/// <summary> /// Emits IL instructions that loads the value of array's item as a <see cref="PHP.Core.PhpReference"/>. /// </summary> /// <param name="variable">A simple variable.</param> /// <param name="index"><see cref="Expression"/> determining the index.</param> public PhpTypeCode EmitGetItemRef(SimpleVarUse/*!*/ variable, Expression index) { IsArrayItem = true; IsLastMember = true; PhpTypeCode index_type_code = PhpTypeCode.Invalid; // index: if (index != null) index_type_code = codeGenerator.EmitArrayKey(this, index); // array: variable.Emit(codeGenerator); // LOAD Operators.GetItemRef([<index>], ref <variable>) codeGenerator.EmitGetItem(index_type_code, index, true); // store the changed variable into table of variables (do nothing in optimalized functions) variable.EmitLoadAddress_StoreBack(codeGenerator); IsArrayItem = false; return PhpTypeCode.PhpReference; }