/*! Returns true if the function was called as a constructor (e.g. \c{"new foo()"}); otherwise returns false. When a function is called as constructor, the thisObject() contains the newly constructed object to be initialized. \note This function is only guaranteed to work for a context corresponding to native functions. */ bool QScriptContext::isCalledAsConstructor() const { JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this)); QScript::APIShim shim(QScript::scriptEngineFromExec(frame)); //For native functions, look up flags. uint flags = QScriptEnginePrivate::contextFlags(frame); if (flags & QScriptEnginePrivate::NativeContext) return flags & QScriptEnginePrivate::CalledAsConstructorContext; //Not a native function, try to look up in the bytecode if we where called from op_construct JSC::Instruction* returnPC = frame->returnPC(); if (!returnPC) return false; JSC::CallFrame *callerFrame = QScriptEnginePrivate::frameForContext(parentContext()); if (!callerFrame) return false; if (returnPC[-JSC::op_construct_length].u.opcode == frame->interpreter()->getOpcode(JSC::op_construct)) { //We are maybe called from the op_construct opcode which has 6 opperands. //But we need to check we are not called from op_call with 4 opperands //we make sure that the returnPC[-1] (thisRegister) is smaller than the returnPC[-3] (registerOffset) //as if it was an op_call, the returnPC[-1] would be the registerOffset, bigger than returnPC[-3] (funcRegister) return returnPC[-1].u.operand < returnPC[-3].u.operand; } return false; }
/*! Returns the arguments object of this QScriptContext. The arguments object has properties \c callee (equal to callee()) and \c length (equal to argumentCount()), and properties \c 0, \c 1, ..., argumentCount() - 1 that provide access to the argument values. Initially, property \c P (0 <= \c P < argumentCount()) has the same value as argument(\c P). In the case when \c P is less than the number of formal parameters of the function, \c P shares its value with the corresponding property of the activation object (activationObject()). This means that changing this property changes the corresponding property of the activation object and vice versa. \sa argument(), activationObject() */ QScriptValue QScriptContext::argumentsObject() const { JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this)); QScript::APIShim shim(QScript::scriptEngineFromExec(frame)); if (frame == frame->lexicalGlobalObject()->globalExec()) { // <global> context doesn't have arguments. return an empty object return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame))->newObject(); } //for a js function if (frame->codeBlock() && frame->callee()) { if (!QScriptEnginePrivate::hasValidCodeBlockRegister(frame)) { // We have a built-in JS host call. // codeBlock is needed by retrieveArguments(), but since it // contains junk, we would crash. Return an invalid value for now. return QScriptValue(); } JSC::JSValue result = frame->interpreter()->retrieveArguments(frame, JSC::asFunction(frame->callee())); return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result); } if (frame->callerFrame()->hasHostCallFrameFlag()) { // <eval> context doesn't have arguments. return an empty object return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame))->newObject(); } //for a native function if (!frame->optionalCalleeArguments() && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)) { // Make sure we don't go here for host JSFunctions Q_ASSERT(frame->argumentCount() > 0); //we need at least 'this' otherwise we'll crash later JSC::Arguments* arguments = new (&frame->globalData())JSC::Arguments(frame, JSC::Arguments::NoParameters); frame->setCalleeArguments(arguments); } return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(frame->optionalCalleeArguments()); }