summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/interpreter/Interpreter.cpp14
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/runtime/CallData.cpp27
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/runtime/ConstructData.cpp39
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/runtime/PropertySlot.cpp23
-rw-r--r--src/script/api/qscriptengine.cpp100
-rw-r--r--src/script/api/qscriptengine_p.h22
-rw-r--r--src/script/api/qscriptvalue.cpp1
-rw-r--r--src/script/bridge/qscriptclassobject.cpp24
-rw-r--r--src/script/bridge/qscriptfunction.cpp61
-rw-r--r--src/script/bridge/qscriptqobject.cpp11
-rw-r--r--tests/auto/qscriptengine/tst_qscriptengine.cpp11
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 &registerFile = 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 &registerFile = 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 &registerFile = 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 {