diff options
author | Lars Knoll <lars.knoll@qt.io> | 2017-10-19 15:21:08 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2017-11-07 07:24:21 +0000 |
commit | 957de0c8fb109ad6938d7a8673164cc94f346ecc (patch) | |
tree | 4cf7161218a31cbf63e55792c0d4df5bd9ad223f /src | |
parent | c8547312d3faf1bd357fe03f4717585e23da7680 (diff) |
Refactor Call/Construct instructions
Give them a pointer to argc and argv instead of a pointer
to a full callData. Like this we can construct the callData
at the end of the JS stack and avoid the need to create an
additional copy in VME::exec().
This also opens up the option of completely avoiding all copies for
calls into runtime methods.
Also make sure that the calldata we pass into other functions is
always at the top of the JS stack.
Change-Id: I3d0eb49f7bfd7adb9ddabb213422087c66e5a520
Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 55 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontext_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth.cpp | 23 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 16 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4arrayobject.cpp | 12 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4global_p.h | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4jscall_p.h | 18 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stringobject.cpp | 9 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 93 |
12 files changed, 152 insertions, 102 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 706f211ae0..331132de3b 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1256,42 +1256,49 @@ bool Codegen::visit(CallExpression *ast) Instruction::CallPropertyLookup call; call.base = base.propertyBase.stackSlot(); call.lookupIndex = registerGetterLookup(base.propertyNameIndex); - call.callData = calldata; + call.argc = calldata.argc; + call.argv = calldata.argv; bytecodeGenerator->addInstruction(call); } else { Instruction::CallProperty call; call.base = base.propertyBase.stackSlot(); call.name = base.propertyNameIndex; - call.callData = calldata; + call.argc = calldata.argc; + call.argv = calldata.argv; bytecodeGenerator->addInstruction(call); } } else if (base.type == Reference::Subscript) { Instruction::CallElement call; call.base = base.elementBase; call.index = base.elementSubscript.stackSlot(); - call.callData = calldata; + call.argc = calldata.argc; + call.argv = calldata.argv; bytecodeGenerator->addInstruction(call); } else if (base.type == Reference::Name) { if (base.name == QStringLiteral("eval")) { Instruction::CallPossiblyDirectEval call; - call.callData = calldata; + call.argc = calldata.argc; + call.argv = calldata.argv; bytecodeGenerator->addInstruction(call); } else if (useFastLookups && base.global) { Instruction::CallGlobalLookup call; call.index = registerGlobalGetterLookup(base.nameAsIndex()); - call.callData = calldata; + call.argc = calldata.argc; + call.argv = calldata.argv; bytecodeGenerator->addInstruction(call); } else { Instruction::CallName call; call.name = base.nameAsIndex(); - call.callData = calldata; + call.argc = calldata.argc; + call.argv = calldata.argv; bytecodeGenerator->addInstruction(call); } } else { base.loadInAccumulator(); Instruction::CallValue call; - call.callData = calldata; + call.argc = calldata.argc; + call.argv = calldata.argv; bytecodeGenerator->addInstruction(call); } @@ -1299,21 +1306,16 @@ bool Codegen::visit(CallExpression *ast) return false; } -Moth::StackSlot Codegen::pushArgs(ArgumentList *args) +Codegen::Arguments Codegen::pushArgs(ArgumentList *args) { int argc = 0; for (ArgumentList *it = args; it; it = it->next) ++argc; - int calldata = bytecodeGenerator->newRegisterArray(sizeof(CallData)/sizeof(Value) - 1 + argc); -#ifndef QT_NO_DEBUG - (void) Reference::fromConst(this, QV4::Encode::undefined()).storeOnStack(calldata + CallData::Function); - (void) Reference::fromConst(this, QV4::Encode::undefined()).storeOnStack(calldata + CallData::Context); - (void) Reference::fromConst(this, QV4::Encode::undefined()).storeOnStack(calldata + CallData::Accumulator); - (void) Reference::fromConst(this, QV4::Encode::undefined()).storeOnStack(calldata + CallData::This); -#endif - (void) Reference::fromConst(this, QV4::Encode(argc)).storeOnStack(calldata + CallData::Argc); - Q_STATIC_ASSERT(sizeof(CallData) == 6 * sizeof(Value)); + if (!argc) + return { 0, 0 }; + + int calldata = bytecodeGenerator->newRegisterArray(argc); argc = 0; for (ArgumentList *it = args; it; it = it->next) { @@ -1321,11 +1323,16 @@ Moth::StackSlot Codegen::pushArgs(ArgumentList *args) Reference e = expression(it->expression); if (hasError) break; - (void) e.storeOnStack(calldata + sizeof(CallData)/sizeof(Value) - 1 + argc); + if (!argc && !it->next) { + // avoid copy for functions taking a single argument + if (e.isStackSlot()) + return { 1, e.stackSlot() }; + } + (void) e.storeOnStack(calldata + argc); ++argc; } - return Moth::StackSlot::createRegister(calldata); + return { argc, calldata }; } bool Codegen::visit(ConditionalExpression *ast) @@ -1581,11 +1588,10 @@ bool Codegen::visit(NewExpression *ast) //### Maybe create a ConstructA that takes an accumulator? base = base.storeOnStack(); - auto calldata = pushArgs(0); - Instruction::Construct create; create.func = base.stackSlot(); - create.callData = calldata; + create.argc = 0; + create.argv = 0; bytecodeGenerator->addInstruction(create); _expr.setResult(Reference::fromAccumulator(this)); return false; @@ -1609,7 +1615,8 @@ bool Codegen::visit(NewMemberExpression *ast) Instruction::Construct create; create.func = base.stackSlot(); - create.callData = calldata; + create.argc = calldata.argc; + create.argv = calldata.argv; bytecodeGenerator->addInstruction(create); _expr.setResult(Reference::fromAccumulator(this)); return false; @@ -2024,8 +2031,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, _context->functionIndex = _module->functions.count() - 1; _context->hasDirectEval |= (_context->compilationMode == EvalCode || _context->compilationMode == GlobalCode || _module->debugMode); // Conditional breakpoints are like eval in the function - // ### still needed? - _context->maxNumberOfArguments = qMax(_context->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount); BytecodeGenerator bytecode(_context->line, _module->debugMode); BytecodeGenerator *savedBytecodeGenerator; diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 881fa08ff8..89c887d46d 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -624,7 +624,8 @@ public: Reference binopHelper(QSOperator::Op oper, Reference &left, Reference &right); Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right); - Moth::StackSlot pushArgs(AST::ArgumentList *args); + struct Arguments { int argc; int argv; }; + Arguments pushArgs(AST::ArgumentList *args); void setUseFastLookups(bool b) { useFastLookups = b; } diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h index f35125e719..0b7ac1fb0c 100644 --- a/src/qml/compiler/qv4compilercontext_p.h +++ b/src/qml/compiler/qv4compilercontext_p.h @@ -216,7 +216,7 @@ struct Context { bool canUseSimpleCall() const { return nestedContexts.isEmpty() && - locals.isEmpty() && arguments.size() <= QV4::Global::ReservedArgumentCount && + locals.isEmpty() && !hasTry && !hasWith && usesArgumentsObject == ArgumentsObjectNotUsed && !hasDirectEval; } diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index ea19233a3d..9cfde99e6b 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -159,6 +159,13 @@ QString dumpRegister(int reg, int nFormals) } +QString dumpArguments(int argc, int argv, int nFormals) +{ + if (!argc) + return QStringLiteral("()"); + return QStringLiteral("(") + dumpRegister(argv, nFormals) + QStringLiteral(", ") + QString::number(argc) + QStringLiteral(")"); +} + void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*startLine*/, const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping) { @@ -335,31 +342,31 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st MOTH_END_INSTR(LoadIdObject) MOTH_BEGIN_INSTR(CallValue) - d << "(" << dumpRegister(callData, nFormals) << ")"; + d << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(CallValue) MOTH_BEGIN_INSTR(CallProperty) - d << dumpRegister(base, nFormals) << "." << name << "(" << dumpRegister(callData, nFormals) << ")"; + d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(CallProperty) MOTH_BEGIN_INSTR(CallPropertyLookup) - d << dumpRegister(base, nFormals) << "." << lookupIndex << "(" << dumpRegister(callData, nFormals) << ")"; + d << dumpRegister(base, nFormals) << "." << lookupIndex << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(CallPropertyLookup) MOTH_BEGIN_INSTR(CallElement) - d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]" << "(" << dumpRegister(callData, nFormals) << ")"; + d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]" << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(CallElement) MOTH_BEGIN_INSTR(CallName) - d << name << "(" << dumpRegister(callData, nFormals) << ")"; + d << name << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(CallName) MOTH_BEGIN_INSTR(CallPossiblyDirectEval) - d << "(" << dumpRegister(callData, nFormals) << ")"; + d << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(CallPossiblyDirectEval) MOTH_BEGIN_INSTR(CallGlobalLookup) - d << index << "(" << dumpRegister(callData, nFormals) << ")"; + d << index << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(CallGlobalLookup) MOTH_BEGIN_INSTR(SetExceptionHandler) @@ -443,7 +450,7 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st MOTH_END_INSTR(ConvertThisToObject) MOTH_BEGIN_INSTR(Construct) - d << "new" << dumpRegister(func, nFormals) << "(" << dumpRegister(callData, nFormals) << ")"; + d << "new" << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(Construct) MOTH_BEGIN_INSTR(Jump) diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index d81762f25b..58d3edf2c4 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -109,13 +109,13 @@ QT_BEGIN_NAMESPACE #define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 2, base, index) #define INSTR_LoadElementA(op) INSTRUCTION(op, LoadElementA, 1, base) #define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 2, base, index) -#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 1, callData) -#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 3, name, callData, base) -#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 3, lookupIndex, callData, base) -#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 3, base, index, callData) -#define INSTR_CallName(op) INSTRUCTION(op, CallName, 2, name, callData) -#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 1, callData) -#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 2, index, callData) +#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 2, argc, argv) +#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 4, name, base, argc, argv) +#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 4, lookupIndex, base, argc, argv) +#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 4, base, index, argc, argv) +#define INSTR_CallName(op) INSTRUCTION(op, CallName, 3, name, argc, argv) +#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 2, argc, argv) +#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv) #define INSTR_SetExceptionHandler(op) INSTRUCTION(op, SetExceptionHandler, 1, offset) #define INSTR_ThrowException(op) INSTRUCTION(op, ThrowException, 0) #define INSTR_GetException(op) INSTRUCTION(op, GetException, 0) @@ -138,7 +138,7 @@ QT_BEGIN_NAMESPACE #define INSTR_CreateMappedArgumentsObject(op) INSTRUCTION(op, CreateMappedArgumentsObject, 0) #define INSTR_CreateUnmappedArgumentsObject(op) INSTRUCTION(op, CreateUnmappedArgumentsObject, 0) #define INSTR_ConvertThisToObject(op) INSTRUCTION(op, ConvertThisToObject, 0) -#define INSTR_Construct(op) INSTRUCTION(op, Construct, 2, callData, func) +#define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv) #define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset) #define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset) #define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 1, offset) diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 5abfe3f8ae..0cf4515cc9 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -791,10 +791,10 @@ ReturnedValue ArrayPrototype::method_every(const BuiltinFunction *b, CallData *c if (!callback) THROW_TYPE_ERROR(); - JSCall jsCall(scope, callback, 3); - jsCall->thisObject = callData->argument(1); ScopedValue r(scope); ScopedValue v(scope); + JSCall jsCall(scope, callback, 3); + jsCall->thisObject = callData->argument(1); bool ok = true; for (uint k = 0; ok && k < len; ++k) { @@ -825,10 +825,10 @@ ReturnedValue ArrayPrototype::method_some(const BuiltinFunction *b, CallData *ca if (!callback) THROW_TYPE_ERROR(); - JSCall jsCall(scope, callback, 3); - jsCall->thisObject = callData->argument(1); ScopedValue v(scope); ScopedValue result(scope); + JSCall jsCall(scope, callback, 3); + jsCall->thisObject = callData->argument(1); for (uint k = 0; k < len; ++k) { bool exists; @@ -859,10 +859,10 @@ ReturnedValue ArrayPrototype::method_forEach(const BuiltinFunction *b, CallData if (!callback) THROW_TYPE_ERROR(); + ScopedValue v(scope); JSCall jsCall(scope, callback, 3); jsCall->thisObject = callData->argument(1); - ScopedValue v(scope); for (uint k = 0; k < len; ++k) { bool exists; v = instance->getIndexed(k, &exists); @@ -894,11 +894,11 @@ ReturnedValue ArrayPrototype::method_map(const BuiltinFunction *b, CallData *cal a->arrayReserve(len); a->setArrayLengthUnchecked(len); + ScopedValue v(scope); ScopedValue mapped(scope); JSCall jsCall(scope, callback, 3); jsCall->thisObject = callData->argument(1); - ScopedValue v(scope); for (uint k = 0; k < len; ++k) { bool exists; v = instance->getIndexed(k, &exists); diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 36c5c4441a..716678d2f8 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -305,6 +305,7 @@ ReturnedValue FunctionPrototype::method_apply(const BuiltinFunction *b, CallData return v4->throwTypeError(); } else { callData->setArgc(0); + v4->jsStackTop = callData->args; } return o->call(callData); @@ -312,16 +313,19 @@ ReturnedValue FunctionPrototype::method_apply(const BuiltinFunction *b, CallData ReturnedValue FunctionPrototype::method_call(const BuiltinFunction *b, CallData *callData) { - if (!callData->thisObject.isFunctionObject()) { - ExecutionEngine *e = b->engine(); - return e->throwTypeError(); - } + ExecutionEngine *engine = b->engine(); + if (!callData->thisObject.isFunctionObject()) + return engine->throwTypeError(); + + Q_ASSERT(engine->jsStackTop == callData->args + callData->argc()); + callData->function = callData->thisObject; callData->thisObject = callData->argc() ? callData->args[0] : Primitive::undefinedValue(); if (callData->argc()) { callData->setArgc(callData->argc() - 1); for (int i = 0, ei = callData->argc(); i < ei; ++i) callData->args[i] = callData->args[i + 1]; + --engine->jsStackTop; } return static_cast<FunctionObject &>(callData->function).call(callData); } @@ -354,12 +358,12 @@ ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData) const ScriptFunction *f = static_cast<const ScriptFunction *>(that); InternalClass *ic = f->classForConstructor(); + callData->context = f->scope(); callData->thisObject = v4->memoryManager->allocObject<Object>(ic); QV4::Function *v4Function = f->function(); Q_ASSERT(v4Function); - callData->context = f->scope(); ReturnedValue result = v4Function->call(callData); if (Q_UNLIKELY(v4->hasException)) diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 4c5e3c4e5e..6bdeda3313 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -248,12 +248,6 @@ struct IdentifierTable; class RegExpCache; class MultiplyWrappedQObjectMap; -namespace Global { - enum { - ReservedArgumentCount = 6 - }; -} - enum PropertyFlag { Attr_Data = 0, Attr_Accessor = 0x1, diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h index 8fd6119102..18dfdc102b 100644 --- a/src/qml/jsruntime/qv4jscall_p.h +++ b/src/qml/jsruntime/qv4jscall_p.h @@ -63,24 +63,36 @@ namespace QV4 { struct JSCall { JSCall(const Scope &scope, std::nullptr_t, int argc = 0) { - int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + qMax(argc , int(QV4::Global::ReservedArgumentCount)); + int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc; ptr = reinterpret_cast<CallData *>(scope.alloc(size)); ptr->setArgc(argc); } JSCall(const Scope &scope, const FunctionObject *function, int argc = 0) { - int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + qMax(argc , int(QV4::Global::ReservedArgumentCount)); + int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc; ptr = reinterpret_cast<CallData *>(scope.alloc(size)); ptr->setArgc(argc); ptr->function = *function; } JSCall(const Scope &scope, Heap::FunctionObject *function, int argc = 0) { - int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + qMax(argc , int(QV4::Global::ReservedArgumentCount)); + int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc; ptr = reinterpret_cast<CallData *>(scope.alloc(size)); ptr->setArgc(argc); ptr->function = function; } + JSCall(const Scope &scope, Value *argv, int argc, Value *thisObject = 0) + { + int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc; + ptr = reinterpret_cast<CallData *>(scope.engine->jsStackTop); + scope.engine->jsStackTop += size; + ptr->function = Encode::undefined(); + ptr->context = Encode::undefined(); + ptr->accumulator = Encode::undefined(); + ptr->thisObject = thisObject ? thisObject->asReturnedValue() : Encode::undefined(); + ptr->setArgc(argc); + memcpy(ptr->args, argv, argc*sizeof(Value)); + } CallData *operator->() { return ptr; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 97b0c5259f..7bc2315610 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -426,10 +426,11 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH qSwap(meth1, meth2); Scope scope(engine); + ScopedValue conv(scope, object->get(meth1)); + JSCall jsCall(scope, nullptr, 0); jsCall->thisObject = *object; - ScopedValue conv(scope, object->get(meth1)); if (FunctionObject *o = conv->as<FunctionObject>()) { jsCall->function = o; jsCall->accumulator = jsCall.call(); diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 9e03913730..b1ce0b0115 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -405,14 +405,17 @@ ReturnedValue StringPrototype::method_match(const BuiltinFunction *b, CallData * if (callData->thisObject.isNullOrUndefined()) return v4->throwTypeError(); - Scope scope(v4); - callData->thisObject = callData->thisObject.toString(scope.engine); + callData->thisObject = callData->thisObject.toString(v4); if (v4->hasException) return Encode::undefined(); + Q_ASSERT(v4->jsStackTop == callData->args + callData->argc()); if (!callData->argc()) callData->args[0] = Encode::undefined(); callData->setArgc(1); + v4->jsStackTop = callData->args + 1; + + Scope scope(v4); if (!callData->args[0].as<RegExpObject>()) { // convert args[0] to a regexp @@ -579,10 +582,10 @@ ReturnedValue StringPrototype::method_replace(const BuiltinFunction *b, CallData ScopedFunctionObject searchCallback(scope, replaceValue); if (!!searchCallback) { result.reserve(string.length() + 10*numStringMatches); + ScopedValue entry(scope); JSCall jsCall(scope, searchCallback, numCaptures + 2); jsCall->thisObject = Primitive::undefinedValue(); int lastEnd = 0; - ScopedValue entry(scope); for (int i = 0; i < numStringMatches; ++i) { for (int k = 0; k < numCaptures; ++k) { int idx = (i * numCaptures + k) * 2; diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index b3b9842ba9..3e9f329c9a 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -54,6 +54,7 @@ #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> @@ -509,14 +510,15 @@ QV4::ReturnedValue VME::exec(CallData *callData, QV4::Function *function) Value *jsStackTop = engine->jsStackTop; - Q_ASSERT(engine->jsStackTop >= callData->args + callData->argc() - 1); - Value *stack = engine->jsStackTop; - engine->jsStackTop += sizeof(CallData)/sizeof(Value) - 1 + qMax(callData->argc(), int(function->compiledFunction->nRegisters)); - memcpy(stack, callData, sizeof(CallData) - sizeof(Value) + callData->argc()*sizeof(Value)); - // clear out remaining arguments and local registers - callData = reinterpret_cast<CallData *>(stack); - for (Value *v = callData->args + callData->argc(); v < engine->jsStackTop; ++v) - *v = Encode::undefined(); + Q_ASSERT(engine->jsStackTop == callData->args + callData->argc()); + Value *stack = reinterpret_cast<Value *>(callData); + int stackSpaceToAdd = int(function->compiledFunction->nRegisters) - callData->argc(); + if (stackSpaceToAdd > 0) { + // clear out remaining arguments and local registers + for (int i = 0; i < stackSpaceToAdd; ++i) + engine->jsStackTop[i] = Encode::undefined(); + engine->jsStackTop += stackSpaceToAdd; + } CppStackFrame frame; frame.parent = engine->currentStackFrame; @@ -743,60 +745,78 @@ QV4::ReturnedValue VME::exec(CallData *callData, QV4::Function *function) MOTH_BEGIN_INSTR(CallValue) STORE_IP(); STORE_ACC(); - QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData); - Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop); - acc = Runtime::method_callValue(engine, accumulator, cData); + { + Scope scope(engine); + JSCall cData(scope, stack + argv, argc); + Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop); + acc = Runtime::method_callValue(engine, accumulator, cData); + } CHECK_EXCEPTION; MOTH_END_INSTR(CallValue) MOTH_BEGIN_INSTR(CallProperty) STORE_IP(); - QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData); - Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop); - cData->thisObject = STACK_VALUE(base); - acc = Runtime::method_callProperty(engine, name, cData); + { + Scope scope(engine); + JSCall cData(scope, stack + argv, argc, stack + base); + Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop); + acc = Runtime::method_callProperty(engine, name, cData); + } CHECK_EXCEPTION; MOTH_END_INSTR(CallProperty) MOTH_BEGIN_INSTR(CallPropertyLookup) STORE_IP(); - QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData); - Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop); - cData->thisObject = STACK_VALUE(base); - acc = Runtime::method_callPropertyLookup(engine, lookupIndex, cData); + { + Scope scope(engine); + JSCall cData(scope, stack + argv, argc, stack + base); + Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop); + acc = Runtime::method_callPropertyLookup(engine, lookupIndex, cData); + } CHECK_EXCEPTION; MOTH_END_INSTR(CallPropertyLookup) MOTH_BEGIN_INSTR(CallElement) STORE_IP(); - QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData); - Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop); - cData->thisObject = STACK_VALUE(base); - acc = Runtime::method_callElement(engine, STACK_VALUE(index), cData); + { + Scope scope(engine); + JSCall cData(scope, stack + argv, argc, stack + base); + Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop); + acc = Runtime::method_callElement(engine, STACK_VALUE(index), cData); + } CHECK_EXCEPTION; MOTH_END_INSTR(CallElement) MOTH_BEGIN_INSTR(CallName) STORE_IP(); - QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData); - Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop); - acc = Runtime::method_callName(engine, name, cData); + { + Scope scope(engine); + JSCall cData(scope, stack + argv, argc); + Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop); + acc = Runtime::method_callName(engine, name, cData); + } CHECK_EXCEPTION; MOTH_END_INSTR(CallName) MOTH_BEGIN_INSTR(CallPossiblyDirectEval) STORE_IP(); - QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData); - Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop); - acc = Runtime::method_callPossiblyDirectEval(engine, cData); + { + Scope scope(engine); + JSCall cData(scope, stack + argv, argc); + Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop); + acc = Runtime::method_callPossiblyDirectEval(engine, cData); + } CHECK_EXCEPTION; MOTH_END_INSTR(CallPossiblyDirectEval) MOTH_BEGIN_INSTR(CallGlobalLookup) STORE_IP(); - QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData); - Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop); - acc = Runtime::method_callGlobalLookup(engine, index, cData); + { + Scope scope(engine); + JSCall cData(scope, stack + argv, argc); + Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop); + acc = Runtime::method_callGlobalLookup(engine, index, cData); + } CHECK_EXCEPTION; MOTH_END_INSTR(CallGlobalLookup) @@ -943,9 +963,12 @@ QV4::ReturnedValue VME::exec(CallData *callData, QV4::Function *function) MOTH_BEGIN_INSTR(Construct) STORE_IP(); - QV4::CallData *cData = reinterpret_cast<QV4::CallData *>(stack + callData); - Q_ASSERT(cData->args + cData->argc() <= engine->jsStackTop); - acc = Runtime::method_construct(engine, STACK_VALUE(func), cData); + { + Scope scope(engine); + JSCall cData(scope, stack + argv, argc); + Q_ASSERT(cData->args + cData->argc() == engine->jsStackTop); + acc = Runtime::method_construct(engine, STACK_VALUE(func), cData); + } CHECK_EXCEPTION; MOTH_END_INSTR(Construct) |