QScriptValue QScriptContext::activationObject() const { JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this)); QScript::APIShim shim(QScript::scriptEngineFromExec(frame)); JSC::JSObject *result = 0; uint flags = QScriptEnginePrivate::contextFlags(frame); if ((flags & QScriptEnginePrivate::NativeContext) && !(flags & QScriptEnginePrivate::HasScopeContext)) { //For native functions, lazily create it if needed QScript::QScriptActivationObject *scope = new (frame) QScript::QScriptActivationObject(frame); frame->setScopeChain(frame->scopeChain()->copy()->push(scope)); result = scope; QScriptEnginePrivate::setContextFlags(frame, flags | QScriptEnginePrivate::HasScopeContext); } else { // look in scope chain JSC::ScopeChainNode *node = frame->scopeChain(); JSC::ScopeChainIterator it(node); for (it = node->begin(); it != node->end(); ++it) { if ((*it) && (*it)->isVariableObject()) { result = *it; break; } } } if (!result) { if (!parentContext()) return engine()->globalObject(); qWarning("QScriptContext::activationObject: could not get activation object for frame"); return QScriptValue(); /*JSC::CodeBlock *codeBlock = frame->codeBlock(); if (!codeBlock) { // non-Qt native function Q_ASSERT(true); //### this should in theorry not happen result = new (frame)QScript::QScriptActivationObject(frame); } else { // ### this is wrong JSC::FunctionBodyNode *body = static_cast<JSC::FunctionBodyNode*>(codeBlock->ownerNode()); result = new (frame)JSC::JSActivation(frame, body); }*/ } if (result && result->inherits(&QScript::QScriptActivationObject::info) && (static_cast<QScript::QScriptActivationObject*>(result)->delegate() != 0)) { // Return the object that property access is being delegated to result = static_cast<QScript::QScriptActivationObject*>(result)->delegate(); } return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result); }
/* Returns the scope chain entry at \a index. If index is less than 0, returns entries starting at the end. For example, scopeChainValue(context, -1) will return the value last in the scope chain. */ QScriptValue QScriptDeclarativeClass::scopeChainValue(QScriptContext *context, int index) { context->activationObject(); //ensure the creation of the normal scope for native context const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(context); QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame); QScript::APIShim shim(engine); JSC::ScopeChainNode *node = frame->scopeChain(); JSC::ScopeChainIterator it(node); if (index < 0) { int count = 0; for (it = node->begin(); it != node->end(); ++it) ++count; index = qAbs(index); if (index > count) return QScriptValue(); else index = count - index; } for (it = node->begin(); it != node->end(); ++it) { if (index == 0) { JSC::JSObject *object = *it; if (!object) return QScriptValue(); if (object->inherits(&QScript::QScriptActivationObject::info) && (static_cast<QScript::QScriptActivationObject*>(object)->delegate() != 0)) { // Return the object that property access is being delegated to object = static_cast<QScript::QScriptActivationObject*>(object)->delegate(); } return engine->scriptValueFromJSCValue(object); } else { --index; } } return QScriptValue(); }
/*! \internal \since 4.5 Returns the scope chain of this QScriptContext. */ QScriptValueList QScriptContext::scopeChain() const { activationObject(); //ensure the creation of the normal scope for native context const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this); QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame); QScript::APIShim shim(engine); QScriptValueList result; JSC::ScopeChainNode *node = frame->scopeChain(); JSC::ScopeChainIterator it(node); for (it = node->begin(); it != node->end(); ++it) { JSC::JSObject *object = *it; if (!object) continue; if (object->inherits(&QScript::QScriptActivationObject::info) && (static_cast<QScript::QScriptActivationObject*>(object)->delegate() != 0)) { // Return the object that property access is being delegated to object = static_cast<QScript::QScriptActivationObject*>(object)->delegate(); } result.append(engine->scriptValueFromJSCValue(object)); } return result; }
/*! \internal */ QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *context) { Q_ASSERT(context); functionType = QScriptContextInfo::NativeFunction; functionMetaIndex = -1; functionStartLineNumber = -1; functionEndLineNumber = -1; scriptId = -1; lineNumber = -1; columnNumber = -1; JSC::CallFrame *frame = const_cast<JSC::CallFrame *>(QScriptEnginePrivate::frameForContext(context)); // Get the line number: //We need to know the context directly up in the backtrace, in order to get the line number, and adjust the global context JSC::CallFrame *rewindContext = QScriptEnginePrivate::get(context->engine())->currentFrame; if (QScriptEnginePrivate::contextForFrame(rewindContext) == context) { //top context frame = rewindContext; //for retreiving the global context's "fake" frame // An agent might have provided the line number. lineNumber = QScript::scriptEngineFromExec(frame)->agentLineNumber; if (lineNumber == -1) lineNumber = QScript::scriptEngineFromExec(frame)->uncaughtExceptionLineNumber; } else { // rewind the stack from the top in order to find the frame from the caller where the returnPC is stored while (rewindContext && QScriptEnginePrivate::contextForFrame(rewindContext->callerFrame()->removeHostCallFrameFlag()) != context) rewindContext = rewindContext->callerFrame()->removeHostCallFrameFlag(); if (rewindContext) { frame = rewindContext->callerFrame()->removeHostCallFrameFlag(); //for retreiving the global context's "fake" frame JSC::Instruction *returnPC = rewindContext->returnPC(); JSC::CodeBlock *codeBlock = frame->codeBlock(); if (returnPC && codeBlock && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)) { #if ENABLE(JIT) JSC::JITCode code = codeBlock->getJITCode(); uintptr_t jitOffset = reinterpret_cast<uintptr_t>(JSC::ReturnAddressPtr(returnPC).value()) - reinterpret_cast<uintptr_t>(code.addressForCall().executableAddress()); // We can only use the JIT code offset if it's smaller than the JIT size; // otherwise calling getBytecodeIndex() is meaningless. if (jitOffset < code.size()) { unsigned bytecodeOffset = codeBlock->getBytecodeIndex(frame, JSC::ReturnAddressPtr(returnPC)); #else unsigned bytecodeOffset = returnPC - codeBlock->instructions().begin(); #endif bytecodeOffset--; //because returnPC is on the next instruction. We want the current one lineNumber = codeBlock->lineNumberForBytecodeOffset(const_cast<JSC::ExecState *>(frame), bytecodeOffset); #if ENABLE(JIT) } #endif } } } // Get the filename and the scriptId: JSC::CodeBlock *codeBlock = frame->codeBlock(); if (codeBlock && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)) { JSC::SourceProvider *source = codeBlock->source(); scriptId = source->asID(); fileName = source->url(); } // Get the others information: JSC::JSObject *callee = frame->callee(); if (callee && callee->inherits(&JSC::InternalFunction::info)) functionName = JSC::asInternalFunction(callee)->name(frame); if (callee && callee->inherits(&JSC::JSFunction::info) && !JSC::asFunction(callee)->isHostFunction()) { functionType = QScriptContextInfo::ScriptFunction; JSC::FunctionExecutable *body = JSC::asFunction(callee)->jsExecutable(); functionStartLineNumber = body->lineNo(); functionEndLineNumber = body->lastLine(); for (size_t i = 0; i < body->parameterCount(); ++i) parameterNames.append(body->parameterName(i)); // ### get the function name from the AST } else if (callee && callee->inherits(&QScript::QtFunction::info)) { functionType = QScriptContextInfo::QtFunction; functionMetaIndex = static_cast<QScript::QtFunction*>(callee)->specificIndex(context); const QMetaObject *meta = static_cast<QScript::QtFunction*>(callee)->metaObject(); if (meta != 0) { QMetaMethod method = meta->method(functionMetaIndex); QList<QByteArray> formals = method.parameterNames(); for (int i = 0; i < formals.count(); ++i) parameterNames.append(QLatin1String(formals.at(i))); } } else if (callee && callee->inherits(&QScript::QtPropertyFunction::info)) { functionType = QScriptContextInfo::QtPropertyFunction; functionMetaIndex = static_cast<QScript::QtPropertyFunction*>(callee)->propertyIndex(); } }