diff options
author | Olivier Goffart <ogoffart@trolltech.com> | 2009-08-13 08:39:28 (GMT) |
---|---|---|
committer | Olivier Goffart <ogoffart@trolltech.com> | 2009-08-13 13:24:12 (GMT) |
commit | 04ac768f2ac5e3800893370c13c261a075a723ff (patch) | |
tree | a14a6c9580cde04bb962c350b9667d4510e66972 /src/script/api/qscriptengine.cpp | |
parent | 88c6dc6ec7f73de279703b30874b30511901854b (diff) | |
download | Qt-04ac768f2ac5e3800893370c13c261a075a723ff.zip Qt-04ac768f2ac5e3800893370c13c261a075a723ff.tar.gz Qt-04ac768f2ac5e3800893370c13c261a075a723ff.tar.bz2 |
Lazily construct the QScriptActivationObject
We can store flags on the ReturnValueRegister entry in the stackframe
header (as native function don't use that)
Then when requesting an activation object we can lookup the flags to
know if we should create it.
This reduce a lot the cost of a native call.
Reviewed-by: Kent Hansen
Diffstat (limited to 'src/script/api/qscriptengine.cpp')
-rw-r--r-- | src/script/api/qscriptengine.cpp | 54 |
1 files changed, 42 insertions, 12 deletions
diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index e8ea222..daf97d5 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -1114,6 +1114,30 @@ JSC::JSValue QScriptEnginePrivate::thisForContext(JSC::ExecState *frame) } } +/*! \internal + For native context, we use the ReturnValueRegister entry in the stackframe header to store flags. + We can do that because this header is not used as the native function return their value thought C++ + + when setting flags, NativeContext should always be set + + contextFlags returns 0 for non native context + */ +uint QScriptEnginePrivate::contextFlags(JSC::ExecState *exec) +{ + if (exec->codeBlock()) + return 0; //js function doesn't have flags + + return exec->returnValueRegister(); +} + +void QScriptEnginePrivate::setContextFlags(JSC::ExecState *exec, uint flags) +{ + Q_ASSERT(!exec->codeBlock()); + quintptr flag_ptr = flags; + exec->registers()[JSC::RegisterFile::ReturnValueRegister] = JSC::JSValue(reinterpret_cast<JSC::JSObject*>(flag_ptr)); +} + + void QScriptEnginePrivate::mark() { if (!originalGlobalObject()->marked()) @@ -2126,6 +2150,7 @@ QScriptValue QScriptEngine::evaluate(const QString &program, const QString &file Q_D(QScriptEngine); JSC::JSLock lock(false); // ### hmmm + currentContext()->activationObject(); //force the creation of a context for native function; JSC::UString jscProgram = QScript::qtStringToJSCUString(program); JSC::UString jscFileName = QScript::qtStringToJSCUString(fileName); @@ -2269,6 +2294,10 @@ JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, const JS thisObject = new (exec) QScriptObject(structure); } + int flags = NativeContext; + if (calledAsConstructor) + flags |= CalledAsConstructorContext; + JSC::CallFrame *newCallFrame = exec; if (callee == 0 || !(exec->callee() == callee && exec->returnPC() != 0)) { //We need to check if the Interpreter might have already created a frame for function called from JS. @@ -2285,16 +2314,16 @@ JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, const JS for (it = args.begin(); it != args.end(); ++it) newCallFrame[++dst] = *it; newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize; - newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, 0, argc, callee); - } else if (calledAsConstructor) { - //update the new created this - JSC::Register* thisRegister = newCallFrame->registers() - JSC::RegisterFile::CallFrameHeaderSize - newCallFrame->argumentCount(); - *thisRegister = thisObject; + newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags, argc, callee); + } else { + setContextFlags(newCallFrame, flags); + if (calledAsConstructor) { + //update the new created this + JSC::Register* thisRegister = newCallFrame->registers() - JSC::RegisterFile::CallFrameHeaderSize - newCallFrame->argumentCount(); + *thisRegister = thisObject; + } } currentFrame = newCallFrame; - QScript::QScriptActivationObject *scope = new (newCallFrame) QScript::QScriptActivationObject(newCallFrame); - scope->d_ptr()->calledAsConstructor = calledAsConstructor; - newCallFrame->setScopeChain(newCallFrame->scopeChain()->copy()->push(scope)); return newCallFrame; } @@ -2311,7 +2340,7 @@ void QScriptEngine::popContext() agent()->contextPop(); Q_D(QScriptEngine); if (d->currentFrame->returnPC() != 0 || d->currentFrame->codeBlock() != 0 - || d->currentFrame->returnValueRegister() != 0 || !currentContext()->parentContext()) { + || !currentContext()->parentContext()) { qWarning("QScriptEngine::popContext() doesn't match with pushContext()"); return; } @@ -2324,17 +2353,18 @@ void QScriptEngine::popContext() */ void QScriptEnginePrivate::popContext() { + bool hasScope = contextFlags(currentFrame) & HasScopeContext; if (currentFrame->returnPC() == 0) { //normal case JSC::RegisterFile ®isterFile = currentFrame->interpreter()->registerFile(); JSC::Register *const newEnd = currentFrame->registers() - JSC::RegisterFile::CallFrameHeaderSize - currentFrame->argumentCount(); - currentFrame->scopeChain()->pop()->deref(); + if (hasScope) + currentFrame->scopeChain()->pop()->deref(); currentFrame = currentFrame->callerFrame(); registerFile.shrink(newEnd); - } else { //the stack frame was created by the Interpreter, we don't need to rewind it. + } else if(hasScope) { //the stack frame was created by the Interpreter, we don't need to rewind it. currentFrame->setScopeChain(currentFrame->scopeChain()->pop()); currentFrame->scopeChain()->deref(); } - } /*! |