Example #1
0
        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);
		}