1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40
41 #include "qv4module_p.h"
42
43 #include <private/qv4mm_p.h>
44 #include <private/qv4vme_moth_p.h>
45 #include <private/qv4context_p.h>
46 #include <private/qv4symbol_p.h>
47 #include <private/qv4identifiertable_p.h>
48
49 #include <QScopeGuard>
50
51 using namespace QV4;
52
53 DEFINE_OBJECT_VTABLE(Module);
54
init(ExecutionEngine * engine,ExecutableCompilationUnit * moduleUnit)55 void Heap::Module::init(ExecutionEngine *engine, ExecutableCompilationUnit *moduleUnit)
56 {
57 Object::init();
58
59 // This is a back pointer and there is no need to call addref() on the unit, because the unit
60 // owns this object instead.
61 unit = moduleUnit;
62 self.set(engine, this);
63
64 Function *moduleFunction = unit->runtimeFunctions[unit->unitData()->indexOfRootFunction];
65
66 const uint locals = moduleFunction->compiledFunction->nLocals;
67 const size_t requiredMemory = sizeof(QV4::CallContext::Data) - sizeof(Value) + sizeof(Value) * locals;
68 scope.set(engine, engine->memoryManager->allocManaged<QV4::CallContext>(requiredMemory, moduleFunction->internalClass));
69 scope->init();
70 scope->outer.set(engine, engine->rootContext()->d());
71 scope->locals.size = locals;
72 scope->locals.alloc = locals;
73 scope->nArgs = 0;
74
75 // Prepare the temporal dead zone
76 scope->setupLocalTemporalDeadZone(moduleFunction->compiledFunction);
77
78 Scope valueScope(engine);
79
80 // It's possible for example to re-export an import, for example:
81 // import * as foo from "./bar.js"
82 // export { foo }
83 // Since we don't add imports to the locals, it won't be found typically.
84 // Except now we add imports at the end of the internal class in the index
85 // space past the locals, so that resolveExport can find it.
86 {
87 Scoped<QV4::InternalClass> ic(valueScope, scope->internalClass);
88
89 for (uint i = 0; i < unit->data->importEntryTableSize; ++i) {
90 const CompiledData::ImportEntry &import = unit->data->importEntryTable()[i];
91 ic = ic->addMember(engine->identifierTable->asPropertyKey(unit->runtimeStrings[import.localName]), Attr_NotConfigurable);
92 }
93 scope->internalClass.set(engine, ic->d());
94 }
95
96
97 Scoped<QV4::Module> This(valueScope, this);
98 ScopedString name(valueScope, engine->newString(QStringLiteral("Module")));
99 This->insertMember(engine->symbol_toStringTag(), name, Attr_ReadOnly);
100 This->setPrototypeUnchecked(nullptr);
101 }
102
evaluate()103 void Module::evaluate()
104 {
105 if (d()->evaluated)
106 return;
107 d()->evaluated = true;
108
109 ExecutableCompilationUnit *unit = d()->unit;
110
111 unit->evaluateModuleRequests();
112
113 ExecutionEngine *v4 = engine();
114 Function *moduleFunction = unit->runtimeFunctions[unit->data->indexOfRootFunction];
115 CppStackFrame frame;
116 frame.init(v4, moduleFunction, nullptr, 0);
117 frame.setupJSFrame(v4->jsStackTop, Value::undefinedValue(), d()->scope,
118 Value::undefinedValue(), Value::undefinedValue());
119
120 frame.push();
121 v4->jsStackTop += frame.requiredJSStackFrameSize();
122 auto frameCleanup = qScopeGuard([&frame]() {
123 frame.pop();
124 });
125 Moth::VME::exec(&frame, v4);
126 }
127
resolveExport(PropertyKey id) const128 const Value *Module::resolveExport(PropertyKey id) const
129 {
130 if (d()->unit->isESModule()) {
131 if (!id.isString())
132 return nullptr;
133 Scope scope(engine());
134 ScopedString name(scope, id.asStringOrSymbol());
135 return d()->unit->resolveExport(name);
136 } else {
137 InternalClassEntry entry = d()->scope->internalClass->find(id);
138 if (entry.isValid())
139 return &d()->scope->locals[entry.index];
140 return nullptr;
141 }
142 }
143
virtualGet(const Managed * m,PropertyKey id,const Value * receiver,bool * hasProperty)144 ReturnedValue Module::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
145 {
146 if (id.isSymbol())
147 return Object::virtualGet(m, id, receiver, hasProperty);
148
149 const Module *module = static_cast<const Module *>(m);
150 const Value *v = module->resolveExport(id);
151 if (hasProperty)
152 *hasProperty = v != nullptr;
153 if (!v)
154 return Encode::undefined();
155 if (v->isEmpty()) {
156 Scope scope(m->engine());
157 ScopedValue propName(scope, id.toStringOrSymbol(scope.engine));
158 return scope.engine->throwReferenceError(propName);
159 }
160 return v->asReturnedValue();
161 }
162
virtualGetOwnProperty(const Managed * m,PropertyKey id,Property * p)163 PropertyAttributes Module::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
164 {
165 if (id.isSymbol())
166 return Object::virtualGetOwnProperty(m, id, p);
167
168 const Module *module = static_cast<const Module *>(m);
169 const Value *v = module->resolveExport(id);
170 if (!v) {
171 if (p)
172 p->value = Encode::undefined();
173 return Attr_Invalid;
174 }
175 if (p)
176 p->value = v->isEmpty() ? Encode::undefined() : v->asReturnedValue();
177 if (v->isEmpty()) {
178 Scope scope(m->engine());
179 ScopedValue propName(scope, id.toStringOrSymbol(scope.engine));
180 scope.engine->throwReferenceError(propName);
181 }
182 return Attr_Data | Attr_NotConfigurable;
183 }
184
virtualHasProperty(const Managed * m,PropertyKey id)185 bool Module::virtualHasProperty(const Managed *m, PropertyKey id)
186 {
187 if (id.isSymbol())
188 return Object::virtualHasProperty(m, id);
189
190 const Module *module = static_cast<const Module *>(m);
191 const Value *v = module->resolveExport(id);
192 return v != nullptr;
193 }
194
virtualPreventExtensions(Managed *)195 bool Module::virtualPreventExtensions(Managed *)
196 {
197 return true;
198 }
199
virtualDefineOwnProperty(Managed *,PropertyKey,const Property *,PropertyAttributes)200 bool Module::virtualDefineOwnProperty(Managed *, PropertyKey, const Property *, PropertyAttributes)
201 {
202 return false;
203 }
204
virtualPut(Managed *,PropertyKey,const Value &,Value *)205 bool Module::virtualPut(Managed *, PropertyKey, const Value &, Value *)
206 {
207 return false;
208 }
209
virtualDeleteProperty(Managed * m,PropertyKey id)210 bool Module::virtualDeleteProperty(Managed *m, PropertyKey id)
211 {
212 if (id.isSymbol())
213 return Object::virtualDeleteProperty(m, id);
214 const Module *module = static_cast<const Module *>(m);
215 const Value *v = module->resolveExport(id);
216 if (v)
217 return false;
218 return true;
219 }
220
221 struct ModuleNamespaceIterator : ObjectOwnPropertyKeyIterator
222 {
223 QStringList exportedNames;
224 int exportIndex = 0;
ModuleNamespaceIteratorModuleNamespaceIterator225 ModuleNamespaceIterator(const QStringList &names) : exportedNames(names) {}
226 ~ModuleNamespaceIterator() override = default;
227 PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
228
229 };
230
next(const Object * o,Property * pd,PropertyAttributes * attrs)231 PropertyKey ModuleNamespaceIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs)
232 {
233 const Module *module = static_cast<const Module *>(o);
234 if (exportIndex < exportedNames.count()) {
235 if (attrs)
236 *attrs = Attr_Data;
237 Scope scope(module->engine());
238 ScopedString exportName(scope, scope.engine->newString(exportedNames.at(exportIndex)));
239 exportIndex++;
240 const Value *v = module->resolveExport(exportName->toPropertyKey());
241 if (pd) {
242 if (v->isEmpty())
243 scope.engine->throwReferenceError(exportName);
244 else
245 pd->value = *v;
246 }
247 return exportName->toPropertyKey();
248 }
249 return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
250 }
251
virtualOwnPropertyKeys(const Object * o,Value * target)252 OwnPropertyKeyIterator *Module::virtualOwnPropertyKeys(const Object *o, Value *target)
253 {
254 const Module *module = static_cast<const Module *>(o);
255 *target = *o;
256
257 QStringList names;
258 if (module->d()->unit->isESModule()) {
259 names = module->d()->unit->exportedNames();
260 } else {
261 Heap::InternalClass *scopeClass = module->d()->scope->internalClass;
262 for (uint i = 0; i < scopeClass->size; ++i)
263 names << scopeClass->keyAt(i);
264 }
265
266 return new ModuleNamespaceIterator(names);
267 }
268
virtualGetPrototypeOf(const Managed *)269 Heap::Object *Module::virtualGetPrototypeOf(const Managed *)
270 {
271 return nullptr;
272 }
273
virtualSetPrototypeOf(Managed *,const Object * proto)274 bool Module::virtualSetPrototypeOf(Managed *, const Object *proto)
275 {
276 return proto == nullptr;
277 }
278
virtualIsExtensible(const Managed *)279 bool Module::virtualIsExtensible(const Managed *)
280 {
281 return false;
282 }
283