aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4module.cpp
diff options
context:
space:
mode:
authorJüri Valdmann <juri.valdmann@qt.io>2018-10-12 16:56:14 +0200
committerJani Heikkinen <jani.heikkinen@qt.io>2018-11-02 16:44:11 +0000
commit627226520a2bbb977ce32a21bdffd2004cb28796 (patch)
treee3989c73887505a179e875baf2984be10fcbdda8 /src/qml/jsruntime/qv4module.cpp
parentf20839aed0f2e4fe9134a239adda4853d7bd204a (diff)
Expose let/const variables from imported JS scripts
This patch allows QML to access let/const variables defined in JS files. Detailed changes: - The recently added ContextType::ScriptImportedByQML is changed to avoid creating Push/PopScriptContext instructions, similar to ContextType::ESModule. - QV4::Module is changed to also work with CompilationUnits which are not ESModules. In this case QV4::Module will behave as if all lexically scoped variables were exported. - CompilationUnit is changed to support instantiating and evaluating QV4::Modules for non-ESModules as well. - QQmlTypeLoader is changed to always create QV4::Modules for evaluating scripts. For the non-ESModule case, the QV4::Module is evaluated inside a QV4::QmlContext, as before. - A pointer to the QV4::Module is added to QV4::QQmlContextWrapper, and used in virtualGet to access the let/const variables in the CallContext. Access is read-only. Fixes: QTBUG-69408 Change-Id: I6f299363fdf5e1c5a4a0f1d9e655b4dc5112dd00 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4module.cpp')
-rw-r--r--src/qml/jsruntime/qv4module.cpp77
1 files changed, 61 insertions, 16 deletions
diff --git a/src/qml/jsruntime/qv4module.cpp b/src/qml/jsruntime/qv4module.cpp
index 19a036374f..237ada8321 100644
--- a/src/qml/jsruntime/qv4module.cpp
+++ b/src/qml/jsruntime/qv4module.cpp
@@ -46,6 +46,8 @@
#include <private/qv4symbol_p.h>
#include <private/qv4identifiertable_p.h>
+#include <QScopeGuard>
+
using namespace QV4;
DEFINE_OBJECT_VTABLE(Module);
@@ -98,20 +100,60 @@ void Heap::Module::init(ExecutionEngine *engine, CompiledData::CompilationUnit *
This->setPrototypeUnchecked(nullptr);
}
+void Module::evaluate()
+{
+ if (d()->evaluated)
+ return;
+ d()->evaluated = true;
+
+ CompiledData::CompilationUnit *unit = d()->unit;
+
+ unit->evaluateModuleRequests();
+
+ ExecutionEngine *v4 = engine();
+ Function *moduleFunction = unit->runtimeFunctions[unit->data->indexOfRootFunction];
+ CppStackFrame frame;
+ frame.init(v4, moduleFunction, nullptr, 0);
+ frame.setupJSFrame(v4->jsStackTop, Value::undefinedValue(), d()->scope,
+ Value::undefinedValue(), Value::undefinedValue());
+
+ frame.push();
+ v4->jsStackTop += frame.requiredJSStackFrameSize();
+ auto frameCleanup = qScopeGuard([&frame]() {
+ frame.pop();
+ });
+ Moth::VME::exec(&frame, v4);
+}
+
+const Value *Module::resolveExport(PropertyKey id) const
+{
+ if (d()->unit->isESModule()) {
+ if (!id.isString())
+ return nullptr;
+ Scope scope(engine());
+ ScopedString name(scope, id.asStringOrSymbol());
+ return d()->unit->resolveExport(name);
+ } else {
+ InternalClassEntry entry = d()->scope->internalClass->find(id);
+ if (entry.isValid())
+ return &d()->scope->locals[entry.index];
+ return nullptr;
+ }
+}
+
ReturnedValue Module::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
{
if (id.isSymbol())
return Object::virtualGet(m, id, receiver, hasProperty);
const Module *module = static_cast<const Module *>(m);
- Scope scope(m->engine());
- ScopedString expectedName(scope, id.toStringOrSymbol(scope.engine));
- const Value *v = module->d()->unit->resolveExport(expectedName);
+ const Value *v = module->resolveExport(id);
if (hasProperty)
*hasProperty = v != nullptr;
if (!v)
return Encode::undefined();
if (v->isEmpty()) {
+ Scope scope(m->engine());
ScopedValue propName(scope, id.toStringOrSymbol(scope.engine));
return scope.engine->throwReferenceError(propName);
}
@@ -124,9 +166,7 @@ PropertyAttributes Module::virtualGetOwnProperty(const Managed *m, PropertyKey i
return Object::virtualGetOwnProperty(m, id, p);
const Module *module = static_cast<const Module *>(m);
- Scope scope(m->engine());
- ScopedString expectedName(scope, id.toStringOrSymbol(scope.engine));
- const Value *v = module->d()->unit->resolveExport(expectedName);
+ const Value *v = module->resolveExport(id);
if (!v) {
if (p)
p->value = Encode::undefined();
@@ -135,6 +175,7 @@ PropertyAttributes Module::virtualGetOwnProperty(const Managed *m, PropertyKey i
if (p)
p->value = v->isEmpty() ? Encode::undefined() : v->asReturnedValue();
if (v->isEmpty()) {
+ Scope scope(m->engine());
ScopedValue propName(scope, id.toStringOrSymbol(scope.engine));
scope.engine->throwReferenceError(propName);
}
@@ -147,9 +188,7 @@ bool Module::virtualHasProperty(const Managed *m, PropertyKey id)
return Object::virtualHasProperty(m, id);
const Module *module = static_cast<const Module *>(m);
- Scope scope(m->engine());
- ScopedString expectedName(scope, id.toStringOrSymbol(scope.engine));
- const Value *v = module->d()->unit->resolveExport(expectedName);
+ const Value *v = module->resolveExport(id);
return v != nullptr;
}
@@ -173,11 +212,7 @@ bool Module::virtualDeleteProperty(Managed *m, PropertyKey id)
if (id.isSymbol())
return Object::virtualDeleteProperty(m, id);
const Module *module = static_cast<const Module *>(m);
- Scope scope(m->engine());
- ScopedString expectedName(scope, id.toStringOrSymbol(scope.engine));
- if (!expectedName)
- return true;
- const Value *v = module->d()->unit->resolveExport(expectedName);
+ const Value *v = module->resolveExport(id);
if (v)
return false;
return true;
@@ -202,7 +237,7 @@ PropertyKey ModuleNamespaceIterator::next(const Object *o, Property *pd, Propert
Scope scope(module->engine());
ScopedString exportName(scope, scope.engine->newString(exportedNames.at(exportIndex)));
exportIndex++;
- const Value *v = module->d()->unit->resolveExport(exportName);
+ const Value *v = module->resolveExport(exportName->toPropertyKey());
if (pd) {
if (v->isEmpty())
scope.engine->throwReferenceError(exportName);
@@ -218,7 +253,17 @@ OwnPropertyKeyIterator *Module::virtualOwnPropertyKeys(const Object *o, Value *t
{
const Module *module = static_cast<const Module *>(o);
*target = *o;
- return new ModuleNamespaceIterator(module->d()->unit->exportedNames());
+
+ QStringList names;
+ if (module->d()->unit->isESModule()) {
+ names = module->d()->unit->exportedNames();
+ } else {
+ Heap::InternalClass *scopeClass = module->d()->scope->internalClass;
+ for (uint i = 0; i < scopeClass->size; ++i)
+ names << scopeClass->keyAt(i);
+ }
+
+ return new ModuleNamespaceIterator(names);
}
Heap::Object *Module::virtualGetPrototypeOf(const Managed *)