diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2017-11-21 12:29:40 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2017-11-21 12:29:40 +0100 |
commit | d373d5e7d70e968cfba8957596ed6fe4f46990c8 (patch) | |
tree | c52bf2b0fbbfdb13d644b4050aa7a931ef4b7109 /src/qml/jsruntime/qv4vme_moth.cpp | |
parent | 9880acb424fd814501ba5fc4ae1caa989e23fafa (diff) | |
parent | 9af8a47746b69b6040fc149c1d24602a1e25b08f (diff) |
Merge remote-tracking branch 'origin/wip/new-backend' into dev
Conflicts:
src/qml/compiler/qv4isel_moth.cpp
src/qml/compiler/qv4jsir_p.h
src/qml/jsruntime/qv4engine_p.h
src/qml/jsruntime/qv4vme_moth.cpp
tests/auto/qml/qml.pro
Change-Id: Ia7b6ec24c7fcbcbb1786d9e798d2df294020ae37
Diffstat (limited to 'src/qml/jsruntime/qv4vme_moth.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 1436 |
1 files changed, 919 insertions, 517 deletions
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index fdf47e772e..adf43812cf 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -53,19 +53,16 @@ #include <private/qv4regexp_p.h> #include <private/qv4regexpobject_p.h> #include <private/qv4string_p.h> +#include <private/qv4profiling_p.h> +#include <private/qv4jscall_p.h> +#include <private/qqmljavascriptexpression_p.h> #include <iostream> #include "qv4alloca_p.h" -#undef DO_TRACE_INSTR // define to enable instruction tracing +#include <private/qv4jit_p.h> -#ifdef DO_TRACE_INSTR -# define TRACE_INSTR(I) qDebug("executing a %s\n", #I); -# define TRACE(n, str, ...) { char buf[4096]; snprintf(buf, 4096, str, __VA_ARGS__); qDebug(" %s : %s", #n, buf); } -#else -# define TRACE_INSTR(I) -# define TRACE(n, str, ...) -#endif // DO_TRACE_INSTR +#undef COUNT_INSTRUCTIONS extern "C" { @@ -146,7 +143,7 @@ Q_QML_EXPORT int qt_v4DebuggerHook(const char *json); #if QT_CONFIG(qml_debug) static int qt_v4BreakpointCount = 0; -static bool qt_v4IsDebugging = true; +static bool qt_v4IsDebugging = false; static bool qt_v4IsStepping = false; class Breakpoint @@ -169,14 +166,6 @@ public: static QVector<Breakpoint> qt_v4Breakpoints; static Breakpoint qt_v4LastStop; -static QV4::Function *qt_v4ExtractFunction(QV4::ExecutionContext *context) -{ - if (QV4::Function *function = context->getFunction()) - return function; - else - return context->engine()->globalCode; -} - static void qt_v4TriggerBreakpoint(const Breakpoint &bp, QV4::Function *function) { qt_v4LastStop = bp; @@ -223,6 +212,7 @@ int qt_v4DebuggerHook(const char *json) bp.fullName = ob.value(QLatin1String("fullName")).toString(); bp.condition = ob.value(QLatin1String("condition")).toString(); qt_v4Breakpoints.append(bp); + qt_v4IsDebugging = true; return bp.bpNumber; } @@ -231,6 +221,7 @@ int qt_v4DebuggerHook(const char *json) QString fullName = ob.value(QLatin1String("fullName")).toString(); if (qt_v4Breakpoints.last().matches(fullName, lineNumber)) { qt_v4Breakpoints.removeLast(); + qt_v4IsDebugging = !qt_v4Breakpoints.isEmpty(); return Success; } for (int i = 0; i + 1 < qt_v4Breakpoints.size(); ++i) { @@ -251,13 +242,13 @@ int qt_v4DebuggerHook(const char *json) return -NoSuchCommand; // Failure. } -static void qt_v4CheckForBreak(QV4::ExecutionContext *context) +Q_NEVER_INLINE static void qt_v4CheckForBreak(QV4::CppStackFrame *frame) { if (!qt_v4IsStepping && !qt_v4Breakpoints.size()) return; - const int lineNumber = context->d()->lineNumber; - QV4::Function *function = qt_v4ExtractFunction(context); + const int lineNumber = frame->lineNumber(); + QV4::Function *function = frame->v4Function; QString engineName = function->sourceFile(); if (engineName.isEmpty()) @@ -287,74 +278,64 @@ static void qt_v4CheckForBreak(QV4::ExecutionContext *context) } } +Q_NEVER_INLINE static void debug_slowPath(QV4::ExecutionEngine *engine) +{ + QV4::Debugging::Debugger *debugger = engine->debugger(); + if (debugger && debugger->pauseAtNextOpportunity()) + debugger->maybeBreakAtInstruction(); + if (qt_v4IsDebugging) + qt_v4CheckForBreak(engine->currentStackFrame); +} + #endif // QT_CONFIG(qml_debug) // End of debugger interface using namespace QV4; using namespace QV4::Moth; -#define MOTH_BEGIN_INSTR_COMMON(I) { \ - const InstrMeta<(int)Instr::I>::DataType &instr = InstrMeta<(int)Instr::I>::data(*genericInstr); \ - code += InstrMeta<(int)Instr::I>::Size; \ - Q_UNUSED(instr); \ - TRACE_INSTR(I) - -#ifdef MOTH_THREADED_INTERPRETER - -# define MOTH_BEGIN_INSTR(I) op_##I: \ - MOTH_BEGIN_INSTR_COMMON(I) - -# define MOTH_END_INSTR(I) } \ - genericInstr = reinterpret_cast<const Instr *>(code); \ - goto *jumpTable[genericInstr->common.instructionType]; \ - -#else - -# define MOTH_BEGIN_INSTR(I) \ - case Instr::I: \ - MOTH_BEGIN_INSTR_COMMON(I) - -# define MOTH_END_INSTR(I) } \ - continue; - -#endif - -#ifdef DO_TRACE_INSTR -Param traceParam(const Param ¶m) -{ - if (param.isConstant()) { - qDebug(" constant\n"); - } else if (param.isArgument()) { - qDebug(" argument %d@%d\n", param.index, param.scope); - } else if (param.isLocal()) { - qDebug(" local %d\n", param.index); - } else if (param.isTemp()) { - qDebug(" temp %d\n", param.index); - } else if (param.isScopedLocal()) { - qDebug(" temp %d@%d\n", param.index, param.scope); - } else { - Q_ASSERT(!"INVALID"); +#ifdef COUNT_INSTRUCTIONS +static struct InstrCount { + InstrCount() { + fprintf(stderr, "Counting instructions...\n"); + for (int i = 0; i < MOTH_NUM_INSTRUCTIONS(); ++i) + hits[i] = 0; + } + ~InstrCount() { + fprintf(stderr, "Instruction count:\n"); +#define BLAH(I) \ + fprintf(stderr, "%llu : %s\n", hits[int(Instr::Type::I)], #I); + FOR_EACH_MOTH_INSTR(BLAH) + #undef BLAH + } + quint64 hits[MOTH_NUM_INSTRUCTIONS()]; + void hit(Instr::Type i) { hits[int(i)]++; } +} instrCount; +#endif // COUNT_INSTRUCTIONS + +#define MOTH_BEGIN_INSTR_COMMON(instr) \ + { \ + INSTR_##instr(MOTH_DECODE) + +#ifdef COUNT_INSTRUCTIONS +# define MOTH_BEGIN_INSTR(instr) \ + MOTH_BEGIN_INSTR_COMMON(instr) \ + instrCount.hit(Instr::Type::instr); +#else // !COUNT_INSTRUCTIONS +# define MOTH_BEGIN_INSTR(instr) \ + MOTH_BEGIN_INSTR_COMMON(instr) +#endif // COUNT_INSTRUCTIONS + +#ifdef MOTH_COMPUTED_GOTO +#define MOTH_END_INSTR(instr) \ + MOTH_DISPATCH() \ + } +#else // !MOTH_COMPUTED_GOTO +#define MOTH_END_INSTR(instr) \ + continue; \ } - return param; -} -# define VALUE(param) (*VALUEPTR(param)) -# define VALUEPTR(param) (scopes[traceParam(param).scope].values + param.index) -#else -# define VALUE(param) (*VALUEPTR(param)) -# define VALUEPTR(param) (scopes[param.scope].values + param.index) #endif -// ### add write barrier here -#define STOREVALUE(param, value) { \ - QV4::ReturnedValue tmp = (value); \ - if (engine->hasException) \ - goto catchException; \ - if (Q_LIKELY(!engine->writeBarrierActive || !scopes[param.scope].base)) { \ - VALUE(param) = tmp; \ - } else { \ - QV4::WriteBarrier::write(engine, scopes[param.scope].base, VALUEPTR(param), QV4::Value::fromReturnedValue(tmp)); \ - } \ -} +#define STACK_VALUE(temp) stack[temp] // qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro #ifdef CHECK_EXCEPTION @@ -364,617 +345,1038 @@ Param traceParam(const Param ¶m) if (engine->hasException) \ goto catchException -QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) +static inline Heap::CallContext *getScope(Value *stack, int level) { -#ifdef DO_TRACE_INSTR - qDebug("Starting VME with context=%p and code=%p", context, code); -#endif // DO_TRACE_INSTR + Heap::ExecutionContext *scope = static_cast<ExecutionContext &>(stack[CallData::Context]).d(); + while (level > 0) { + --level; + scope = scope->outer; + } + Q_ASSERT(scope); + return static_cast<Heap::CallContext *>(scope); +} - qt_v4ResolvePendingBreakpointsHook(); +static inline const QV4::Value &constant(Function *function, int index) +{ + return function->compilationUnit->constants[index]; +} -#ifdef MOTH_THREADED_INTERPRETER -#define MOTH_INSTR_ADDR(I, FMT) &&op_##I, - static void *jumpTable[] = { - FOR_EACH_MOTH_INSTR(MOTH_INSTR_ADDR) - }; -#undef MOTH_INSTR_ADDR -#endif - QV4::Value *stack = 0; - unsigned stackSize = 0; +static bool compareEqual(Value lhs, Value rhs) +{ + redo: + if (lhs.asReturnedValue() == rhs.asReturnedValue()) + return !lhs.isNaN(); + + int lt = lhs.quickType(); + int rt = rhs.quickType(); + if (rt < lt) { + qSwap(lhs, rhs); + qSwap(lt, rt); + } - const uchar *exceptionHandler = 0; + switch (lt) { + case Value::QT_ManagedOrUndefined: + if (lhs.isUndefined()) + return rhs.isNullOrUndefined(); + Q_FALLTHROUGH(); + case Value::QT_ManagedOrUndefined1: + case Value::QT_ManagedOrUndefined2: + case Value::QT_ManagedOrUndefined3: + // LHS: Managed + switch (rt) { + case Value::QT_ManagedOrUndefined: + if (rhs.isUndefined()) + return false; + Q_FALLTHROUGH(); + case Value::QT_ManagedOrUndefined1: + case Value::QT_ManagedOrUndefined2: + case Value::QT_ManagedOrUndefined3: { + // RHS: Managed + Heap::Base *l = lhs.m(); + Heap::Base *r = rhs.m(); + Q_ASSERT(l); + Q_ASSERT(r); + if (l->vtable()->isString == r->vtable()->isString) + return static_cast<QV4::Managed &>(lhs).isEqualTo(&static_cast<QV4::Managed &>(rhs)); + if (l->vtable()->isString) { + rhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(rhs), PREFERREDTYPE_HINT)); + break; + } else { + Q_ASSERT(r->vtable()->isString); + lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT)); + break; + } + return false; + } + case Value::QT_Empty: + Q_UNREACHABLE(); + case Value::QT_Null: + return false; + case Value::QT_Bool: + case Value::QT_Int: + rhs = Primitive::fromDouble(rhs.int_32()); + // fall through + default: // double + if (lhs.m()->vtable()->isString) + return RuntimeHelpers::toNumber(lhs) == rhs.doubleValue(); + else + lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT)); + } + goto redo; + case Value::QT_Empty: + Q_UNREACHABLE(); + case Value::QT_Null: + return rhs.isNull(); + case Value::QT_Bool: + case Value::QT_Int: + switch (rt) { + case Value::QT_ManagedOrUndefined: + case Value::QT_ManagedOrUndefined1: + case Value::QT_ManagedOrUndefined2: + case Value::QT_ManagedOrUndefined3: + case Value::QT_Empty: + case Value::QT_Null: + Q_UNREACHABLE(); + case Value::QT_Bool: + case Value::QT_Int: + return lhs.int_32() == rhs.int_32(); + default: // double + return lhs.int_32() == rhs.doubleValue(); + } + default: // double + Q_ASSERT(rhs.isDouble()); + return lhs.doubleValue() == rhs.doubleValue(); + } +} - QV4::Scope scope(engine); - engine->current->lineNumber = -1; +static bool compareEqualInt(Value &accumulator, Value lhs, int rhs) +{ + redo: + switch (lhs.quickType()) { + case Value::QT_ManagedOrUndefined: + if (lhs.isUndefined()) + return false; + Q_FALLTHROUGH(); + case Value::QT_ManagedOrUndefined1: + case Value::QT_ManagedOrUndefined2: + case Value::QT_ManagedOrUndefined3: + // LHS: Managed + if (lhs.m()->vtable()->isString) + return RuntimeHelpers::stringToNumber(static_cast<String &>(lhs).toQString()) == rhs; + accumulator = lhs; + lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(accumulator), PREFERREDTYPE_HINT)); + goto redo; + case Value::QT_Empty: + Q_UNREACHABLE(); + case Value::QT_Null: + return false; + case Value::QT_Bool: + case Value::QT_Int: + return lhs.int_32() == rhs; + default: // double + return lhs.doubleValue() == rhs; + } +} -#ifdef DO_TRACE_INSTR - qDebug("Starting VME with context=%p and code=%p", context, code); -#endif // DO_TRACE_INSTR +#define STORE_IP() frame.instructionPointer = int(code - codeStart); +#define STORE_ACC() accumulator = acc; +#define ACC Primitive::fromReturnedValue(acc) +#define VALUE_TO_INT(i, val) \ + int i; \ + do { \ + if (Q_LIKELY(val.integerCompatible())) { \ + i = val.int_32(); \ + } else { \ + double d; \ + if (val.isDouble()) \ + d = val.doubleValue(); \ + else { \ + d = val.toNumberImpl(); \ + CHECK_EXCEPTION; \ + } \ + i = Double::toInt32(d); \ + } \ + } while (false) + +QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc) +{ + qt_v4ResolvePendingBreakpointsHook(); + ExecutionEngine *engine; + Value *stack; + CppStackFrame frame; + frame.originalArguments = argv; + frame.originalArgumentsCount = argc; + Function *function; - // setup lookup scopes - int scopeDepth = 0; { - QV4::Heap::ExecutionContext *scope = engine->current; - while (scope) { - ++scopeDepth; - scope = scope->outer; + Heap::ExecutionContext *scope; + + quintptr d = reinterpret_cast<quintptr>(fo); + if (d & 0x1) { + // we don't have a FunctionObject, but a ExecData + ExecData *data = reinterpret_cast<ExecData *>(d - 1); + function = data->function; + scope = data->scope->d(); + fo = nullptr; + } else { + function = fo->function(); + scope = fo->scope(); } + + engine = function->internalClass->engine; + + stack = engine->jsStackTop; + CallData *callData = reinterpret_cast<CallData *>(stack); + callData->function = fo ? fo->asReturnedValue() : Encode::undefined(); + callData->context = scope; + callData->accumulator = Encode::undefined(); + callData->thisObject = thisObject ? *thisObject : Primitive::undefinedValue(); + if (argc > int(function->nFormals)) + argc = int(function->nFormals); + callData->setArgc(argc); + + int jsStackFrameSize = offsetof(CallData, args)/sizeof(Value) + function->compiledFunction->nRegisters; + engine->jsStackTop += jsStackFrameSize; + memcpy(callData->args, argv, argc*sizeof(Value)); + for (Value *v = callData->args + argc; v < engine->jsStackTop; ++v) + *v = Encode::undefined(); + + frame.parent = engine->currentStackFrame; + frame.v4Function = function; + frame.instructionPointer = 0; + frame.jsFrame = callData; + engine->currentStackFrame = &frame; } + CHECK_STACK_LIMITS(engine); - struct Scopes { - QV4::Value *values; - QV4::Heap::Base *base; // non 0 if a write barrier is required - }; - Q_ALLOCA_VAR(Scopes, scopes, sizeof(Scopes)*(2 + 2*scopeDepth)); - { - scopes[0] = { const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->constants), 0 }; - // stack gets setup in push instruction - scopes[1] = { 0, 0 }; - QV4::Heap::ExecutionContext *scope = engine->current; - int i = 0; - while (scope) { - if (scope->type == QV4::Heap::ExecutionContext::Type_SimpleCallContext) { - QV4::Heap::SimpleCallContext *cc = static_cast<QV4::Heap::SimpleCallContext *>(scope); - scopes[2*i + 2] = { cc->callData->args, 0 }; - scopes[2*i + 3] = { 0, 0 }; - } else if (scope->type == QV4::Heap::ExecutionContext::Type_CallContext) { - QV4::Heap::CallContext *cc = static_cast<QV4::Heap::CallContext *>(scope); - scopes[2*i + 2] = { cc->callData->args, cc }; - scopes[2*i + 3] = { cc->locals.values, cc }; - } else { - scopes[2*i + 2] = { 0, 0 }; - scopes[2*i + 3] = { 0, 0 }; - } - ++i; - scope = scope->outer; - } + Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling + QV4::Debugging::Debugger *debugger = engine->debugger(); + + const uchar *exceptionHandler = 0; + + QV4::Value &accumulator = frame.jsFrame->accumulator; + QV4::ReturnedValue acc = Encode::undefined(); + +#ifdef V4_ENABLE_JIT + static const bool forceInterpreter = qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER"); + if (function->jittedCode == nullptr) { + if (ExecutionEngine::canJIT() && debugger == nullptr && !forceInterpreter) + QV4::JIT::BaselineJIT(function).generate(); } +#endif // V4_ENABLE_JIT + + if (debugger) + debugger->enteringFunction(); + if (function->jittedCode != nullptr && debugger == nullptr) { + acc = function->jittedCode(&frame, engine); + } else { + // interpreter + const uchar *code = function->codeData; + const uchar *codeStart = code; + + MOTH_JUMP_TABLE; for (;;) { - const Instr *genericInstr = reinterpret_cast<const Instr *>(code); -#ifdef MOTH_THREADED_INTERPRETER - goto *jumpTable[genericInstr->common.instructionType]; -#else - switch (genericInstr->common.instructionType) { -#endif + MOTH_DISPATCH() + Q_UNREACHABLE(); // only reached when the dispatch doesn't jump somewhere + + MOTH_BEGIN_INSTR(LoadConst) + acc = constant(function, index).asReturnedValue(); + MOTH_END_INSTR(LoadConst) + + MOTH_BEGIN_INSTR(LoadNull) + acc = Encode::null(); + MOTH_END_INSTR(LoadNull) + + MOTH_BEGIN_INSTR(LoadZero) + acc = Encode(static_cast<int>(0)); + MOTH_END_INSTR(LoadZero) - MOTH_BEGIN_INSTR(Move) - VALUE(instr.result) = VALUE(instr.source); - MOTH_END_INSTR(Move) + MOTH_BEGIN_INSTR(LoadTrue) + acc = Encode(true); + MOTH_END_INSTR(LoadTrue) + + MOTH_BEGIN_INSTR(LoadFalse) + acc = Encode(false); + MOTH_END_INSTR(LoadFalse) + + MOTH_BEGIN_INSTR(LoadUndefined) + acc = Encode::undefined(); + MOTH_END_INSTR(LoadUndefined) + + MOTH_BEGIN_INSTR(LoadInt) + acc = Encode(value); + MOTH_END_INSTR(LoadInt) MOTH_BEGIN_INSTR(MoveConst) - VALUE(instr.result) = instr.source; + STACK_VALUE(destTemp) = constant(function, constIndex); MOTH_END_INSTR(MoveConst) - MOTH_BEGIN_INSTR(SwapTemps) - qSwap(VALUE(instr.left), VALUE(instr.right)); - MOTH_END_INSTR(MoveTemp) + MOTH_BEGIN_INSTR(LoadReg) + acc = STACK_VALUE(reg).asReturnedValue(); + MOTH_END_INSTR(LoadReg) + + MOTH_BEGIN_INSTR(StoreReg) + STACK_VALUE(reg) = acc; + MOTH_END_INSTR(StoreReg) + + MOTH_BEGIN_INSTR(MoveReg) + STACK_VALUE(destReg) = STACK_VALUE(srcReg); + MOTH_END_INSTR(MoveReg) + + MOTH_BEGIN_INSTR(LoadLocal) + auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m()); + acc = cc->locals[index].asReturnedValue(); + MOTH_END_INSTR(LoadLocal) + + MOTH_BEGIN_INSTR(StoreLocal) + CHECK_EXCEPTION; + auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m()); + QV4::WriteBarrier::write(engine, cc, cc->locals.values + index, ACC); + MOTH_END_INSTR(StoreLocal) + + MOTH_BEGIN_INSTR(LoadScopedLocal) + auto cc = getScope(stack, scope); + acc = cc->locals[index].asReturnedValue(); + MOTH_END_INSTR(LoadScopedLocal) + + MOTH_BEGIN_INSTR(StoreScopedLocal) + CHECK_EXCEPTION; + auto cc = getScope(stack, scope); + QV4::WriteBarrier::write(engine, cc, cc->locals.values + index, ACC); + MOTH_END_INSTR(StoreScopedLocal) MOTH_BEGIN_INSTR(LoadRuntimeString) -// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData()); - VALUE(instr.result) = engine->current->compilationUnit->runtimeStrings[instr.stringId]; + acc = function->compilationUnit->runtimeStrings[stringId]->asReturnedValue(); MOTH_END_INSTR(LoadRuntimeString) MOTH_BEGIN_INSTR(LoadRegExp) -// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData()); - Heap::RegExpObject *ro = engine->newRegExpObject( - static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit) - ->runtimeRegularExpressions[instr.regExpId].as<RegExp>()); - VALUE(instr.result) = ro; + acc = Runtime::method_regexpLiteral(engine, regExpId); MOTH_END_INSTR(LoadRegExp) MOTH_BEGIN_INSTR(LoadClosure) - STOREVALUE(instr.result, Runtime::method_closure(engine, instr.value)); + acc = Runtime::method_closure(engine, value); MOTH_END_INSTR(LoadClosure) MOTH_BEGIN_INSTR(LoadName) - TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData()); - STOREVALUE(instr.result, Runtime::method_getActivationProperty(engine, instr.name)); + STORE_IP(); + acc = Runtime::method_loadName(engine, name); + CHECK_EXCEPTION; MOTH_END_INSTR(LoadName) - MOTH_BEGIN_INSTR(GetGlobalLookup) - QV4::Lookup *l = engine->current->lookups + instr.index; - STOREVALUE(instr.result, l->globalGetter(l, engine)); - MOTH_END_INSTR(GetGlobalLookup) + MOTH_BEGIN_INSTR(LoadGlobalLookup) + QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; + acc = l->globalGetter(l, engine); + CHECK_EXCEPTION; + MOTH_END_INSTR(LoadGlobalLookup) + + MOTH_BEGIN_INSTR(StoreNameStrict) + STORE_IP(); + STORE_ACC(); + Runtime::method_storeNameStrict(engine, name, accumulator); + CHECK_EXCEPTION; + MOTH_END_INSTR(StoreNameStrict) - MOTH_BEGIN_INSTR(StoreName) - TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData()); - Runtime::method_setActivationProperty(engine, instr.name, VALUE(instr.source)); + MOTH_BEGIN_INSTR(StoreNameSloppy) + STORE_IP(); + STORE_ACC(); + Runtime::method_storeNameSloppy(engine, name, accumulator); CHECK_EXCEPTION; - MOTH_END_INSTR(StoreName) + MOTH_END_INSTR(StoreNameSloppy) MOTH_BEGIN_INSTR(LoadElement) - STOREVALUE(instr.result, Runtime::method_getElement(engine, VALUE(instr.base), VALUE(instr.index))); + STORE_IP(); + acc = Runtime::method_loadElement(engine, STACK_VALUE(base), STACK_VALUE(index)); + CHECK_EXCEPTION; MOTH_END_INSTR(LoadElement) - MOTH_BEGIN_INSTR(LoadElementLookup) - QV4::Lookup *l = engine->current->lookups + instr.lookup; - STOREVALUE(instr.result, l->indexedGetter(l, engine, VALUE(instr.base), VALUE(instr.index))); - MOTH_END_INSTR(LoadElementLookup) + MOTH_BEGIN_INSTR(LoadElementA) + STORE_IP(); + STORE_ACC(); + acc = Runtime::method_loadElement(engine, STACK_VALUE(base), accumulator); + CHECK_EXCEPTION; + MOTH_END_INSTR(LoadElementA) MOTH_BEGIN_INSTR(StoreElement) - Runtime::method_setElement(engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source)); + STORE_IP(); + STORE_ACC(); + if (!Runtime::method_storeElement(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator) && function->isStrict()) + engine->throwTypeError(); CHECK_EXCEPTION; MOTH_END_INSTR(StoreElement) - MOTH_BEGIN_INSTR(StoreElementLookup) - QV4::Lookup *l = engine->current->lookups + instr.lookup; - l->indexedSetter(l, engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source)); - CHECK_EXCEPTION; - MOTH_END_INSTR(StoreElementLookup) - MOTH_BEGIN_INSTR(LoadProperty) - STOREVALUE(instr.result, Runtime::method_getProperty(engine, VALUE(instr.base), instr.name)); + STORE_IP(); + acc = Runtime::method_loadProperty(engine, STACK_VALUE(base), name); + CHECK_EXCEPTION; MOTH_END_INSTR(LoadProperty) + MOTH_BEGIN_INSTR(LoadPropertyA) + STORE_IP(); + STORE_ACC(); + acc = Runtime::method_loadProperty(engine, accumulator, name); + CHECK_EXCEPTION; + MOTH_END_INSTR(LoadPropertyA) + MOTH_BEGIN_INSTR(GetLookup) - QV4::Lookup *l = engine->current->lookups + instr.index; - STOREVALUE(instr.result, l->getter(l, engine, VALUE(instr.base))); + STORE_IP(); + QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; + acc = l->getter(l, engine, STACK_VALUE(base)); + CHECK_EXCEPTION; MOTH_END_INSTR(GetLookup) + MOTH_BEGIN_INSTR(GetLookupA) + STORE_IP(); + STORE_ACC(); + QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; + acc = l->getter(l, engine, accumulator); + CHECK_EXCEPTION; + MOTH_END_INSTR(GetLookupA) + MOTH_BEGIN_INSTR(StoreProperty) - Runtime::method_setProperty(engine, VALUE(instr.base), instr.name, VALUE(instr.source)); + STORE_IP(); + STORE_ACC(); + if (!Runtime::method_storeProperty(engine, STACK_VALUE(base), name, accumulator) && function->isStrict()) + engine->throwTypeError(); CHECK_EXCEPTION; MOTH_END_INSTR(StoreProperty) MOTH_BEGIN_INSTR(SetLookup) - QV4::Lookup *l = engine->current->lookups + instr.index; - l->setter(l, engine, VALUE(instr.base), VALUE(instr.source)); + STORE_IP(); + STORE_ACC(); + QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; + if (!l->setter(l, engine, STACK_VALUE(base), accumulator) && function->isStrict()) + engine->throwTypeError(); CHECK_EXCEPTION; MOTH_END_INSTR(SetLookup) - MOTH_BEGIN_INSTR(StoreQObjectProperty) - Runtime::method_setQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); - CHECK_EXCEPTION; - MOTH_END_INSTR(StoreQObjectProperty) - - MOTH_BEGIN_INSTR(LoadQObjectProperty) - STOREVALUE(instr.result, Runtime::method_getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); - MOTH_END_INSTR(LoadQObjectProperty) - MOTH_BEGIN_INSTR(StoreScopeObjectProperty) - Runtime::method_setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); + STORE_ACC(); + Runtime::method_storeQmlScopeObjectProperty(engine, STACK_VALUE(base), propertyIndex, accumulator); CHECK_EXCEPTION; MOTH_END_INSTR(StoreScopeObjectProperty) MOTH_BEGIN_INSTR(LoadScopeObjectProperty) - STOREVALUE(instr.result, Runtime::method_getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); + STORE_IP(); + acc = Runtime::method_loadQmlScopeObjectProperty(engine, STACK_VALUE(base), propertyIndex, captureRequired); + CHECK_EXCEPTION; MOTH_END_INSTR(LoadScopeObjectProperty) MOTH_BEGIN_INSTR(StoreContextObjectProperty) - Runtime::method_setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); + STORE_IP(); + STORE_ACC(); + Runtime::method_storeQmlContextObjectProperty(engine, STACK_VALUE(base), propertyIndex, accumulator); CHECK_EXCEPTION; MOTH_END_INSTR(StoreContextObjectProperty) MOTH_BEGIN_INSTR(LoadContextObjectProperty) - STOREVALUE(instr.result, Runtime::method_getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); + STORE_IP(); + acc = Runtime::method_loadQmlContextObjectProperty(engine, STACK_VALUE(base), propertyIndex, captureRequired); + CHECK_EXCEPTION; MOTH_END_INSTR(LoadContextObjectProperty) MOTH_BEGIN_INSTR(LoadIdObject) - STOREVALUE(instr.result, Runtime::method_getQmlIdObject(engine, VALUE(instr.base), instr.index)); + STORE_IP(); + acc = Runtime::method_loadQmlIdObject(engine, STACK_VALUE(base), index); + CHECK_EXCEPTION; MOTH_END_INSTR(LoadIdObject) - MOTH_BEGIN_INSTR(LoadAttachedQObjectProperty) - STOREVALUE(instr.result, Runtime::method_getQmlAttachedProperty(engine, instr.attachedPropertiesId, instr.propertyIndex)); - MOTH_END_INSTR(LoadAttachedQObjectProperty) - - MOTH_BEGIN_INSTR(LoadSingletonQObjectProperty) - STOREVALUE(instr.result, Runtime::method_getQmlSingletonQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); - MOTH_END_INSTR(LoadSingletonQObjectProperty) - - MOTH_BEGIN_INSTR(Push) - TRACE(inline, "stack size: %u", instr.value); - stackSize = instr.value; - stack = scope.alloc(stackSize); - scopes[1].values = stack; - MOTH_END_INSTR(Push) - MOTH_BEGIN_INSTR(CallValue) -#if 0 //def DO_TRACE_INSTR - if (Debugging::Debugger *debugger = context->engine()->debugger) { - if (QV4::FunctionObject *o = (VALUE(instr.dest)).asFunctionObject()) { - if (Debugging::FunctionDebugInfo *info = debugger->debugInfo(o)) { - QString n = debugger->name(o); - std::cerr << "*** Call to \"" << (n.isNull() ? "<no name>" : qPrintable(n)) << "\" defined @" << info->startLine << ":" << info->startColumn << std::endl; - } - } + STORE_IP(); + STORE_ACC(); + Value func = Value::fromReturnedValue(acc); + if (Q_UNLIKELY(!func.isFunctionObject())) { + acc = engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); + goto catchException; } -#endif // DO_TRACE_INSTR - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, Runtime::method_callValue(engine, VALUE(instr.dest), callData)); + acc = static_cast<const FunctionObject &>(func).call(nullptr, stack + argv, argc); + CHECK_EXCEPTION; MOTH_END_INSTR(CallValue) MOTH_BEGIN_INSTR(CallProperty) - TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData()); - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, Runtime::method_callProperty(engine, instr.name, callData)); + STORE_IP(); + acc = Runtime::method_callProperty(engine, stack + base, name, stack + argv, argc); + CHECK_EXCEPTION; MOTH_END_INSTR(CallProperty) MOTH_BEGIN_INSTR(CallPropertyLookup) - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, Runtime::method_callPropertyLookup(engine, instr.lookupIndex, callData)); - MOTH_END_INSTR(CallPropertyLookup) + STORE_IP(); + Lookup *l = function->compilationUnit->runtimeLookups + lookupIndex; + // ok to have the value on the stack here + Value f = Value::fromReturnedValue(l->getter(l, engine, stack[base])); + + if (Q_UNLIKELY(!f.isFunctionObject())) { + acc = engine->throwTypeError(); + goto catchException; + } - MOTH_BEGIN_INSTR(CallScopeObjectProperty) - TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData()); - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, Runtime::method_callQmlScopeObjectProperty(engine, instr.index, callData)); - MOTH_END_INSTR(CallScopeObjectProperty) - - MOTH_BEGIN_INSTR(CallContextObjectProperty) - TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData()); - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, Runtime::method_callQmlContextObjectProperty(engine, instr.index, callData)); - MOTH_END_INSTR(CallContextObjectProperty) + acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc); + CHECK_EXCEPTION; + MOTH_END_INSTR(CallPropertyLookup) MOTH_BEGIN_INSTR(CallElement) - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, Runtime::method_callElement(engine, VALUE(instr.index), callData)); + STORE_IP(); + acc = Runtime::method_callElement(engine, stack + base, STACK_VALUE(index), stack + argv, argc); + CHECK_EXCEPTION; MOTH_END_INSTR(CallElement) - MOTH_BEGIN_INSTR(CallActivationProperty) - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, Runtime::method_callActivationProperty(engine, instr.name, callData)); - MOTH_END_INSTR(CallActivationProperty) + MOTH_BEGIN_INSTR(CallName) + STORE_IP(); + acc = Runtime::method_callName(engine, name, stack + argv, argc); + CHECK_EXCEPTION; + MOTH_END_INSTR(CallName) + + MOTH_BEGIN_INSTR(CallPossiblyDirectEval) + STORE_IP(); + acc = Runtime::method_callPossiblyDirectEval(engine, stack + argv, argc); + CHECK_EXCEPTION; + MOTH_END_INSTR(CallPossiblyDirectEval) MOTH_BEGIN_INSTR(CallGlobalLookup) - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, Runtime::method_callGlobalLookup(engine, instr.index, callData)); + STORE_IP(); + acc = Runtime::method_callGlobalLookup(engine, index, stack + argv, argc); + CHECK_EXCEPTION; MOTH_END_INSTR(CallGlobalLookup) MOTH_BEGIN_INSTR(SetExceptionHandler) - exceptionHandler = instr.offset ? ((const uchar *)&instr.offset) + instr.offset : 0; + exceptionHandler = offset ? code + offset : nullptr; MOTH_END_INSTR(SetExceptionHandler) - MOTH_BEGIN_INSTR(CallBuiltinThrow) - Runtime::method_throwException(engine, VALUE(instr.arg)); + MOTH_BEGIN_INSTR(ThrowException) + STORE_IP(); + STORE_ACC(); + Runtime::method_throwException(engine, accumulator); + goto catchException; + MOTH_END_INSTR(ThrowException) + + MOTH_BEGIN_INSTR(GetException) + acc = engine->hasException ? engine->exceptionValue->asReturnedValue() + : Primitive::emptyValue().asReturnedValue(); + engine->hasException = false; + MOTH_END_INSTR(HasException) + + MOTH_BEGIN_INSTR(SetException) + *engine->exceptionValue = acc; + engine->hasException = true; + MOTH_END_INSTR(SetException) + + MOTH_BEGIN_INSTR(PushCatchContext) + STACK_VALUE(reg) = STACK_VALUE(CallData::Context); + ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context); + STACK_VALUE(CallData::Context) = Runtime::method_createCatchContext(c, name); + MOTH_END_INSTR(PushCatchContext) + + MOTH_BEGIN_INSTR(CreateCallContext) + stack[CallData::Context] = ExecutionContext::newCallContext(&frame); + MOTH_END_INSTR(CreateCallContext) + + MOTH_BEGIN_INSTR(PushWithContext) + STORE_IP(); + STORE_ACC(); + accumulator = accumulator.toObject(engine); + CHECK_EXCEPTION; + STACK_VALUE(reg) = STACK_VALUE(CallData::Context); + ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context); + STACK_VALUE(CallData::Context) = Runtime::method_createWithContext(c, accumulator); + MOTH_END_INSTR(PushWithContext) + + MOTH_BEGIN_INSTR(PopContext) + STACK_VALUE(CallData::Context) = STACK_VALUE(reg); + MOTH_END_INSTR(PopContext) + + MOTH_BEGIN_INSTR(ForeachIteratorObject) + STORE_ACC(); + acc = Runtime::method_foreachIterator(engine, accumulator); CHECK_EXCEPTION; - MOTH_END_INSTR(CallBuiltinThrow) + MOTH_END_INSTR(ForeachIteratorObject) - MOTH_BEGIN_INSTR(CallBuiltinUnwindException) - STOREVALUE(instr.result, Runtime::method_unwindException(engine)); - MOTH_END_INSTR(CallBuiltinUnwindException) + MOTH_BEGIN_INSTR(ForeachNextPropertyName) + STORE_ACC(); + acc = Runtime::method_foreachNextPropertyName(accumulator); + CHECK_EXCEPTION; + MOTH_END_INSTR(ForeachNextPropertyName) + + MOTH_BEGIN_INSTR(DeleteMember) + if (!Runtime::method_deleteMember(engine, STACK_VALUE(base), member)) { + if (function->isStrict()) { + STORE_IP(); + engine->throwTypeError(); + goto catchException; + } + acc = Encode(false); + } else { + acc = Encode(true); + } + MOTH_END_INSTR(DeleteMember) + + MOTH_BEGIN_INSTR(DeleteSubscript) + if (!Runtime::method_deleteElement(engine, STACK_VALUE(base), STACK_VALUE(index))) { + if (function->isStrict()) { + STORE_IP(); + engine->throwTypeError(); + goto catchException; + } + acc = Encode(false); + } else { + acc = Encode(true); + } + MOTH_END_INSTR(DeleteSubscript) + + MOTH_BEGIN_INSTR(DeleteName) + if (!Runtime::method_deleteName(engine, name)) { + if (function->isStrict()) { + STORE_IP(); + QString n = function->compilationUnit->runtimeStrings[name]->toQString(); + engine->throwSyntaxError(QStringLiteral("Can't delete property %1").arg(n)); + goto catchException; + } + acc = Encode(false); + } else { + acc = Encode(true); + } + MOTH_END_INSTR(DeleteName) + + MOTH_BEGIN_INSTR(TypeofName) + acc = Runtime::method_typeofName(engine, name); + MOTH_END_INSTR(TypeofName) + + MOTH_BEGIN_INSTR(TypeofValue) + STORE_ACC(); + acc = Runtime::method_typeofValue(engine, accumulator); + MOTH_END_INSTR(TypeofValue) + + MOTH_BEGIN_INSTR(DeclareVar) + Runtime::method_declareVar(engine, isDeletable, varName); + MOTH_END_INSTR(DeclareVar) + + MOTH_BEGIN_INSTR(DefineArray) + QV4::Value *arguments = stack + args; + acc = Runtime::method_arrayLiteral(engine, arguments, argc); + MOTH_END_INSTR(DefineArray) + + MOTH_BEGIN_INSTR(DefineObjectLiteral) + QV4::Value *arguments = stack + args; + acc = Runtime::method_objectLiteral(engine, arguments, internalClassId, arrayValueCount, arrayGetterSetterCountAndFlags); + MOTH_END_INSTR(DefineObjectLiteral) + + MOTH_BEGIN_INSTR(CreateMappedArgumentsObject) + acc = Runtime::method_createMappedArgumentsObject(engine); + MOTH_END_INSTR(CreateMappedArgumentsObject) + + MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject) + acc = Runtime::method_createUnmappedArgumentsObject(engine); + MOTH_END_INSTR(CreateUnmappedArgumentsObject) + + MOTH_BEGIN_INSTR(ConvertThisToObject) + Value *t = &stack[CallData::This]; + if (!t->isObject()) { + if (t->isNullOrUndefined()) { + *t = engine->globalObject->asReturnedValue(); + } else { + *t = t->toObject(engine)->asReturnedValue(); + CHECK_EXCEPTION; + } + } + MOTH_END_INSTR(ConvertThisToObject) - MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope) - Runtime::method_pushCatchScope(static_cast<QV4::NoThrowEngine*>(engine), instr.name); - MOTH_END_INSTR(CallBuiltinPushCatchScope) - - MOTH_BEGIN_INSTR(CallBuiltinPushScope) - Runtime::method_pushWithScope(VALUE(instr.arg), static_cast<QV4::NoThrowEngine*>(engine)); - CHECK_EXCEPTION; - MOTH_END_INSTR(CallBuiltinPushScope) - - MOTH_BEGIN_INSTR(CallBuiltinPopScope) - Runtime::method_popScope(static_cast<QV4::NoThrowEngine*>(engine)); - MOTH_END_INSTR(CallBuiltinPopScope) - - MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject) - STOREVALUE(instr.result, Runtime::method_foreachIterator(engine, VALUE(instr.arg))); - MOTH_END_INSTR(CallBuiltinForeachIteratorObject) - - MOTH_BEGIN_INSTR(CallBuiltinForeachNextPropertyName) - STOREVALUE(instr.result, Runtime::method_foreachNextPropertyName(VALUE(instr.arg))); - MOTH_END_INSTR(CallBuiltinForeachNextPropertyName) - - MOTH_BEGIN_INSTR(CallBuiltinDeleteMember) - STOREVALUE(instr.result, Runtime::method_deleteMember(engine, VALUE(instr.base), instr.member)); - MOTH_END_INSTR(CallBuiltinDeleteMember) - - MOTH_BEGIN_INSTR(CallBuiltinDeleteSubscript) - STOREVALUE(instr.result, Runtime::method_deleteElement(engine, VALUE(instr.base), VALUE(instr.index))); - MOTH_END_INSTR(CallBuiltinDeleteSubscript) - - MOTH_BEGIN_INSTR(CallBuiltinDeleteName) - STOREVALUE(instr.result, Runtime::method_deleteName(engine, instr.name)); - MOTH_END_INSTR(CallBuiltinDeleteName) - - MOTH_BEGIN_INSTR(CallBuiltinTypeofScopeObjectProperty) - STOREVALUE(instr.result, Runtime::method_typeofScopeObjectProperty(engine, VALUE(instr.base), instr.index)); - MOTH_END_INSTR(CallBuiltinTypeofMember) - - MOTH_BEGIN_INSTR(CallBuiltinTypeofContextObjectProperty) - STOREVALUE(instr.result, Runtime::method_typeofContextObjectProperty(engine, VALUE(instr.base), instr.index)); - MOTH_END_INSTR(CallBuiltinTypeofMember) - - MOTH_BEGIN_INSTR(CallBuiltinTypeofMember) - STOREVALUE(instr.result, Runtime::method_typeofMember(engine, VALUE(instr.base), instr.member)); - MOTH_END_INSTR(CallBuiltinTypeofMember) - - MOTH_BEGIN_INSTR(CallBuiltinTypeofSubscript) - STOREVALUE(instr.result, Runtime::method_typeofElement(engine, VALUE(instr.base), VALUE(instr.index))); - MOTH_END_INSTR(CallBuiltinTypeofSubscript) - - MOTH_BEGIN_INSTR(CallBuiltinTypeofName) - STOREVALUE(instr.result, Runtime::method_typeofName(engine, instr.name)); - MOTH_END_INSTR(CallBuiltinTypeofName) - - MOTH_BEGIN_INSTR(CallBuiltinTypeofValue) - STOREVALUE(instr.result, Runtime::method_typeofValue(engine, VALUE(instr.value))); - MOTH_END_INSTR(CallBuiltinTypeofValue) - - MOTH_BEGIN_INSTR(CallBuiltinDeclareVar) - Runtime::method_declareVar(engine, instr.isDeletable, instr.varName); - MOTH_END_INSTR(CallBuiltinDeclareVar) - - MOTH_BEGIN_INSTR(CallBuiltinDefineArray) - Q_ASSERT(instr.args + instr.argc <= stackSize); - QV4::Value *args = stack + instr.args; - STOREVALUE(instr.result, Runtime::method_arrayLiteral(engine, args, instr.argc)); - MOTH_END_INSTR(CallBuiltinDefineArray) - - MOTH_BEGIN_INSTR(CallBuiltinDefineObjectLiteral) - QV4::Value *args = stack + instr.args; - STOREVALUE(instr.result, Runtime::method_objectLiteral(engine, args, instr.internalClassId, instr.arrayValueCount, instr.arrayGetterSetterCountAndFlags)); - MOTH_END_INSTR(CallBuiltinDefineObjectLiteral) - - MOTH_BEGIN_INSTR(CallBuiltinSetupArgumentsObject) - STOREVALUE(instr.result, Runtime::method_setupArgumentsObject(engine)); - MOTH_END_INSTR(CallBuiltinSetupArgumentsObject) - - MOTH_BEGIN_INSTR(CallBuiltinConvertThisToObject) - Runtime::method_convertThisToObject(engine); - CHECK_EXCEPTION; - MOTH_END_INSTR(CallBuiltinConvertThisToObject) - - MOTH_BEGIN_INSTR(CreateValue) - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, Runtime::method_constructValue(engine, VALUE(instr.func), callData)); - MOTH_END_INSTR(CreateValue) - - MOTH_BEGIN_INSTR(CreateProperty) - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, Runtime::method_constructProperty(engine, instr.name, callData)); - MOTH_END_INSTR(CreateProperty) - - MOTH_BEGIN_INSTR(ConstructPropertyLookup) - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, Runtime::method_constructPropertyLookup(engine, instr.index, callData)); - MOTH_END_INSTR(ConstructPropertyLookup) - - MOTH_BEGIN_INSTR(CreateActivationProperty) - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, Runtime::method_constructActivationProperty(engine, instr.name, callData)); - MOTH_END_INSTR(CreateActivationProperty) - - MOTH_BEGIN_INSTR(ConstructGlobalLookup) - Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); - QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = quint32(Value::ValueTypeInternal::Integer); - callData->argc = instr.argc; - callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, Runtime::method_constructGlobalLookup(engine, instr.index, callData)); - MOTH_END_INSTR(ConstructGlobalLookup) + MOTH_BEGIN_INSTR(Construct) + STORE_IP(); + acc = Runtime::method_construct(engine, STACK_VALUE(func), stack + argv, argc); + CHECK_EXCEPTION; + MOTH_END_INSTR(Construct) MOTH_BEGIN_INSTR(Jump) - code = ((const uchar *)&instr.offset) + instr.offset; + code += offset; MOTH_END_INSTR(Jump) - MOTH_BEGIN_INSTR(JumpEq) - bool cond = VALUEPTR(instr.condition)->toBoolean(); - TRACE(condition, "%s", cond ? "TRUE" : "FALSE"); - if (cond) - code = ((const uchar *)&instr.offset) + instr.offset; - MOTH_END_INSTR(JumpEq) + MOTH_BEGIN_INSTR(JumpTrue) + if (Q_LIKELY(ACC.integerCompatible())) { + if (ACC.int_32()) + code += offset; + } else { + if (ACC.toBoolean()) + code += offset; + } + MOTH_END_INSTR(JumpTrue) + + MOTH_BEGIN_INSTR(JumpFalse) + if (Q_LIKELY(ACC.integerCompatible())) { + if (!ACC.int_32()) + code += offset; + } else { + if (!ACC.toBoolean()) + code += offset; + } + MOTH_END_INSTR(JumpFalse) + + MOTH_BEGIN_INSTR(CmpEqNull) + acc = Encode(ACC.isNullOrUndefined()); + MOTH_END_INSTR(CmpEqNull) + + MOTH_BEGIN_INSTR(CmpNeNull) + acc = Encode(!ACC.isNullOrUndefined()); + MOTH_END_INSTR(CmpNeNull) + + MOTH_BEGIN_INSTR(CmpEqInt) + if (ACC.isIntOrBool()) { + acc = Encode(ACC.int_32() == lhs); + } else { + STORE_ACC(); + acc = Encode(compareEqualInt(accumulator, ACC, lhs)); + CHECK_EXCEPTION; + } + MOTH_END_INSTR(CmpEqInt) + + MOTH_BEGIN_INSTR(CmpNeInt) + if (ACC.isIntOrBool()) { + acc = Encode(bool(ACC.int_32() != lhs)); + } else { + STORE_ACC(); + acc = Encode(!compareEqualInt(accumulator, ACC, lhs)); + CHECK_EXCEPTION; + } + MOTH_END_INSTR(CmpNeInt) + + MOTH_BEGIN_INSTR(CmpEq) + const Value left = STACK_VALUE(lhs); + if (Q_LIKELY(left.asReturnedValue() == ACC.asReturnedValue())) { + acc = Encode(!ACC.isNaN()); + } else if (Q_LIKELY(left.isInteger() && ACC.isInteger())) { + acc = Encode(left.int_32() == ACC.int_32()); + } else { + STORE_ACC(); + acc = Encode(compareEqual(left, accumulator)); + CHECK_EXCEPTION; + } + MOTH_END_INSTR(CmpEq) + + MOTH_BEGIN_INSTR(CmpNe) + const Value left = STACK_VALUE(lhs); + if (Q_LIKELY(left.isInteger() && ACC.isInteger())) { + acc = Encode(bool(left.int_32() != ACC.int_32())); + } else { + STORE_ACC(); + acc = Encode(!compareEqual(left, accumulator)); + CHECK_EXCEPTION; + } + MOTH_END_INSTR(CmpNe) + + MOTH_BEGIN_INSTR(CmpGt) + const Value left = STACK_VALUE(lhs); + if (Q_LIKELY(left.isInteger() && ACC.isInteger())) { + acc = Encode(left.int_32() > ACC.int_32()); + } else if (left.isNumber() && ACC.isNumber()) { + acc = Encode(left.asDouble() > ACC.asDouble()); + } else { + STORE_ACC(); + acc = Encode(bool(Runtime::method_compareGreaterThan(left, accumulator))); + CHECK_EXCEPTION; + } + MOTH_END_INSTR(CmpGt) + + MOTH_BEGIN_INSTR(CmpGe) + const Value left = STACK_VALUE(lhs); + if (Q_LIKELY(left.isInteger() && ACC.isInteger())) { + acc = Encode(left.int_32() >= ACC.int_32()); + } else if (left.isNumber() && ACC.isNumber()) { + acc = Encode(left.asDouble() >= ACC.asDouble()); + } else { + STORE_ACC(); + acc = Encode(bool(Runtime::method_compareGreaterEqual(left, accumulator))); + CHECK_EXCEPTION; + } + MOTH_END_INSTR(CmpGe) + + MOTH_BEGIN_INSTR(CmpLt) + const Value left = STACK_VALUE(lhs); + if (Q_LIKELY(left.isInteger() && ACC.isInteger())) { + acc = Encode(left.int_32() < ACC.int_32()); + } else if (left.isNumber() && ACC.isNumber()) { + acc = Encode(left.asDouble() < ACC.asDouble()); + } else { + STORE_ACC(); + acc = Encode(bool(Runtime::method_compareLessThan(left, accumulator))); + CHECK_EXCEPTION; + } + MOTH_END_INSTR(CmpLt) + + MOTH_BEGIN_INSTR(CmpLe) + const Value left = STACK_VALUE(lhs); + if (Q_LIKELY(left.isInteger() && ACC.isInteger())) { + acc = Encode(left.int_32() <= ACC.int_32()); + } else if (left.isNumber() && ACC.isNumber()) { + acc = Encode(left.asDouble() <= ACC.asDouble()); + } else { + STORE_ACC(); + acc = Encode(bool(Runtime::method_compareLessEqual(left, accumulator))); + CHECK_EXCEPTION; + } + MOTH_END_INSTR(CmpLe) + + MOTH_BEGIN_INSTR(CmpStrictEqual) + if (STACK_VALUE(lhs).rawValue() == ACC.rawValue() && !ACC.isNaN()) { + acc = Encode(true); + } else { + STORE_ACC(); + acc = Encode(bool(RuntimeHelpers::strictEqual(STACK_VALUE(lhs), accumulator))); + CHECK_EXCEPTION; + } + MOTH_END_INSTR(CmpStrictEqual) + + MOTH_BEGIN_INSTR(CmpStrictNotEqual) + if (STACK_VALUE(lhs).rawValue() != ACC.rawValue() || ACC.isNaN()) { + STORE_ACC(); + acc = Encode(!RuntimeHelpers::strictEqual(STACK_VALUE(lhs), accumulator)); + CHECK_EXCEPTION; + } else { + acc = Encode(false); + } + MOTH_END_INSTR(CmpStrictNotEqual) + + MOTH_BEGIN_INSTR(CmpIn) + STORE_ACC(); + acc = Runtime::method_in(engine, STACK_VALUE(lhs), accumulator); + CHECK_EXCEPTION; + MOTH_END_INSTR(CmpIn) + + MOTH_BEGIN_INSTR(CmpInstanceOf) + // 11.8.6, 5: rval must be an Object + const Object *rhs = Primitive::fromReturnedValue(acc).as<Object>(); + if (Q_UNLIKELY(!rhs)) { + acc = engine->throwTypeError(); + goto catchException; + } + + // 11.8.6, 7: call "HasInstance", which we term instanceOf, and return the result. + acc = rhs->instanceOf(STACK_VALUE(lhs)); + CHECK_EXCEPTION; + MOTH_END_INSTR(CmpInstanceOf) + + MOTH_BEGIN_INSTR(JumpStrictNotEqualStackSlotInt) + if (STACK_VALUE(lhs).int_32() != rhs || STACK_VALUE(lhs).isUndefined()) + code += offset; + MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt) - MOTH_BEGIN_INSTR(JumpNe) - bool cond = VALUEPTR(instr.condition)->toBoolean(); - TRACE(condition, "%s", cond ? "TRUE" : "FALSE"); - if (!cond) - code = ((const uchar *)&instr.offset) + instr.offset; - MOTH_END_INSTR(JumpNe) + MOTH_BEGIN_INSTR(JumpStrictEqualStackSlotInt) + if (STACK_VALUE(lhs).int_32() == rhs && !STACK_VALUE(lhs).isUndefined()) + code += offset; + MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt) MOTH_BEGIN_INSTR(UNot) - STOREVALUE(instr.result, Runtime::method_uNot(VALUE(instr.source))); + if (ACC.integerCompatible()) { + acc = Encode(!static_cast<bool>(ACC.int_32())); + } else { + acc = Encode(!Value::toBooleanImpl(ACC)); + } MOTH_END_INSTR(UNot) - MOTH_BEGIN_INSTR(UNotBool) - bool b = VALUE(instr.source).booleanValue(); - VALUE(instr.result) = QV4::Encode(!b); - MOTH_END_INSTR(UNotBool) - MOTH_BEGIN_INSTR(UPlus) - STOREVALUE(instr.result, Runtime::method_uPlus(VALUE(instr.source))); + if (Q_UNLIKELY(!ACC.isNumber())) { + acc = Encode(ACC.toNumberImpl()); + CHECK_EXCEPTION; + } MOTH_END_INSTR(UPlus) MOTH_BEGIN_INSTR(UMinus) - STOREVALUE(instr.result, Runtime::method_uMinus(VALUE(instr.source))); + if (Q_LIKELY(ACC.integerCompatible())) { + int a = ACC.int_32(); + if (a == 0 || a == std::numeric_limits<int>::min()) { + acc = Encode(-static_cast<double>(a)); + } else { + acc = sub_int32(0, ACC.int_32()); + } + } else if (ACC.isDouble()) { + acc ^= (1ull << 63); // simply flip sign bit + } else { + acc = Encode(-ACC.toNumberImpl()); + CHECK_EXCEPTION; + } MOTH_END_INSTR(UMinus) MOTH_BEGIN_INSTR(UCompl) - STOREVALUE(instr.result, Runtime::method_complement(VALUE(instr.source))); + VALUE_TO_INT(a, ACC); + acc = Encode(~a); MOTH_END_INSTR(UCompl) - MOTH_BEGIN_INSTR(UComplInt) - VALUE(instr.result) = QV4::Encode((int)~VALUE(instr.source).integerValue()); - MOTH_END_INSTR(UComplInt) - MOTH_BEGIN_INSTR(Increment) - STOREVALUE(instr.result, Runtime::method_increment(VALUE(instr.source))); + if (Q_LIKELY(ACC.integerCompatible())) { + acc = add_int32(ACC.int_32(), 1); + } else if (ACC.isDouble()) { + acc = QV4::Encode(ACC.doubleValue() + 1.); + } else { + acc = Encode(ACC.toNumberImpl() + 1.); + CHECK_EXCEPTION; + } MOTH_END_INSTR(Increment) MOTH_BEGIN_INSTR(Decrement) - STOREVALUE(instr.result, Runtime::method_decrement(VALUE(instr.source))); + if (Q_LIKELY(ACC.integerCompatible())) { + acc = sub_int32(ACC.int_32(), 1); + } else if (ACC.isDouble()) { + acc = QV4::Encode(ACC.doubleValue() - 1.); + } else { + acc = Encode(ACC.toNumberImpl() - 1.); + CHECK_EXCEPTION; + } MOTH_END_INSTR(Decrement) - MOTH_BEGIN_INSTR(Binop) - QV4::Runtime::BinaryOperation op = *reinterpret_cast<QV4::Runtime::BinaryOperation *>(reinterpret_cast<char *>(&engine->runtime.runtimeMethods[instr.alu])); - STOREVALUE(instr.result, op(VALUE(instr.lhs), VALUE(instr.rhs))); - MOTH_END_INSTR(Binop) - MOTH_BEGIN_INSTR(Add) - STOREVALUE(instr.result, Runtime::method_add(engine, VALUE(instr.lhs), VALUE(instr.rhs))); + const Value left = STACK_VALUE(lhs); + if (Q_LIKELY(Value::integerCompatible(left, ACC))) { + acc = add_int32(left.int_32(), ACC.int_32()); + } else if (left.isNumber() && ACC.isNumber()) { + acc = Encode(left.asDouble() + ACC.asDouble()); + } else { + STORE_ACC(); + acc = Runtime::method_add(engine, left, accumulator); + CHECK_EXCEPTION; + } MOTH_END_INSTR(Add) + MOTH_BEGIN_INSTR(Sub) + const Value left = STACK_VALUE(lhs); + if (Q_LIKELY(Value::integerCompatible(left, ACC))) { + acc = sub_int32(left.int_32(), ACC.int_32()); + } else if (left.isNumber() && ACC.isNumber()) { + acc = Encode(left.asDouble() - ACC.asDouble()); + } else { + STORE_ACC(); + acc = Runtime::method_sub(left, accumulator); + CHECK_EXCEPTION; + } + MOTH_END_INSTR(Sub) + + MOTH_BEGIN_INSTR(Mul) + const Value left = STACK_VALUE(lhs); + if (Q_LIKELY(Value::integerCompatible(left, ACC))) { + acc = mul_int32(left.int_32(), ACC.int_32()); + } else if (left.isNumber() && ACC.isNumber()) { + acc = Encode(left.asDouble() * ACC.asDouble()); + } else { + STORE_ACC(); + acc = Runtime::method_mul(left, accumulator); + CHECK_EXCEPTION; + } + MOTH_END_INSTR(Mul) + + MOTH_BEGIN_INSTR(Div) + STORE_ACC(); + acc = Runtime::method_div(STACK_VALUE(lhs), accumulator); + CHECK_EXCEPTION; + MOTH_END_INSTR(Div) + + MOTH_BEGIN_INSTR(Mod) + STORE_ACC(); + acc = Runtime::method_mod(STACK_VALUE(lhs), accumulator); + CHECK_EXCEPTION; + MOTH_END_INSTR(Mod) + MOTH_BEGIN_INSTR(BitAnd) - STOREVALUE(instr.result, Runtime::method_bitAnd(VALUE(instr.lhs), VALUE(instr.rhs))); + VALUE_TO_INT(l, STACK_VALUE(lhs)); + VALUE_TO_INT(a, ACC); + acc = Encode(l & a); MOTH_END_INSTR(BitAnd) MOTH_BEGIN_INSTR(BitOr) - STOREVALUE(instr.result, Runtime::method_bitOr(VALUE(instr.lhs), VALUE(instr.rhs))); + VALUE_TO_INT(l, STACK_VALUE(lhs)); + VALUE_TO_INT(a, ACC); + acc = Encode(l | a); MOTH_END_INSTR(BitOr) MOTH_BEGIN_INSTR(BitXor) - STOREVALUE(instr.result, Runtime::method_bitXor(VALUE(instr.lhs), VALUE(instr.rhs))); + VALUE_TO_INT(l, STACK_VALUE(lhs)); + VALUE_TO_INT(a, ACC); + acc = Encode(l ^ a); MOTH_END_INSTR(BitXor) + MOTH_BEGIN_INSTR(UShr) + uint l = STACK_VALUE(lhs).toUInt32(); + VALUE_TO_INT(a, ACC); + acc = Encode(l >> uint(a & 0x1f)); + MOTH_END_INSTR(UShr) + MOTH_BEGIN_INSTR(Shr) - STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() >> (VALUEPTR(instr.rhs)->toInt32() & 0x1f)))); + VALUE_TO_INT(l, STACK_VALUE(lhs)); + VALUE_TO_INT(a, ACC); + acc = Encode(l >> (a & 0x1f)); MOTH_END_INSTR(Shr) MOTH_BEGIN_INSTR(Shl) - STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() << (VALUEPTR(instr.rhs)->toInt32() & 0x1f)))); + VALUE_TO_INT(l, STACK_VALUE(lhs)); + VALUE_TO_INT(a, ACC); + acc = Encode(l << (a & 0x1f)); MOTH_END_INSTR(Shl) MOTH_BEGIN_INSTR(BitAndConst) - int lhs = VALUEPTR(instr.lhs)->toInt32(); - STOREVALUE(instr.result, QV4::Encode((int)(lhs & instr.rhs))); - MOTH_END_INSTR(BitAnd) + VALUE_TO_INT(a, ACC); + acc = Encode(a & rhs); + CHECK_EXCEPTION; + MOTH_END_INSTR(BitAndConst) MOTH_BEGIN_INSTR(BitOrConst) - int lhs = VALUEPTR(instr.lhs)->toInt32(); - STOREVALUE(instr.result, QV4::Encode((int)(lhs | instr.rhs))); - MOTH_END_INSTR(BitOr) + VALUE_TO_INT(a, ACC); + acc = Encode(a | rhs); + MOTH_END_INSTR(BitOrConst) MOTH_BEGIN_INSTR(BitXorConst) - int lhs = VALUEPTR(instr.lhs)->toInt32(); - STOREVALUE(instr.result, QV4::Encode((int)(lhs ^ instr.rhs))); - MOTH_END_INSTR(BitXor) + VALUE_TO_INT(a, ACC); + acc = Encode(a ^ rhs); + MOTH_END_INSTR(BitXorConst) + + MOTH_BEGIN_INSTR(UShrConst) + acc = Encode(ACC.toUInt32() >> uint(rhs)); + MOTH_END_INSTR(UShrConst) MOTH_BEGIN_INSTR(ShrConst) - STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() >> instr.rhs))); + VALUE_TO_INT(a, ACC); + acc = Encode(a >> rhs); MOTH_END_INSTR(ShrConst) MOTH_BEGIN_INSTR(ShlConst) - STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() << instr.rhs))); + VALUE_TO_INT(a, ACC); + acc = Encode(a << rhs); MOTH_END_INSTR(ShlConst) - MOTH_BEGIN_INSTR(Mul) - STOREVALUE(instr.result, Runtime::method_mul(VALUE(instr.lhs), VALUE(instr.rhs))); - MOTH_END_INSTR(Mul) - - MOTH_BEGIN_INSTR(Sub) - STOREVALUE(instr.result, Runtime::method_sub(VALUE(instr.lhs), VALUE(instr.rhs))); - MOTH_END_INSTR(Sub) - - MOTH_BEGIN_INSTR(BinopContext) - QV4::Runtime::BinaryOperationContext op = *reinterpret_cast<QV4::Runtime::BinaryOperationContext *>(reinterpret_cast<char *>(&engine->runtime.runtimeMethods[instr.alu])); - STOREVALUE(instr.result, op(engine, VALUE(instr.lhs), VALUE(instr.rhs))); - MOTH_END_INSTR(BinopContext) - MOTH_BEGIN_INSTR(Ret) -// TRACE(Ret, "returning value %s", result.toString(context)->toQString().toUtf8().constData()); - return VALUE(instr.result).asReturnedValue(); + goto functionExit; MOTH_END_INSTR(Ret) #if QT_CONFIG(qml_debug) MOTH_BEGIN_INSTR(Debug) - engine->current->lineNumber = instr.lineNumber; - QV4::Debugging::Debugger *debugger = engine->debugger(); - if (debugger && debugger->pauseAtNextOpportunity()) - debugger->maybeBreakAtInstruction(); - if (qt_v4IsDebugging) - qt_v4CheckForBreak(engine->currentContext); + STORE_IP(); + debug_slowPath(engine); MOTH_END_INSTR(Debug) - - MOTH_BEGIN_INSTR(Line) - engine->current->lineNumber = instr.lineNumber; - if (qt_v4IsDebugging) - qt_v4CheckForBreak(engine->currentContext); - MOTH_END_INSTR(Line) #endif // QT_CONFIG(qml_debug) - MOTH_BEGIN_INSTR(LoadThis) - VALUE(instr.result) = engine->currentContext->thisObject(); - MOTH_END_INSTR(LoadThis) - MOTH_BEGIN_INSTR(LoadQmlContext) - VALUE(instr.result) = Runtime::method_getQmlContext(static_cast<QV4::NoThrowEngine*>(engine)); + STACK_VALUE(result) = Runtime::method_loadQmlContext(static_cast<QV4::NoThrowEngine*>(engine)); MOTH_END_INSTR(LoadQmlContext) MOTH_BEGIN_INSTR(LoadQmlImportedScripts) - VALUE(instr.result) = Runtime::method_getQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine)); + STACK_VALUE(result) = Runtime::method_loadQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine)); MOTH_END_INSTR(LoadQmlImportedScripts) MOTH_BEGIN_INSTR(LoadQmlSingleton) - VALUE(instr.result) = Runtime::method_getQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), instr.name); + acc = Runtime::method_loadQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), name); MOTH_END_INSTR(LoadQmlSingleton) -#ifdef MOTH_THREADED_INTERPRETER - // nothing to do -#else - default: - qFatal("QQmlJS::Moth::VME: Internal error - unknown instruction %d", genericInstr->common.instructionType); - break; - } -#endif - - Q_ASSERT(false); catchException: Q_ASSERT(engine->hasException); - if (!exceptionHandler) - return QV4::Encode::undefined(); + if (!exceptionHandler) { + acc = Encode::undefined(); + goto functionExit; + } code = exceptionHandler; } -} + } -QV4::ReturnedValue VME::exec(ExecutionEngine *engine, const uchar *code) -{ - VME vme; - QV4::Debugging::Debugger *debugger = engine->debugger(); - if (debugger) - debugger->enteringFunction(); - QV4::ReturnedValue retVal = vme.run(engine, code); - if (debugger) - debugger->leavingFunction(retVal); - return retVal; +functionExit: + if (QV4::Debugging::Debugger *debugger = engine->debugger()) + debugger->leavingFunction(ACC.asReturnedValue()); + engine->currentStackFrame = frame.parent; + engine->jsStackTop = stack; + + return acc; } |