aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4engine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4engine.cpp')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp189
1 files changed, 66 insertions, 123 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 8ca6b03950..d10fd78973 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -81,14 +81,6 @@
#include <QtCore/QTextStream>
#include <QDateTime>
-#ifdef V4_ENABLE_JIT
-#include "qv4isel_masm_p.h"
-#endif // V4_ENABLE_JIT
-
-#if QT_CONFIG(qml_interpreter)
-#include "qv4isel_moth_p.h"
-#endif
-
#if USE(PTHREADS)
# include <pthread.h>
#if !defined(Q_OS_INTEGRITY)
@@ -109,9 +101,9 @@ using namespace QV4;
static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
-void throwTypeError(const BuiltinFunction *, Scope &scope, CallData *)
+ReturnedValue throwTypeError(const BuiltinFunction *b, CallData *)
{
- scope.result = scope.engine->throwTypeError();
+ return b->engine()->throwTypeError();
}
@@ -129,7 +121,7 @@ QQmlEngine *ExecutionEngine::qmlEngine() const
qint32 ExecutionEngine::maxCallDepth = -1;
-ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
+ExecutionEngine::ExecutionEngine()
: executableAllocator(new QV4::ExecutableAllocator)
, regExpAllocator(new QV4::ExecutableAllocator)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
@@ -153,38 +145,15 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
bool ok = false;
maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
if (!ok || maxCallDepth <= 0) {
+#ifdef QT_NO_DEBUG
maxCallDepth = 1234;
- }
- }
- Q_ASSERT(maxCallDepth > 0);
-
- if (!factory) {
-#if QT_CONFIG(qml_interpreter)
- bool jitDisabled = true;
-
-#ifdef V4_ENABLE_JIT
- static const bool forceMoth = !qEnvironmentVariableIsEmpty("QV4_FORCE_INTERPRETER") ||
- !OSAllocator::canAllocateExecutableMemory();
- if (forceMoth) {
- factory = new Moth::ISelFactory;
- } else {
- factory = new JIT::ISelFactory<>;
- jitDisabled = false;
- }
-#else // !V4_ENABLE_JIT
- factory = new Moth::ISelFactory;
-#endif // V4_ENABLE_JIT
-
- if (jitDisabled) {
- qWarning("JIT is disabled for QML. Property bindings and animations will be "
- "very slow. Visit https://wiki.qt.io/V4 to learn about possible "
- "solutions for your platform.");
- }
#else
- factory = new JIT::ISelFactory<>;
+ // no (tail call) optimization is done, so there'll be a lot mare stack frames active
+ maxCallDepth = 200;
#endif
+ }
}
- iselFactory.reset(factory);
+ Q_ASSERT(maxCallDepth > 0);
// reserve space for the JS stack
// we allow it to grow to a bit more than JSStackLimit, as we can overshoot due to ScopedValues
@@ -223,7 +192,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable());
internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable());
- internalClasses[Class_SimpleCallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
+ internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
jsStrings[String_Empty] = newIdentifier(QString());
jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
@@ -429,8 +398,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
//
// set up the global object
//
- rootContext()->d()->global.set(scope.engine, globalObject->d());
- rootContext()->d()->callData->thisObject = globalObject;
+ rootContext()->d()->activation.set(scope.engine, globalObject->d());
Q_ASSERT(globalObject->d()->vtable());
globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor());
@@ -547,19 +515,11 @@ void ExecutionEngine::setProfiler(Profiling::Profiler *profiler)
void ExecutionEngine::initRootContext()
{
Scope scope(this);
- Scoped<GlobalContext> r(scope, memoryManager->allocManaged<GlobalContext>(
- sizeof(GlobalContext::Data) + sizeof(CallData)));
- r->d_unchecked()->init(this);
- r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1);
- r->d()->callData->tag = quint32(Value::ValueTypeInternal::Integer);
- r->d()->callData->argc = 0;
- r->d()->callData->thisObject = globalObject;
- r->d()->callData->args[0] = Encode::undefined();
+ Scoped<ExecutionContext> r(scope, memoryManager->allocManaged<ExecutionContext>(sizeof(ExecutionContext::Data)));
+ r->d_unchecked()->init(Heap::ExecutionContext::Type_GlobalContext);
+ r->d()->activation.set(this, globalObject->d());
jsObjects[RootContext] = r;
jsObjects[IntegerNull] = Encode((int)0);
-
- currentContext = static_cast<ExecutionContext *>(jsObjects + RootContext);
- current = currentContext->d();
}
InternalClass *ExecutionEngine::newClass(const InternalClass &other)
@@ -567,14 +527,6 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other)
return new (classPool) InternalClass(other);
}
-ExecutionContext *ExecutionEngine::pushGlobalContext()
-{
- pushContext(rootContext()->d());
-
- Q_ASSERT(current == rootContext()->d());
- return currentContext;
-}
-
InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype)
{
return internalClasses[EngineBase::Class_Empty]->changeVTable(vtable)->changePrototype(prototype ? prototype->d() : 0);
@@ -697,12 +649,12 @@ Heap::DateObject *ExecutionEngine::newDateObjectFromTime(const QTime &t)
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
{
- bool global = (flags & IR::RegExp::RegExp_Global);
+ bool global = (flags & QV4::CompiledData::RegExp::RegExp_Global);
bool ignoreCase = false;
bool multiline = false;
- if (flags & IR::RegExp::RegExp_IgnoreCase)
+ if (flags & QV4::CompiledData::RegExp::RegExp_IgnoreCase)
ignoreCase = true;
- if (flags & IR::RegExp::RegExp_Multiline)
+ if (flags & QV4::CompiledData::RegExp::RegExp_Multiline)
multiline = true;
Scope scope(this);
@@ -776,11 +728,9 @@ Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o)
Heap::QmlContext *ExecutionEngine::qmlContext() const
{
- Heap::ExecutionContext *ctx = current;
-
- // get the correct context when we're within a builtin function
- if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer)
- ctx = parentContext(currentContext)->d();
+ if (!currentStackFrame)
+ return 0;
+ Heap::ExecutionContext *ctx = currentContext()->d();
if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer)
return 0;
@@ -801,7 +751,7 @@ QObject *ExecutionEngine::qmlScopeObject() const
if (!ctx)
return 0;
- return ctx->qml->scopeObject;
+ return ctx->qml()->scopeObject;
}
ReturnedValue ExecutionEngine::qmlSingletonWrapper(String *name)
@@ -831,57 +781,56 @@ QQmlContextData *ExecutionEngine::callingQmlContext() const
if (!ctx)
return 0;
- return ctx->qml->context->contextData();
+ return ctx->qml()->context->contextData();
}
-QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
+QString CppStackFrame::source() const
{
- Scope scope(const_cast<ExecutionEngine *>(this));
- ScopedString name(scope);
- QVector<StackFrame> stack;
-
- ExecutionContext *c = currentContext;
- while (c && frameLimit) {
- QV4::Function *function = c->getFunction();
- if (function) {
- StackFrame frame;
- frame.source = function->sourceFile();
- name = function->name();
- frame.function = name->toQString();
-
- // line numbers can be negative for places where you can't set a real breakpoint
- frame.line = qAbs(c->d()->lineNumber);
- frame.column = -1;
-
- stack.append(frame);
- --frameLimit;
- }
- c = parentContext(c);
- }
-
- if (frameLimit && globalCode) {
- StackFrame frame;
- frame.source = globalCode->sourceFile();
- frame.function = globalCode->name()->toQString();
- frame.line = rootContext()->d()->lineNumber;
- frame.column = -1;
+ return v4Function->sourceFile();
+}
- stack.append(frame);
- }
- return stack;
+QString CppStackFrame::function() const
+{
+ return v4Function->name()->toQString();
}
-StackFrame ExecutionEngine::currentStackFrame() const
+int CppStackFrame::lineNumber() const
{
- StackFrame frame;
- frame.line = -1;
- frame.column = -1;
+ auto findLine = [](const CompiledData::CodeOffsetToLine &entry, uint offset) {
+ return entry.codeOffset < offset;
+ };
+
+ const QV4::CompiledData::Function *cf = v4Function->compiledFunction;
+ uint offset = static_cast<uint>(instructionPointer - v4Function->codeData);
+ const CompiledData::CodeOffsetToLine *lineNumbers = cf->lineNumberTable();
+ uint nLineNumbers = cf->nLineNumbers;
+ const CompiledData::CodeOffsetToLine *line = std::lower_bound(lineNumbers, lineNumbers + nLineNumbers, offset, findLine) - 1;
+ return line->line;
+}
+
+ReturnedValue CppStackFrame::thisObject() const {
+ return jsFrame->thisObject.asReturnedValue();
+}
- QVector<StackFrame> trace = stackTrace(/*limit*/ 1);
- if (!trace.isEmpty())
- frame = trace.first();
+StackTrace ExecutionEngine::stackTrace(int frameLimit) const
+{
+ Scope scope(const_cast<ExecutionEngine *>(this));
+ ScopedString name(scope);
+ StackTrace stack;
+
+ CppStackFrame *f = currentStackFrame;
+ while (f && frameLimit) {
+ QV4::StackFrame frame;
+ frame.source = f->source();
+ frame.function = f->function();
+ frame.line = f->lineNumber();
+ frame.column = -1;
+ stack.append(frame);
+ --frameLimit;
+ f = f->parent;
+ }
- return frame;
+ return stack;
}
/* Helper and "C" linkage exported function to format a GDBMI stacktrace for
@@ -924,14 +873,13 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
return src;
QUrl base;
- ExecutionContext *c = currentContext;
- while (c) {
- SimpleCallContext *callCtx = c->asSimpleCallContext();
- if (callCtx && callCtx->d()->v4Function) {
- base.setUrl(callCtx->d()->v4Function->sourceFile());
+ CppStackFrame *f = currentStackFrame;
+ while (f) {
+ if (f->v4Function) {
+ base.setUrl(f->v4Function->sourceFile());
break;
}
- c = parentContext(c);
+ f = f->parent;
}
if (base.isEmpty() && globalCode)
@@ -1606,11 +1554,6 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
return 0;
}
-void ExecutionEngine::failStackLimitCheck(Scope &scope)
-{
- scope.result = throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
-}
-
// Converts a JS value to a meta-type.
// data must point to a place that can store a value of the given type.
// Returns true if conversion succeeded, false otherwise.