diff options
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/api/qscriptcontext.cpp | 19 | ||||
-rw-r--r-- | src/script/api/qscriptcontextinfo.cpp | 7 | ||||
-rw-r--r-- | src/script/api/qscriptengine.cpp | 38 | ||||
-rw-r--r-- | src/script/api/qscriptengine_p.h | 18 | ||||
-rw-r--r-- | src/script/api/qscriptvalue.cpp | 5 | ||||
-rw-r--r-- | src/script/bridge/qscriptdeclarativeclass.cpp | 13 | ||||
-rw-r--r-- | src/script/bridge/qscriptdeclarativeclass_p.h | 2 |
7 files changed, 81 insertions, 21 deletions
diff --git a/src/script/api/qscriptcontext.cpp b/src/script/api/qscriptcontext.cpp index 59ea52d..5454df5 100644 --- a/src/script/api/qscriptcontext.cpp +++ b/src/script/api/qscriptcontext.cpp @@ -268,8 +268,14 @@ QScriptValue QScriptContext::argument(int index) const QScriptValue QScriptContext::callee() const { const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this); - QScript::APIShim shim(QScript::scriptEngineFromExec(frame)); - return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(frame->callee()); + QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(frame); + QScript::APIShim shim(eng); + if (frame->callee() == eng->originalGlobalObject()) { + // This is a pushContext()-created context; the callee is a lie. + Q_ASSERT(QScriptEnginePrivate::contextFlags(const_cast<JSC::CallFrame*>(frame)) & QScriptEnginePrivate::NativeContext); + return QScriptValue(); + } + return eng->scriptValueFromJSCValue(frame->callee()); } /*! @@ -299,6 +305,12 @@ QScriptValue QScriptContext::argumentsObject() const //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); } @@ -309,7 +321,8 @@ QScriptValue QScriptContext::argumentsObject() const } //for a native function - if (!frame->optionalCalleeArguments()) { + 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); diff --git a/src/script/api/qscriptcontextinfo.cpp b/src/script/api/qscriptcontextinfo.cpp index db6b2d7..0f9de1d 100644 --- a/src/script/api/qscriptcontextinfo.cpp +++ b/src/script/api/qscriptcontextinfo.cpp @@ -157,7 +157,7 @@ QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *conte JSC::Instruction *returnPC = rewindContext->returnPC(); JSC::CodeBlock *codeBlock = frame->codeBlock(); - if (returnPC && codeBlock) { + if (returnPC && codeBlock && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)) { #if ENABLE(JIT) unsigned bytecodeOffset = codeBlock->getBytecodeIndex(frame, JSC::ReturnAddressPtr(returnPC)); #else @@ -171,7 +171,7 @@ QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *conte // Get the filename and the scriptId: JSC::CodeBlock *codeBlock = frame->codeBlock(); - if (codeBlock) { + if (codeBlock && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)) { JSC::SourceProvider *source = codeBlock->source(); scriptId = source->asID(); fileName = source->url(); @@ -181,7 +181,8 @@ QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *conte 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)) { + if (callee && callee->inherits(&JSC::JSFunction::info) + && !JSC::asFunction(callee)->isHostFunction()) { functionType = QScriptContextInfo::ScriptFunction; JSC::FunctionExecutable *body = JSC::asFunction(callee)->jsExecutable(); functionStartLineNumber = body->lineNo(); diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index 54039c0..160058e 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -858,7 +858,8 @@ JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState *exec, JSC::JSObject*, JS { JSC::ExecState *frame = exec->callerFrame()->removeHostCallFrameFlag(); while (frame) { - if (frame->codeBlock() && frame->codeBlock()->source() + if (frame->codeBlock() && QScriptEnginePrivate::hasValidCodeBlockRegister(frame) + && frame->codeBlock()->source() && !frame->codeBlock()->source()->url().isEmpty()) { context = engine->translationContextFromUrl(frame->codeBlock()->source()->url()); break; @@ -954,8 +955,11 @@ static QScriptValue __setupPackage__(QScriptContext *ctx, QScriptEngine *eng) } // namespace QScript QScriptEnginePrivate::QScriptEnginePrivate() - : registeredScriptValues(0), freeScriptValues(0), freeScriptValuesCount(0), - registeredScriptStrings(0), inEval(false) + : originalGlobalObjectProxy(0), currentFrame(0), + qobjectPrototype(0), qmetaobjectPrototype(0), variantPrototype(0), + activeAgent(0), agentLineNumber(-1), + registeredScriptValues(0), freeScriptValues(0), freeScriptValuesCount(0), + registeredScriptStrings(0), processEventsInterval(-1), inEval(false) { qMetaTypeId<QScriptValue>(); qMetaTypeId<QList<int> >(); @@ -1001,10 +1005,6 @@ QScriptEnginePrivate::QScriptEnginePrivate() currentFrame = exec; - originalGlobalObjectProxy = 0; - activeAgent = 0; - agentLineNumber = -1; - processEventsInterval = -1; cachedTranslationUrl = JSC::UString(); cachedTranslationContext = JSC::UString(); JSC::setCurrentIdentifierTable(oldTable); @@ -1252,10 +1252,12 @@ void QScriptEnginePrivate::mark(JSC::MarkStack& markStack) { Q_Q(QScriptEngine); - markStack.append(originalGlobalObject()); - markStack.append(globalObject()); - if (originalGlobalObjectProxy) - markStack.append(originalGlobalObjectProxy); + if (originalGlobalObject()) { + markStack.append(originalGlobalObject()); + markStack.append(globalObject()); + if (originalGlobalObjectProxy) + markStack.append(originalGlobalObjectProxy); + } if (qobjectPrototype) markStack.append(qobjectPrototype); @@ -1280,7 +1282,7 @@ void QScriptEnginePrivate::mark(JSC::MarkStack& markStack) } } - { + if (q) { QScriptContext *context = q->currentContext(); while (context) { @@ -2726,6 +2728,14 @@ JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSV bool clearScopeChain) { JSC::JSValue thisObject = _thisObject; + if (!callee) { + // callee can't be zero, as this can cause JSC to crash during GC + // marking phase if the context's Arguments object has been created. + // Fake it by using the global object. Note that this is also handled + // in QScriptContext::callee(), as that function should still return + // an invalid value. + callee = originalGlobalObject(); + } if (calledAsConstructor) { //JSC doesn't create default created object for native functions. so we do it JSC::JSValue prototype = callee->get(exec, exec->propertyNames().prototype); @@ -2761,9 +2771,7 @@ JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSV if (!clearScopeChain) { newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee); } else { - JSC::JSObject *jscObject = originalGlobalObject(); - JSC::ScopeChainNode *scn = new JSC::ScopeChainNode(0, jscObject, &exec->globalData(), exec->lexicalGlobalObject(), jscObject); - newCallFrame->init(0, /*vPC=*/0, scn, exec, flags | ShouldRestoreCallFrame, argc, callee); + newCallFrame->init(0, /*vPC=*/0, globalExec()->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee); } } else { setContextFlags(newCallFrame, flags); diff --git a/src/script/api/qscriptengine_p.h b/src/script/api/qscriptengine_p.h index f8144e9..94d195e 100644 --- a/src/script/api/qscriptengine_p.h +++ b/src/script/api/qscriptengine_p.h @@ -56,6 +56,7 @@ #include "Debugger.h" #include "ErrorInstance.h" #include "JSArray.h" +#include "Executable.h" #include "Lexer.h" #include "RefPtr.h" #include "RegExpConstructor.h" @@ -231,6 +232,8 @@ public: static inline JSC::ExecState *frameForContext(QScriptContext *context); static inline const JSC::ExecState *frameForContext(const QScriptContext *context); + static inline bool hasValidCodeBlockRegister(JSC::ExecState *frame); + JSC::JSGlobalObject *originalGlobalObject() const; JSC::JSObject *getOriginalGlobalObjectProxy(); JSC::JSObject *customGlobalObject() const; @@ -862,6 +865,21 @@ inline const JSC::ExecState *QScriptEnginePrivate::frameForContext(const QScript return reinterpret_cast<const JSC::ExecState*>(context); } +inline bool QScriptEnginePrivate::hasValidCodeBlockRegister(JSC::ExecState *frame) +{ +#if ENABLE(JIT) + // Frames created by the VM don't have their CodeBlock register + // initialized. We can detect such frames by checking if the + // callee is a host JSFunction. + JSC::JSObject *callee = frame->callee(); + return !(callee && callee->inherits(&JSC::JSFunction::info) + && JSC::asFunction(callee)->isHostFunction()); +#else + Q_UNUSED(frame); + return true; +#endif +} + inline JSC::ExecState *QScriptEnginePrivate::globalExec() const { return originalGlobalObject()->globalExec(); diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index ac57918..e289636 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -254,6 +254,7 @@ QScriptValue::QScriptValue(QScriptEngine *engine, int val) : d_ptr(new (QScriptEnginePrivate::get(engine))QScriptValuePrivate(QScriptEnginePrivate::get(engine))) { if (engine) { + QScript::APIShim shim(d_ptr->engine); JSC::ExecState *exec = d_ptr->engine->currentFrame; d_ptr->initFrom(JSC::jsNumber(exec, val)); } else @@ -271,6 +272,7 @@ QScriptValue::QScriptValue(QScriptEngine *engine, uint val) : d_ptr(new (QScriptEnginePrivate::get(engine))QScriptValuePrivate(QScriptEnginePrivate::get(engine))) { if (engine) { + QScript::APIShim shim(d_ptr->engine); JSC::ExecState *exec = d_ptr->engine->currentFrame; d_ptr->initFrom(JSC::jsNumber(exec, val)); } else @@ -288,6 +290,7 @@ QScriptValue::QScriptValue(QScriptEngine *engine, qsreal val) : d_ptr(new (QScriptEnginePrivate::get(engine))QScriptValuePrivate(QScriptEnginePrivate::get(engine))) { if (engine) { + QScript::APIShim shim(d_ptr->engine); JSC::ExecState *exec = d_ptr->engine->currentFrame; d_ptr->initFrom(JSC::jsNumber(exec, val)); } else @@ -305,6 +308,7 @@ QScriptValue::QScriptValue(QScriptEngine *engine, const QString &val) : d_ptr(new (QScriptEnginePrivate::get(engine))QScriptValuePrivate(QScriptEnginePrivate::get(engine))) { if (engine) { + QScript::APIShim shim(d_ptr->engine); JSC::ExecState *exec = d_ptr->engine->currentFrame; d_ptr->initFrom(JSC::jsString(exec, val)); } else { @@ -325,6 +329,7 @@ QScriptValue::QScriptValue(QScriptEngine *engine, const char *val) : d_ptr(new (QScriptEnginePrivate::get(engine))QScriptValuePrivate(QScriptEnginePrivate::get(engine))) { if (engine) { + QScript::APIShim shim(d_ptr->engine); JSC::ExecState *exec = d_ptr->engine->currentFrame; d_ptr->initFrom(JSC::jsString(exec, val)); } else { diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index 0dcf1ec..6126b32 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -179,6 +179,11 @@ QScriptDeclarativeClass::PersistentIdentifier::operator=(const PersistentIdentif return *this; } +QString QScriptDeclarativeClass::PersistentIdentifier::toString() const +{ + return ((JSC::Identifier &)d).ustring(); +} + QScriptDeclarativeClass::QScriptDeclarativeClass(QScriptEngine *engine) : d_ptr(new QScriptDeclarativeClassPrivate) { @@ -468,6 +473,14 @@ QString QScriptDeclarativeClass::toString(const Identifier &identifier) return QString((QChar *)r->data(), r->size()); } +bool QScriptDeclarativeClass::startsWithUpper(const Identifier &identifier) +{ + JSC::UString::Rep *r = (JSC::UString::Rep *)identifier; + if (r->size() < 1) + return false; + return QChar::category((ushort)(r->data()[0])) == QChar::Letter_Uppercase; +} + quint32 QScriptDeclarativeClass::toArrayIndex(const Identifier &identifier, bool *ok) { JSC::UString::Rep *r = (JSC::UString::Rep *)identifier; diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h index 25dc396..e4c18f5 100644 --- a/src/script/bridge/qscriptdeclarativeclass_p.h +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -107,6 +107,7 @@ public: PersistentIdentifier(const PersistentIdentifier &other); PersistentIdentifier &operator=(const PersistentIdentifier &other); + QString toString() const; private: friend class QScriptDeclarativeClass; PersistentIdentifier(QScriptEnginePrivate *e) : identifier(0), engine(e), d(0) {} @@ -126,6 +127,7 @@ public: PersistentIdentifier createPersistentIdentifier(const Identifier &); QString toString(const Identifier &); + bool startsWithUpper(const Identifier &); quint32 toArrayIndex(const Identifier &, bool *ok); virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, |