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