internal override PhpTypeCode EmitCall(CodeGenerator/*!*/ codeGenerator, string fallbackQualifiedName, CallSignature callSignature, IPlace instance, bool runtimeVisibilityCheck, int overloadIndex, DType type, Position position, AccessType access, bool callVirt) { Debug.Assert(instance == null || instance is ExpressionPlace); Debug.Assert(fallbackQualifiedName == null); return codeGenerator.EmitRoutineOperatorCall(declaringType, ExpressionPlace.GetExpression(instance), FullName, null, null, callSignature, access); // TODO: check operators: should deep-copy return value if PhpRoutine is called }
internal override PhpTypeCode EmitCall(CodeGenerator/*!*/ codeGenerator, string fallbackQualifiedName, CallSignature callSignature, IPlace instance, bool runtimeVisibilityCheck, int overloadIndex, DType type, Position position, AccessType access, bool callVirt) { return codeGenerator.EmitRoutineOperatorCall(null, null, FullName, fallbackQualifiedName, null, callSignature, access); }
internal override PhpTypeCode EmitCall(CodeGenerator/*!*/ codeGenerator, string fallbackQualifiedName, CallSignature callSignature, IPlace instance, bool runtimeVisibilityCheck, int overloadIndex, DType type, Position position, AccessType access, bool callVirt) { Debug.Assert(instance == null && !runtimeVisibilityCheck); Debug.Assert(callVirt == false); if (!IsDefinite) { return codeGenerator.EmitRoutineOperatorCall(null, null, this.FullName, null, null, callSignature, access); } else { return base.EmitCall(codeGenerator, fallbackQualifiedName, callSignature, null, false, overloadIndex, null, position, access, callVirt); } }
internal override PhpTypeCode EmitCall(CodeGenerator/*!*/ codeGenerator, string fallbackQualifiedName, CallSignature callSignature, IPlace instance, bool runtimeVisibilityCheck, int overloadIndex, DType type, Position position, AccessType access, bool callVirt) { #if DEBUG_DYNAMIC_STUBS MethodBuilder mb = codeGenerator.IL.TypeBuilder.DefineMethod(DeclaringType.FullName + "::" + FullName, MethodAttributes.PrivateScope | MethodAttributes.Static, typeof(object), Types.Object_PhpStack); ILEmitter il = new ILEmitter(mb); IndexedPlace instance2 = new IndexedPlace(PlaceHolder.Argument, 0); IndexedPlace stack = new IndexedPlace(PlaceHolder.Argument, 1); EmitArglessStub(il, stack, instance2); #endif Debug.Assert(instance == null || instance is ExpressionPlace || instance == IndexedPlace.ThisArg); Debug.Assert(fallbackQualifiedName == null); return codeGenerator.EmitRoutineOperatorCall(DeclaringType, ExpressionPlace.GetExpression(instance), this.FullName, null, null, callSignature, access); }
internal override PhpTypeCode EmitCall(CodeGenerator/*!*/ codeGenerator, string fallbackQualifiedName, CallSignature callSignature, IPlace instance, bool runtimeVisibilityCheck, int overloadIndex, DType type, Position position, AccessType access, bool callVirt) { if (IsStatic != (instance == null) || runtimeVisibilityCheck) { Expression targetExpression = null; if (instance != null) { targetExpression = ExpressionPlace.GetExpression(instance); // the instance expression, $this would be determined in runtime Debug.Assert(targetExpression != null || instance == IndexedPlace.ThisArg, "Unexpected instance IPlace type" + this.Name.Value); } // call the operator if we could not provide an appropriate instance or the visibility has to be checked: return codeGenerator.EmitRoutineOperatorCall(this.UsesLateStaticBinding ? type : this.DeclaringType, targetExpression, this.FullName, fallbackQualifiedName, null, callSignature, access); } Debug.Assert(IsStatic == (instance == null)); if (IsStatic) callVirt = false; // never call static method virtually ILEmitter il = codeGenerator.IL; bool args_aware = (Properties & RoutineProperties.IsArgsAware) != 0; var constructedType = type as ConstructedType; // load the instance reference if we have one: // Just here we need RealObject if possible. When calling CLR method on $this, // Phalanger has "this.<proxy>" in "codeGenerator.SelfPlace". We need just "this". EmitLoadInstanceUnwrapped(codeGenerator, instance); // arg-full overload may not be present in the case of classes declared Class Library where // we do not require the user to specify both overloads if (args_aware || ArgFullInfo == null) { // args-aware routines // Debug.Assert(callVirt == false, "Cannot call ArgLess stub virtually!"); // all arg-less stubs have the 'instance' parameter if (instance == null) il.Emit(OpCodes.Ldnull); // emits load of parameters to the PHP stack: callSignature.EmitLoadOnPhpStack(codeGenerator); // CALL <routine>(context.Stack) codeGenerator.EmitLoadScriptContext(); il.Emit(OpCodes.Ldfld, Fields.ScriptContext_Stack); if (this.UsesLateStaticBinding) { // <stack>.LateStaticBindType = <type> il.Emit(OpCodes.Dup); type.EmitLoadTypeDesc(codeGenerator, ResolveTypeFlags.None); il.Emit(OpCodes.Stfld, Fields.PhpStack_LateStaticBindType); } il.Emit(OpCodes.Call, DType.MakeConstructed(ArgLessInfo, constructedType)); // arg-less overload's return value has to be type-cast to a reference if it returns one: if (signature == null || signature.AliasReturn) codeGenerator.IL.Emit(OpCodes.Castclass, typeof(PhpReference)); } else { // args-unaware routines // // CALL <routine>(context, <argumens>) codeGenerator.EmitLoadScriptContext(); callSignature.EmitLoadOnEvalStack(codeGenerator, this); il.Emit(callVirt ? OpCodes.Callvirt : OpCodes.Call, DType.MakeConstructed(ArgFullInfo, constructedType)); } // marks transient sequence point just after the call: codeGenerator.MarkTransientSequencePoint(); return ((signature == null || signature.AliasReturn) ? PhpTypeCode.PhpReference : PhpTypeCode.Object); }