summaryrefslogtreecommitdiffstats
path: root/src/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/script')
-rw-r--r--src/script/api/qscriptcontext.cpp19
-rw-r--r--src/script/api/qscriptcontextinfo.cpp7
-rw-r--r--src/script/api/qscriptengine.cpp38
-rw-r--r--src/script/api/qscriptengine_p.h18
-rw-r--r--src/script/api/qscriptvalue.cpp5
-rw-r--r--src/script/bridge/qscriptdeclarativeclass.cpp13
-rw-r--r--src/script/bridge/qscriptdeclarativeclass_p.h2
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 &,