diff options
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/interpreter/Interpreter.cpp | 14 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/runtime/CallData.cpp | 27 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/runtime/ConstructData.cpp | 39 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/runtime/PropertySlot.cpp | 23 | ||||
-rw-r--r-- | src/script/api/qscriptengine.cpp | 100 | ||||
-rw-r--r-- | src/script/api/qscriptengine_p.h | 22 | ||||
-rw-r--r-- | src/script/api/qscriptvalue.cpp | 1 | ||||
-rw-r--r-- | src/script/bridge/qscriptclassobject.cpp | 24 | ||||
-rw-r--r-- | src/script/bridge/qscriptfunction.cpp | 61 | ||||
-rw-r--r-- | src/script/bridge/qscriptqobject.cpp | 11 | ||||
-rw-r--r-- | tests/auto/qscriptengine/tst_qscriptengine.cpp | 11 |
11 files changed, 142 insertions, 191 deletions
diff --git a/src/3rdparty/webkit/JavaScriptCore/interpreter/Interpreter.cpp b/src/3rdparty/webkit/JavaScriptCore/interpreter/Interpreter.cpp index fe663ae..c78466e 100644 --- a/src/3rdparty/webkit/JavaScriptCore/interpreter/Interpreter.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/interpreter/Interpreter.cpp @@ -3507,20 +3507,6 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ScopeChainNode* scopeChain = callFrame->scopeChain(); - Structure* structure; - JSValue prototype = callFrame->r(proto).jsValue(); - if (prototype.isObject()) - structure = asObject(prototype)->inheritorID(); - else - structure = scopeChain->globalObject()->emptyObjectStructure(); -#ifdef QT_BUILD_SCRIPT_LIB - // ### world-class hack - QScriptObject* newObject = new (globalData) QScriptObject(structure); -#else - JSObject* newObject = new (globalData) JSObject(structure); -#endif - callFrame[thisRegister] = JSValue(newObject); // "this" value - CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, asObject(v)); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/CallData.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/CallData.cpp index b33c8ba..c89ebf8 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/CallData.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/CallData.cpp @@ -25,10 +25,6 @@ #include "config.h" #include "CallData.h" -#ifdef QT_BUILD_SCRIPT_LIB -#include "ExceptionHelpers.h" -#include "Interpreter.h" -#endif #include "JSFunction.h" #include "JSGlobalObject.h" @@ -59,29 +55,8 @@ JSValue JSC::NativeFuncWrapper::operator() (ExecState* exec, JSObject* jsobj, JS JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args) { - if (callType == CallTypeHost) { -#ifdef QT_BUILD_SCRIPT_LIB - ScopeChainNode* scopeChain = exec->scopeChain(); - Interpreter *interp = exec->interpreter(); - Register *oldEnd = interp->registerFile().end(); - int argc = 1 + args.size(); // implicit "this" parameter - if (!interp->registerFile().grow(oldEnd + argc + RegisterFile::CallFrameHeaderSize)) - return createStackOverflowError(exec); - CallFrame* newCallFrame = CallFrame::create(oldEnd); - newCallFrame[0] = thisValue; - size_t dst = 0; - ArgList::const_iterator it; - for (it = args.begin(); it != args.end(); ++it) - newCallFrame[++dst] = *it; - newCallFrame += argc + RegisterFile::CallFrameHeaderSize; - newCallFrame->init(0, /*vPC=*/0, scopeChain, exec, 0, argc, asObject(functionObject)); - JSValue result = callData.native.function(newCallFrame, asObject(functionObject), thisValue, args); - interp->registerFile().shrink(oldEnd); - return result; -#else + if (callType == CallTypeHost) return callData.native.function(exec, asObject(functionObject), thisValue, args); -#endif - } ASSERT(callType == CallTypeJS); // FIXME: Can this be done more efficiently using the callData? return asFunction(functionObject)->call(exec, thisValue, args); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/ConstructData.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/ConstructData.cpp index 5fe792f..d4eb307 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/ConstructData.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/ConstructData.cpp @@ -25,12 +25,6 @@ #include "config.h" #include "ConstructData.h" -#ifdef QT_BUILD_SCRIPT_LIB -#include "ExceptionHelpers.h" -#include "Interpreter.h" -#include "JSGlobalObject.h" -#include "bridge/qscriptobject_p.h" -#endif #include "JSFunction.h" @@ -60,39 +54,8 @@ JSObject* JSC::NativeConstrWrapper::operator() (ExecState* exec, JSObject* jsobj JSObject* construct(ExecState* exec, JSValue callee, ConstructType constructType, const ConstructData& constructData, const ArgList& args) { - if (constructType == ConstructTypeHost) { -#ifdef QT_BUILD_SCRIPT_LIB - Structure* structure; - JSValue prototype = callee.get(exec, exec->propertyNames().prototype); - if (prototype.isObject()) - structure = asObject(prototype)->inheritorID(); - else - structure = exec->lexicalGlobalObject()->emptyObjectStructure(); - JSObject* thisObj = new (exec) QScriptObject(structure); - - ScopeChainNode* scopeChain = exec->scopeChain(); - Interpreter *interp = exec->interpreter(); - Register *oldEnd = interp->registerFile().end(); - int argc = 1 + args.size(); // implicit "this" parameter - if (!interp->registerFile().grow(oldEnd + argc + RegisterFile::CallFrameHeaderSize)) - return asObject(createStackOverflowError(exec)); - CallFrame* newCallFrame = CallFrame::create(oldEnd); - size_t dst = 0; - newCallFrame[0] = JSValue(thisObj); - ArgList::const_iterator it; - for (it = args.begin(); it != args.end(); ++it) - newCallFrame[++dst] = *it; - newCallFrame += argc + RegisterFile::CallFrameHeaderSize; - newCallFrame->init(0, /*vPC=*/0, scopeChain, exec, 0, argc, asObject(callee)); - JSObject *result = constructData.native.function(newCallFrame, asObject(callee), args); - if (!result) - result = thisObj; - interp->registerFile().shrink(oldEnd); - return result; -#else + if (constructType == ConstructTypeHost) return constructData.native.function(exec, asObject(callee), args); -#endif - } ASSERT(constructType == ConstructTypeJS); // FIXME: Can this be done more efficiently using the constructData? return asFunction(callee)->construct(exec, args); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/PropertySlot.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/PropertySlot.cpp index 08f50b4..36fa5d8 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/PropertySlot.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/PropertySlot.cpp @@ -19,10 +19,6 @@ */ #include "config.h" -#ifdef QT_BUILD_SCRIPT_LIB -#include "ExceptionHelpers.h" -#include "Interpreter.h" -#endif #include "PropertySlot.h" #include "JSFunction.h" @@ -39,25 +35,8 @@ JSValue PropertySlot::functionGetter(ExecState* exec, const Identifier&, const P CallData callData; CallType callType = slot.m_data.getterFunc->getCallData(callData); - if (callType == CallTypeHost) { -#ifdef QT_BUILD_SCRIPT_LIB - ScopeChainNode* scopeChain = exec->scopeChain(); - Interpreter *interp = exec->interpreter(); - Register *oldEnd = interp->registerFile().end(); - int argc = 1; // implicit "this" parameter - if (!interp->registerFile().grow(oldEnd + argc + RegisterFile::CallFrameHeaderSize)) - return createStackOverflowError(exec); - JSC::CallFrame* newCallFrame = JSC::CallFrame::create(oldEnd); - newCallFrame[0] = slot.slotBase(); // this - newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize; - newCallFrame->init(0, /*vPC=*/0, scopeChain, exec, 0, argc, slot.m_data.getterFunc); - JSValue result = callData.native.function(newCallFrame, slot.m_data.getterFunc, slot.slotBase(), exec->emptyList()); - interp->registerFile().shrink(oldEnd); - return result; -#else + if (callType == CallTypeHost) return callData.native.function(exec, slot.m_data.getterFunc, slot.slotBase(), exec->emptyList()); -#endif - } ASSERT(callType == CallTypeJS); // FIXME: Can this be done more efficiently using the callData? return static_cast<JSFunction*>(slot.m_data.getterFunc)->call(exec, slot.slotBase(), exec->emptyList()); diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index f59cd99..a0ca6b0 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -797,24 +797,6 @@ static QScriptValue __setupPackage__(QScriptContext *ctx, QScriptEngine *eng) } #endif -QScriptPushScopeHelper::QScriptPushScopeHelper(JSC::CallFrame *exec, bool calledAsConstructor) -{ - engine = scriptEngineFromExec(exec); - previousFrame = engine->currentFrame; - engine->currentFrame = exec; - QScriptActivationObject *scope = new (exec) QScriptActivationObject(exec); - scope->d_ptr()->calledAsConstructor = calledAsConstructor; - exec->setScopeChain(exec->scopeChain()->copy()->push(scope)); -} - -QScriptPushScopeHelper::~QScriptPushScopeHelper() -{ - JSC::CallFrame *exec = engine->currentFrame; - exec->setScopeChain(exec->scopeChain()->pop()); - exec->scopeChain()->deref(); - engine->currentFrame = previousFrame; -} - } // namespace QScript QScriptEnginePrivate::QScriptEnginePrivate() : idGenerator(1) @@ -2269,26 +2251,55 @@ QScriptContext *QScriptEngine::currentContext() const QScriptContext *QScriptEngine::pushContext() { Q_D(QScriptEngine); - const int argCount = 1; // for 'this' - JSC::RegisterFile ®isterFile = d->currentFrame->interpreter()->registerFile(); - JSC::Register *const newEnd = registerFile.end() + JSC::RegisterFile::CallFrameHeaderSize + argCount; - if (!registerFile.grow(newEnd)) - return 0; - JSC::CallFrame* previousFrame = d->currentFrame; - JSC::JSObject* scope = new (d->currentFrame) QScript::QScriptActivationObject(d->currentFrame); + JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, d->currentFrame->globalData().dynamicGlobalObject, + JSC::ArgList(), /*callee = */0); - d->currentFrame = JSC::CallFrame::create(newEnd); - d->currentFrame->init(0, 0, previousFrame->scopeChain()->copy()->push(scope), - previousFrame, 0, argCount, 0); - QScriptContext *ctx = d->contextForFrame(d->currentFrame); - ctx->setThisObject(globalObject()); - if (agent()) agent()->contextPush(); - return ctx; + + return d->contextForFrame(newFrame); } +/*! \internal + push a context for a native function. + JSC native function doesn't have different stackframe or context. so we need to create one. + + use popContext right after to go back to the previous context the context if no stack overflow has hapenned + + exec is the current top frame. + + return the new top frame. (might be the same as exec if a new stackframe was not needed) or 0 if stack overflow +*/ +JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, const JSC::JSValue &thisObject, + const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor) +{ + 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. + JSC::Interpreter *interp = exec->interpreter(); + JSC::Register *oldEnd = interp->registerFile().end(); + int argc = args.size() + 1; //add "this" + JSC::Register *newEnd = oldEnd + argc + JSC::RegisterFile::CallFrameHeaderSize; + if (!interp->registerFile().grow(newEnd)) + return 0; //### Stack overflow + newCallFrame = JSC::CallFrame::create(oldEnd); + newCallFrame[0] = thisObject; + int dst = 0; + JSC::ArgList::const_iterator it; + 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); + } + currentFrame = newCallFrame; + QScript::QScriptActivationObject *scope = new (newCallFrame) QScript::QScriptActivationObject(newCallFrame); + scope->d_ptr()->calledAsConstructor = calledAsConstructor; + newCallFrame->setScopeChain(newCallFrame->scopeChain()->copy()->push(scope)); + return newCallFrame; +} + + /*! Pops the current execution context and restores the previous one. This function must be used in conjunction with pushContext(). @@ -2305,11 +2316,26 @@ void QScriptEngine::popContext() qWarning("QScriptEngine::popContext() doesn't match with pushContext()"); return; } - JSC::RegisterFile ®isterFile = d->currentFrame->interpreter()->registerFile(); - JSC::Register *const newEnd = d->currentFrame->registers() - JSC::RegisterFile::CallFrameHeaderSize - d->currentFrame->argumentCount(); - d->currentFrame->scopeChain()->pop()->deref(); - d->currentFrame = d->currentFrame->callerFrame(); - registerFile.shrink(newEnd); + + d->popContext(); +} + +/*! \internal + counter part of QScriptEnginePrivate::pushContext + */ +void QScriptEnginePrivate::popContext() +{ + 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(); + currentFrame = currentFrame->callerFrame(); + registerFile.shrink(newEnd); + } else { //the stack frame was created by the Interpreter, we don't need to rewind it. + currentFrame->setScopeChain(currentFrame->scopeChain()->pop()); + currentFrame->scopeChain()->deref(); + } + } /*! diff --git a/src/script/api/qscriptengine_p.h b/src/script/api/qscriptengine_p.h index 1506e7e..572f361 100644 --- a/src/script/api/qscriptengine_p.h +++ b/src/script/api/qscriptengine_p.h @@ -157,6 +157,10 @@ public: JSC::JSValue toUsableValue(JSC::JSValue value); static JSC::JSValue thisForContext(JSC::ExecState *frame); + JSC::CallFrame *pushContext(JSC::CallFrame *exec, const JSC::JSValue &thisObject, const JSC::ArgList& args, + JSC::JSObject *callee, bool calledAsConstructor = false); + void popContext(); + void mark(); bool isCollecting() const; void collectGarbage(); @@ -246,24 +250,6 @@ public: #endif }; -namespace QScript -{ -/*! \internal - Helper class to create QScriptActivationObject. - To be used on the stack -*/ -class QScriptPushScopeHelper -{ - public: - QScriptPushScopeHelper(JSC::CallFrame *newFrame, bool calledAsConstructor = false); - ~QScriptPushScopeHelper(); - private: - QScriptEnginePrivate *engine; - JSC::CallFrame *previousFrame; -}; -} // namespace QScript - - QT_END_NAMESPACE #endif diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index 9bf4ff2..aa0e8cb 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -889,7 +889,6 @@ void QScriptValue::setPrototype(const QScriptValue &prototype) } nextPrototypeValue = nextPrototype->prototype(); } - JSC::asObject(d->jscValue)->setPrototype(other); } diff --git a/src/script/bridge/qscriptclassobject.cpp b/src/script/bridge/qscriptclassobject.cpp index 50547e81..3a41dae 100644 --- a/src/script/bridge/qscriptclassobject.cpp +++ b/src/script/bridge/qscriptclassobject.cpp @@ -214,14 +214,16 @@ JSC::JSValue JSC_HOST_CALL ClassObjectDelegate::call(JSC::ExecState *exec, JSC:: if (!delegate || (delegate->type() != QScriptObjectDelegate::ClassObject)) return JSC::throwError(exec, JSC::TypeError, "callee is not a ClassObject object"); - //We might have nested eval inside our function so we should create another scope - QScriptPushScopeHelper scope(exec, true); - QScriptClass *scriptClass = static_cast<ClassObjectDelegate*>(delegate)->scriptClass(); QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec); - QScriptContext *ctx = eng_p->contextForFrame(exec); + + JSC::ExecState *oldFrame = eng_p->currentFrame; + eng_p->pushContext(exec, thisValue, args, callee); + QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame); QScriptValue scriptObject = eng_p->scriptValueFromJSCValue(obj); QVariant result = scriptClass->extension(QScriptClass::Callable, qVariantFromValue(ctx)); + eng_p->popContext(); + eng_p->currentFrame = oldFrame; return eng_p->jscValueFromVariant(result); } @@ -241,11 +243,19 @@ JSC::JSObject* ClassObjectDelegate::construct(JSC::ExecState *exec, JSC::JSObjec QScriptObjectDelegate *delegate = obj->delegate(); QScriptClass *scriptClass = static_cast<ClassObjectDelegate*>(delegate)->scriptClass(); - //We might have nested eval inside our function so we should create another scope - QScriptPushScopeHelper scope(exec, true); + JSC::Structure* structure; + JSC::JSValue prototype = JSC::asObject(callee)->get(exec, exec->propertyNames().prototype); + if (prototype.isObject()) + structure = JSC::asObject(prototype)->inheritorID(); + else + structure = exec->lexicalGlobalObject()->emptyObjectStructure(); + JSC::JSObject* thisObject = new (exec) QScriptObject(structure); QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec); - QScriptContext *ctx = eng_p->contextForFrame(exec); + JSC::ExecState *oldFrame = eng_p->currentFrame; + eng_p->pushContext(exec, thisObject, args, callee, true); + QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame); + QScriptValue defaultObject = ctx->thisObject(); QScriptValue result = qvariant_cast<QScriptValue>(scriptClass->extension(QScriptClass::Callable, qVariantFromValue(ctx))); if (!result.isObject()) diff --git a/src/script/bridge/qscriptfunction.cpp b/src/script/bridge/qscriptfunction.cpp index 2124128..f3880b4 100644 --- a/src/script/bridge/qscriptfunction.cpp +++ b/src/script/bridge/qscriptfunction.cpp @@ -46,12 +46,12 @@ #include "private/qscriptcontext_p.h" #include "private/qscriptvalue_p.h" #include "qscriptactivationobject_p.h" +#include "qscriptobject_p.h" #include "JSGlobalObject.h" #include "DebuggerCallFrame.h" #include "Debugger.h" - namespace JSC { ASSERT_CLASS_FITS_IN_CELL(QScript::FunctionWrapper); @@ -91,29 +91,38 @@ JSC::JSValue FunctionWrapper::proxyCall(JSC::ExecState *exec, JSC::JSObject *cal { FunctionWrapper *self = static_cast<FunctionWrapper*>(callee); QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec); - QScriptContext *ctx = eng_p->contextForFrame(exec); - //We might have nested eval inside our function so we should create another scope - QScriptPushScopeHelper scope(exec); + JSC::ExecState *oldFrame = eng_p->currentFrame; + eng_p->pushContext(exec, thisObject, args, callee); + QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame); QScriptValue result = self->data->function(ctx, QScriptEnginePrivate::get(eng_p)); if (!result.isValid()) result = QScriptValue(QScriptValue::UndefinedValue); + eng_p->popContext(); + eng_p->currentFrame = oldFrame; + return eng_p->scriptValueToJSCValue(result); } JSC::JSObject* FunctionWrapper::proxyConstruct(JSC::ExecState *exec, JSC::JSObject *callee, const JSC::ArgList &args) { + JSC::Structure* structure; + JSC::JSValue prototype = JSC::asObject(callee)->get(exec, exec->propertyNames().prototype); + if (prototype.isObject()) + structure = JSC::asObject(prototype)->inheritorID(); + else + structure = exec->lexicalGlobalObject()->emptyObjectStructure(); + JSC::JSObject* thisObject = new (exec) QScriptObject(structure); + FunctionWrapper *self = static_cast<FunctionWrapper*>(callee); QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec); - QScriptContext *ctx = eng_p->contextForFrame(exec); - - //We might have nested eval inside our function so we should create another scope - QScriptPushScopeHelper scope(exec, true); - QScriptValue defaultObject = ctx->thisObject(); + JSC::ExecState *oldFrame = eng_p->currentFrame; + eng_p->pushContext(exec, thisObject, args, callee, true); + QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame); QScriptValue result = self->data->function(ctx, QScriptEnginePrivate::get(eng_p)); #ifdef QT_BUILD_SCRIPT_LIB @@ -121,7 +130,10 @@ JSC::JSObject* FunctionWrapper::proxyConstruct(JSC::ExecState *exec, JSC::JSObje debugger->functionExit(QScriptValuePrivate::get(result)->jscValue, -1); #endif if (!result.isObject()) - result = defaultObject; + result = ctx->thisObject(); + + eng_p->popContext(); + eng_p->currentFrame = oldFrame; return JSC::asObject(eng_p->scriptValueToJSCValue(result)); } @@ -152,10 +164,14 @@ JSC::JSValue FunctionWithArgWrapper::proxyCall(JSC::ExecState *exec, JSC::JSObje FunctionWithArgWrapper *self = static_cast<FunctionWithArgWrapper*>(callee); QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec); - //We might have nested eval inside our function so we should create another scope - QScriptPushScopeHelper scope(exec); + JSC::ExecState *oldFrame = eng_p->currentFrame; + eng_p->pushContext(exec, thisObject, args, callee); + QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame); + + QScriptValue result = self->data->function(ctx, QScriptEnginePrivate::get(eng_p), self->data->arg); - QScriptValue result = self->data->function(eng_p->contextForFrame(exec), QScriptEnginePrivate::get(eng_p), self->data->arg); + eng_p->popContext(); + eng_p->currentFrame = oldFrame; return eng_p->scriptValueToJSCValue(result); } @@ -163,18 +179,27 @@ JSC::JSValue FunctionWithArgWrapper::proxyCall(JSC::ExecState *exec, JSC::JSObje JSC::JSObject* FunctionWithArgWrapper::proxyConstruct(JSC::ExecState *exec, JSC::JSObject *callee, const JSC::ArgList &args) { + JSC::Structure* structure; + JSC::JSValue prototype = JSC::asObject(callee)->get(exec, exec->propertyNames().prototype); + if (prototype.isObject()) + structure = JSC::asObject(prototype)->inheritorID(); + else + structure = exec->lexicalGlobalObject()->emptyObjectStructure(); + JSC::JSObject* thisObject = new (exec) QScriptObject(structure); + FunctionWithArgWrapper *self = static_cast<FunctionWithArgWrapper*>(callee); QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec); - QScriptContext *ctx = eng_p->contextForFrame(exec); - //We might have nested eval inside our function so we should create another scope - QScriptPushScopeHelper scope(exec, true); + JSC::ExecState *oldFrame = eng_p->currentFrame; + eng_p->pushContext(exec, thisObject, args, callee, true); + QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame); - QScriptValue defaultObject = ctx->thisObject(); QScriptValue result = self->data->function(ctx, QScriptEnginePrivate::get(eng_p) , self->data->arg); if (!result.isObject()) - result = defaultObject; + result = ctx->thisObject(); + eng_p->popContext(); + eng_p->currentFrame = oldFrame; return JSC::asObject(eng_p->scriptValueToJSCValue(result)); } diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp index 69ae205..a15e632 100644 --- a/src/script/bridge/qscriptqobject.cpp +++ b/src/script/bridge/qscriptqobject.cpp @@ -1837,8 +1837,9 @@ JSC::JSValue JSC_HOST_CALL QMetaObjectWrapperObject::call( return throwError(exec, JSC::TypeError, "callee is not a QMetaObject"); QMetaObjectWrapperObject *self = static_cast<QMetaObjectWrapperObject*>(callee); JSC::ExecState *previousFrame = eng_p->currentFrame; - eng_p->currentFrame = exec; - JSC::JSValue result = self->execute(exec, args, /*calledAsConstructor=*/false); + eng_p->pushContext(exec, thisValue, args, callee); + JSC::JSValue result = self->execute(eng_p->currentFrame, args, /*calledAsConstructor=*/false); + eng_p->popContext(); eng_p->currentFrame = previousFrame; return result; } @@ -1848,8 +1849,9 @@ JSC::JSObject* QMetaObjectWrapperObject::construct(JSC::ExecState *exec, JSC::JS QMetaObjectWrapperObject *self = static_cast<QMetaObjectWrapperObject*>(callee); QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec); JSC::ExecState *previousFrame = eng_p->currentFrame; - eng_p->currentFrame = exec; - JSC::JSValue result = self->execute(exec, args, /*calledAsConstructor=*/true); + eng_p->pushContext(exec, JSC::JSValue(), args, callee, true); + JSC::JSValue result = self->execute(eng_p->currentFrame, args, /*calledAsConstructor=*/true); + eng_p->popContext(); eng_p->currentFrame = previousFrame; if (!result || !result.isObject()) return 0; @@ -1863,7 +1865,6 @@ JSC::JSValue QMetaObjectWrapperObject::execute(JSC::ExecState *exec, if (data->ctor) { QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec); QScriptContext *ctx = eng_p->contextForFrame(exec); - QScriptPushScopeHelper scope(exec, calledAsConstructor); JSC::CallData callData; JSC::CallType callType = data->ctor.getCallData(callData); Q_ASSERT_X(callType == JSC::CallTypeHost, Q_FUNC_INFO, "script constructors not supported"); diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index 5947814..f15ebdf 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -1872,26 +1872,27 @@ static QScriptValue recurse2(QScriptContext *ctx, QScriptEngine *eng) void tst_QScriptEngine::infiniteRecursion() { - QSKIP("Can cause C stack overflow (task 241294)", SkipAll); - + const QString stackOverflowError = QString::fromLatin1("RangeError: Maximum call stack size exceeded."); QScriptEngine eng; { QScriptValue ret = eng.evaluate("function foo() { foo(); }; foo();"); QCOMPARE(ret.isError(), true); - QCOMPARE(ret.toString(), QLatin1String("Error: call stack overflow")); + QCOMPARE(ret.toString(), stackOverflowError); } +#if 0 //The native C++ stack overflow before the JS stack { QScriptValue fun = eng.newFunction(recurse); QScriptValue ret = fun.call(); QCOMPARE(ret.isError(), true); - QCOMPARE(ret.toString(), QLatin1String("Error: call stack overflow")); + QCOMPARE(ret.toString(), stackOverflowError); } { QScriptValue fun = eng.newFunction(recurse2); QScriptValue ret = fun.construct(); QCOMPARE(ret.isError(), true); - QCOMPARE(ret.toString(), QLatin1String("Error: call stack overflow")); + QCOMPARE(ret.toString(), stackOverflowError); } +#endif } struct Bar { |