/*!
  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());
}