From b1f07986c30978ed6636457e8d3f4a65c5db38a3 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 15 Oct 2018 10:22:47 +0200 Subject: Create proper template objects for tagged templates If a tagged template gets evaluated multiple times, the underlying template object is shared. Change-Id: Ie2f476fbc93d5991322ce1087c42719a8d8333ae Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4bytecodehandler.cpp | 3 + src/qml/compiler/qv4codegen.cpp | 78 +++++-------------------- src/qml/compiler/qv4codegen_p.h | 2 +- src/qml/compiler/qv4compileddata.cpp | 34 +++++++++++ src/qml/compiler/qv4compileddata_p.h | 42 ++++++++++++- src/qml/compiler/qv4compiler.cpp | 53 ++++++++++++++++- src/qml/compiler/qv4compiler_p.h | 2 + src/qml/compiler/qv4compilercontext_p.h | 9 +++ src/qml/compiler/qv4instr_moth.cpp | 4 ++ src/qml/compiler/qv4instr_moth_p.h | 2 + src/qml/jit/qv4baselinejit.cpp | 9 +++ src/qml/jit/qv4baselinejit_p.h | 1 + src/qml/jsruntime/qv4runtime.cpp | 6 ++ src/qml/jsruntime/qv4runtime_p.h | 2 + src/qml/jsruntime/qv4vme_moth.cpp | 4 ++ tests/auto/qml/ecmascripttests/TestExpectations | 8 +-- 16 files changed, 183 insertions(+), 76 deletions(-) diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp index 9cf96d27f3..af86b70014 100644 --- a/src/qml/compiler/qv4bytecodehandler.cpp +++ b/src/qml/compiler/qv4bytecodehandler.cpp @@ -537,6 +537,9 @@ std::vector ByteCodeHandler::collectLabelsInBytecode(const char *code, uint COLLECTOR_BEGIN_INSTR(ThrowOnNullOrUndefined) COLLECTOR_END_INSTR(ThrowOnNullOrUndefined) + COLLECTOR_BEGIN_INSTR(GetTemplateObject) + COLLECTOR_END_INSTR(GetTemplateObject) + COLLECTOR_BEGIN_INSTR(LoadQmlContext) COLLECTOR_END_INSTR(LoadQmlContext) diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index ac596e2b5b..09c0e60f4d 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2243,85 +2243,35 @@ bool Codegen::visit(TaggedTemplate *ast) break; } - int arrayTemp = createTemplateArray(ast->templateLiteral); - Q_UNUSED(arrayTemp); + createTemplateObject(ast->templateLiteral); + int templateObjectTemp = Reference::fromAccumulator(this).storeOnStack().stackSlot(); + Q_UNUSED(templateObjectTemp); auto calldata = pushTemplateArgs(ast->templateLiteral); if (hasError) return false; ++calldata.argc; - Q_ASSERT(calldata.argv == arrayTemp + 1); + Q_ASSERT(calldata.argv == templateObjectTemp + 1); --calldata.argv; handleCall(base, calldata, functionObject, thisObject); return false; } -int Codegen::createTemplateArray(TemplateLiteral *t) +void Codegen::createTemplateObject(TemplateLiteral *t) { - int arrayTemp = bytecodeGenerator->newRegister(); + TemplateObject obj; - int argc = 0; - int args = -1; - auto push = [this, &argc, &args](const QStringRef &arg) { - int temp = bytecodeGenerator->newRegister(); - if (args == -1) - args = temp; - Instruction::LoadRuntimeString instr; - instr.stringId = registerString(arg.toString()); - bytecodeGenerator->addInstruction(instr); - Instruction::StoreReg store; - store.reg = temp; - bytecodeGenerator->addInstruction(store); - - ++argc; - }; - - { - RegisterScope scope(this); - - for (TemplateLiteral *it = t; it; it = it->next) - push(it->value); - - if (args == -1) { - Q_ASSERT(argc == 0); - args = 0; - } - - Instruction::DefineArray call; - call.argc = argc; - call.args = Moth::StackSlot::createRegister(args); - bytecodeGenerator->addInstruction(call); - - Instruction::StoreReg store; - store.reg = arrayTemp; - bytecodeGenerator->addInstruction(store); + for (TemplateLiteral *it = t; it; it = it->next) { + obj.strings.append(registerString(it->value.toString())); + obj.rawStrings.append(registerString(it->rawValue.toString())); } - { - RegisterScope scope(this); - - argc = 0; - args = -1; - - for (TemplateLiteral *it = t; it; it = it->next) - push(it->rawValue); - - if (args == -1) { - Q_ASSERT(argc == 0); - args = 0; - } - - Instruction::DefineArray call; - call.argc = argc; - call.args = Moth::StackSlot::createRegister(args); - bytecodeGenerator->addInstruction(call); - - Reference a = Reference::fromStackSlot(this, arrayTemp); - Reference m = Reference::fromMember(a, QStringLiteral("raw")); - m.storeConsumeAccumulator(); - } + int index = _module->templateObjects.size(); + _module->templateObjects.append(obj); - return arrayTemp; + Instruction::GetTemplateObject getTemplateObject; + getTemplateObject.index = index; + bytecodeGenerator->addInstruction(getTemplateObject); } bool Codegen::visit(FunctionExpression *ast) diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index e6e7d2e9fb..0bc04750f7 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -682,7 +682,7 @@ public: void handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject); Arguments pushTemplateArgs(AST::TemplateLiteral *args); - int createTemplateArray(AST::TemplateLiteral *t); + void createTemplateObject(AST::TemplateLiteral *t); void setUseFastLookups(bool b) { useFastLookups = b; } diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 244e762faf..3b2d6e0a48 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -225,6 +225,36 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) return nullptr; } +Heap::Object *CompilationUnit::templateObjectAt(int index) const +{ + Q_ASSERT(index < int(data->templateObjectTableSize)); + if (!templateObjects.size()) + templateObjects.resize(data->templateObjectTableSize); + Heap::Object *o = templateObjects.at(index); + if (o) + return o; + + // create the template object + Scope scope(engine); + const CompiledData::TemplateObject *t = data->templateObjectAt(index); + Scoped a(scope, engine->newArrayObject(t->size)); + Scoped raw(scope, engine->newArrayObject(t->size)); + ScopedValue s(scope); + for (uint i = 0; i < t->size; ++i) { + s = runtimeStrings[t->stringIndexAt(i)]; + a->arraySet(i, s); + s = runtimeStrings[t->rawStringIndexAt(i)]; + raw->arraySet(i, s); + } + + ObjectPrototype::method_freeze(engine->functionCtor(), nullptr, raw, 1); + a->defineReadonlyProperty(QStringLiteral("raw"), raw); + ObjectPrototype::method_freeze(engine->functionCtor(), nullptr, a, 1); + + templateObjects[index] = a->objectValue()->d(); + return templateObjects.at(index); +} + void CompilationUnit::unlink() { if (engine) @@ -284,6 +314,10 @@ void CompilationUnit::markObjects(QV4::MarkStack *markStack) if (c) c->mark(markStack); + for (QV4::Heap::Object *o : qAsConst(templateObjects)) + if (o) + o->mark(markStack); + if (runtimeLookups) { for (uint i = 0; i < data->lookupTableSize; ++i) runtimeLookups[i].markObjects(markStack); diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index b36b1a91ea..d0785c6883 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -373,6 +373,34 @@ struct Class }; static_assert(sizeof(Class) == 24, "Class structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); +struct TemplateObject +{ + quint32_le size; + + static int calculateSize(int size) { + int trailingData = 2 * size * sizeof(quint32_le); + size_t s = align(sizeof(TemplateObject) + trailingData); + Q_ASSERT(s < INT_MAX); + return int(s); + } + + static size_t align(size_t a) { + return (a + 7) & ~size_t(7); + } + + const quint32_le *stringTable() const { + return reinterpret_cast(reinterpret_cast(this + 1)); + } + + uint stringIndexAt(uint i) const { + return stringTable()[i]; + } + uint rawStringIndexAt(uint i) const { + return stringTable()[size + i]; + } +}; +static_assert(sizeof(TemplateObject) == 4, "Template object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); + struct ExportEntry { quint32_le exportName; @@ -841,6 +869,8 @@ struct Unit quint32_le offsetToFunctionTable; quint32_le classTableSize; quint32_le offsetToClassTable; + quint32_le templateObjectTableSize; + quint32_le offsetToTemplateObjectTable; quint32_le blockTableSize; quint32_le offsetToBlockTable; quint32_le lookupTableSize; @@ -908,6 +938,7 @@ struct Unit const quint32_le *functionOffsetTable() const { return reinterpret_cast((reinterpret_cast(this)) + offsetToFunctionTable); } const quint32_le *classOffsetTable() const { return reinterpret_cast((reinterpret_cast(this)) + offsetToClassTable); } + const quint32_le *templateObjectOffsetTable() const { return reinterpret_cast((reinterpret_cast(this)) + offsetToTemplateObjectTable); } const quint32_le *blockOffsetTable() const { return reinterpret_cast((reinterpret_cast(this)) + offsetToBlockTable); } const Function *functionAt(int idx) const { @@ -922,6 +953,12 @@ struct Unit return reinterpret_cast(reinterpret_cast(this) + offset); } + const TemplateObject *templateObjectAt(int idx) const { + const quint32_le *offsetTable = templateObjectOffsetTable(); + const quint32_le offset = offsetTable[idx]; + return reinterpret_cast(reinterpret_cast(this) + offset); + } + const Block *blockAt(int idx) const { const quint32_le *offsetTable = blockOffsetTable(); const quint32_le offset = offsetTable[idx]; @@ -957,7 +994,7 @@ struct Unit const quint32_le *moduleRequestTable() const { return reinterpret_cast((reinterpret_cast(this)) + offsetToModuleRequestTable); } }; -static_assert(sizeof(Unit) == 240, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); +static_assert(sizeof(Unit) == 248, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); struct TypeReference { @@ -1110,6 +1147,7 @@ public: QV4::Lookup *runtimeLookups = nullptr; QVector runtimeFunctions; QVector runtimeBlocks; + mutable QVector templateObjects; mutable QQmlNullableValue m_url; mutable QQmlNullableValue m_finalUrl; @@ -1160,6 +1198,8 @@ public: return data->stringAtInternal(index); } + Heap::Object *templateObjectAt(int index) const; + struct FunctionIterator { FunctionIterator(const Unit *unit, const Object *object, int index) : unit(unit), object(object), index(index) {} diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 7636baa1e6..3076c6b526 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -269,7 +269,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO registerString(request); } - Q_ALLOCA_VAR(quint32_le, blockClassAndFunctionOffsets, (module->functions.size() + module->classes.size() + module->blocks.size()) * sizeof(quint32_le)); + Q_ALLOCA_VAR(quint32_le, blockClassAndFunctionOffsets, (module->functions.size() + module->classes.size() + module->templateObjects.size() + module->blocks.size()) * sizeof(quint32_le)); uint jsClassDataOffset = 0; char *dataPtr; @@ -284,7 +284,8 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO memcpy(dataPtr + unit->offsetToFunctionTable, blockClassAndFunctionOffsets, unit->functionTableSize * sizeof(quint32_le)); memcpy(dataPtr + unit->offsetToClassTable, blockClassAndFunctionOffsets + unit->functionTableSize, unit->classTableSize * sizeof(quint32_le)); - memcpy(dataPtr + unit->offsetToBlockTable, blockClassAndFunctionOffsets + unit->functionTableSize + unit->classTableSize, unit->blockTableSize * sizeof(quint32_le)); + memcpy(dataPtr + unit->offsetToTemplateObjectTable, blockClassAndFunctionOffsets + unit->functionTableSize + unit->classTableSize, unit->templateObjectTableSize * sizeof(quint32_le)); + memcpy(dataPtr + unit->offsetToBlockTable, blockClassAndFunctionOffsets + unit->functionTableSize + unit->classTableSize + unit->templateObjectTableSize, unit->blockTableSize * sizeof(quint32_le)); for (int i = 0; i < module->functions.size(); ++i) { Context *function = module->functions.at(i); @@ -300,10 +301,16 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO writeClass(dataPtr + blockClassAndFunctionOffsets[i + module->functions.size()], c); } + for (int i = 0; i < module->templateObjects.size(); ++i) { + const TemplateObject &t = module->templateObjects.at(i); + + writeTemplateObject(dataPtr + blockClassAndFunctionOffsets[i + module->functions.size() + module->classes.size()], t); + } + for (int i = 0; i < module->blocks.size(); ++i) { Context *block = module->blocks.at(i); - writeBlock(dataPtr + blockClassAndFunctionOffsets[i + module->classes.size() + module->functions.size()], block); + writeBlock(dataPtr + blockClassAndFunctionOffsets[i + module->classes.size() + module->templateObjects.size() + module->functions.size()], block); } CompiledData::Lookup *lookupsToWrite = reinterpret_cast(dataPtr + unit->offsetToLookupTable); @@ -532,6 +539,34 @@ void QV4::Compiler::JSUnitGenerator::writeClass(char *b, const QV4::Compiler::Cl } } +void QV4::Compiler::JSUnitGenerator::writeTemplateObject(char *b, const QV4::Compiler::TemplateObject &t) +{ + QV4::CompiledData::TemplateObject *tmpl = reinterpret_cast(b); + tmpl->size = t.strings.size(); + + quint32 currentOffset = sizeof(QV4::CompiledData::TemplateObject); + + quint32_le *strings = reinterpret_cast(b + currentOffset); + + // write methods + for (int i = 0; i < t.strings.size(); ++i) + strings[i] = t.strings.at(i); + strings += t.strings.size(); + + for (int i = 0; i < t.rawStrings.size(); ++i) + strings[i] = t.rawStrings.at(i); + + static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE"); + if (showCode) { + qDebug() << "=== TemplateObject size" << tmpl->size; + for (uint i = 0; i < tmpl->size; ++i) { + qDebug() << " " << i << stringForIndex(tmpl->stringIndexAt(i)); + qDebug() << " raw: " << stringForIndex(tmpl->rawStringIndexAt(i)); + } + qDebug(); + } +} + void QV4::Compiler::JSUnitGenerator::writeBlock(char *b, QV4::Compiler::Context *irBlock) const { QV4::CompiledData::Block *block = reinterpret_cast(b); @@ -580,6 +615,10 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp unit.offsetToClassTable = nextOffset; nextOffset += unit.classTableSize * sizeof(uint); + unit.templateObjectTableSize = module->templateObjects.size(); + unit.offsetToTemplateObjectTable = nextOffset; + nextOffset += unit.templateObjectTableSize * sizeof(uint); + unit.blockTableSize = module->blocks.size(); unit.offsetToBlockTable = nextOffset; nextOffset += unit.blockTableSize * sizeof(uint); @@ -658,6 +697,14 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp } blockAndFunctionOffsets += module->classes.size(); + for (int i = 0; i < module->templateObjects.size(); ++i) { + const TemplateObject &t = module->templateObjects.at(i); + blockAndFunctionOffsets[i] = nextOffset; + + nextOffset += QV4::CompiledData::TemplateObject::calculateSize(t.strings.size()); + } + blockAndFunctionOffsets += module->templateObjects.size(); + for (int i = 0; i < module->blocks.size(); ++i) { Context *c = module->blocks.at(i); blockAndFunctionOffsets[i] = nextOffset; diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h index c4c886ffad..2f5889ab53 100644 --- a/src/qml/compiler/qv4compiler_p.h +++ b/src/qml/compiler/qv4compiler_p.h @@ -73,6 +73,7 @@ struct JSClassMember; namespace Compiler { struct Class; +struct TemplateObject; struct Q_QML_PRIVATE_EXPORT StringTableGenerator { StringTableGenerator(); @@ -137,6 +138,7 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator { QV4::CompiledData::Unit *generateUnit(GeneratorOption option = GenerateWithStringTable); void writeFunction(char *f, Context *irFunction) const; void writeClass(char *f, const Class &c); + void writeTemplateObject(char *f, const TemplateObject &o); void writeBlock(char *f, Context *irBlock) const; StringTableGenerator stringTable; diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h index d36ef0f447..328715da07 100644 --- a/src/qml/compiler/qv4compilercontext_p.h +++ b/src/qml/compiler/qv4compilercontext_p.h @@ -99,6 +99,14 @@ struct Class { QVector methods; }; +struct TemplateObject { + QVector strings; + QVector rawStrings; + bool operator==(const TemplateObject &other) { + return strings == other.strings && rawStrings == other.rawStrings; + } +}; + struct ExportEntry { QString exportName; @@ -133,6 +141,7 @@ struct Module { QList functions; QList blocks; QVector classes; + QVector templateObjects; Context *rootContext; QString fileName; QString finalUrl; diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index eed8ffe6b8..6edf5a4ae7 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -712,6 +712,10 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st MOTH_BEGIN_INSTR(ThrowOnNullOrUndefined) MOTH_END_INSTR(ThrowOnNullOrUndefined) + MOTH_BEGIN_INSTR(GetTemplateObject) + d << index; + MOTH_END_INSTR(GetTemplateObject) + MOTH_BEGIN_INSTR(LoadQmlContext) d << dumpRegister(result, nFormals); MOTH_END_INSTR(LoadQmlContext) diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 2b1660ee58..2ca8f692b8 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -198,6 +198,7 @@ QT_BEGIN_NAMESPACE #define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result) #define INSTR_InitializeBlockDeadTemporalZone(op) INSTRUCTION(op, InitializeBlockDeadTemporalZone, 2, firstReg, count) #define INSTR_ThrowOnNullOrUndefined(op) INSTRUCTION(op, ThrowOnNullOrUndefined, 0) +#define INSTR_GetTemplateObject(op) INSTRUCTION(op, GetTemplateObject, 1, index) #define INSTR_TailCall(op) INSTRUCTION(op, TailCall, 4, func, thisObject, argc, argv) #define FOR_EACH_MOTH_INSTR_ALL(F) \ @@ -339,6 +340,7 @@ QT_BEGIN_NAMESPACE F(PopScriptContext) \ F(InitializeBlockDeadTemporalZone) \ F(ThrowOnNullOrUndefined) \ + F(GetTemplateObject) \ F(TailCall) \ F(Debug) \ diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp index 6bc1ca6e45..098bbfc6c6 100644 --- a/src/qml/jit/qv4baselinejit.cpp +++ b/src/qml/jit/qv4baselinejit.cpp @@ -992,6 +992,15 @@ void BaselineJIT::generate_ThrowOnNullOrUndefined() as->checkException(); } +void BaselineJIT::generate_GetTemplateObject(int index) +{ + STORE_ACC(); + as->prepareCallWithArgCount(2); + as->passInt32AsArg(index, 1); + as->passFunctionAsArg(0); + BASELINEJIT_GENERATE_RUNTIME_CALL(RuntimeHelpers::getTemplateObject, CallResultDestination::InAccumulator); + as->checkException(); +} void BaselineJIT::startInstruction(Instr::Type /*instr*/) { diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h index 47ad274d23..98d23f4517 100644 --- a/src/qml/jit/qv4baselinejit_p.h +++ b/src/qml/jit/qv4baselinejit_p.h @@ -215,6 +215,7 @@ public: void generate_LoadQmlImportedScripts(int result) override; void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override; void generate_ThrowOnNullOrUndefined() override; + void generate_GetTemplateObject(int index) override; void startInstruction(Moth::Instr::Type instr) override; void endInstruction(Moth::Instr::Type instr) override; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index b576bb4d87..13244fdd95 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -595,6 +595,12 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu return Encode(x + y); } +ReturnedValue RuntimeHelpers::getTemplateObject(Function *function, int index) +{ + return function->compilationUnit->templateObjectAt(index)->asReturnedValue(); +} + + void Runtime::method_storeProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value) { Scope scope(engine); diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 72af90d1dc..2be3ebf012 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -114,6 +114,8 @@ struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { static Bool strictEqual(const Value &x, const Value &y); static ReturnedValue addHelper(ExecutionEngine *engine, const Value &left, const Value &right); + + static ReturnedValue getTemplateObject(Function *function, int index); }; diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 1cca50f6c1..5208894934 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -1378,6 +1378,10 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, } MOTH_END_INSTR(ThrowOnNullOrUndefined) + MOTH_BEGIN_INSTR(GetTemplateObject) + acc = RuntimeHelpers::getTemplateObject(function, index); + MOTH_END_INSTR(GetTemplateObject) + MOTH_BEGIN_INSTR(Debug) #if QT_CONFIG(qml_debug) STORE_IP(); diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index dddf5ace86..81f9318cdc 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -567,15 +567,9 @@ language/expressions/prefix-increment/S11.4.4_A5_T3.js sloppyFails language/expressions/prefix-increment/S11.4.4_A5_T4.js sloppyFails language/expressions/prefix-increment/S11.4.4_A5_T5.js fails language/expressions/prefix-increment/S11.4.4_A6_T3.js fails -language/expressions/tagged-template/cache-different-functions-same-site.js fails -language/expressions/tagged-template/cache-eval-inner-function.js fails -language/expressions/tagged-template/cache-same-site-top-level.js fails -language/expressions/tagged-template/cache-same-site.js fails +language/expressions/tagged-template/cache-eval-inner-function.js strictFails language/expressions/tagged-template/invalid-escape-sequences.js fails language/expressions/tagged-template/tco-member.js strictFails -language/expressions/tagged-template/template-object-frozen-non-strict.js sloppyFails -language/expressions/tagged-template/template-object-frozen-strict.js strictFails -language/expressions/tagged-template/template-object.js fails language/function-code/each-param-has-own-non-shared-eval-scope.js sloppyFails language/function-code/each-param-has-own-scope.js sloppyFails language/function-code/eval-param-env-with-computed-key.js sloppyFails -- cgit v1.2.3