We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSModuleRecord.cpp
1 /*
2  * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "JSModuleRecord.h"
28
29 #include "BuiltinNames.h"
30 #include "Error.h"
31 #include "Interpreter.h"
32 #include "JSCInlines.h"
33 #include "JSModuleEnvironment.h"
34 #include "JSModuleLoader.h"
35 #include "JSModuleNamespaceObject.h"
36 #include "UnlinkedModuleProgramCodeBlock.h"
37
38 namespace JSC {
39
40 const ClassInfo JSModuleRecord::s_info = { "ModuleRecord", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSModuleRecord) };
41
42
43 Structure* JSModuleRecord::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
44 {
45     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
46 }
47
48 JSModuleRecord* JSModuleRecord::create(ExecState* exec, VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
49 {
50     JSModuleRecord* instance = new (NotNull, allocateCell<JSModuleRecord>(vm.heap)) JSModuleRecord(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables);
51     instance->finishCreation(exec, vm);
52     return instance;
53 }
54 JSModuleRecord::JSModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
55     : Base(vm, structure, moduleKey)
56     , m_sourceCode(sourceCode)
57     , m_declaredVariables(declaredVariables)
58     , m_lexicalVariables(lexicalVariables)
59 {
60 }
61
62 void JSModuleRecord::destroy(JSCell* cell)
63 {
64     JSModuleRecord* thisObject = static_cast<JSModuleRecord*>(cell);
65     thisObject->JSModuleRecord::~JSModuleRecord();
66 }
67
68 void JSModuleRecord::finishCreation(ExecState* exec, VM& vm)
69 {
70     Base::finishCreation(exec, vm);
71     ASSERT(inherits(vm, info()));
72 }
73
74 void JSModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
75 {
76     JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell);
77     Base::visitChildren(thisObject, visitor);
78     visitor.append(thisObject->m_moduleProgramExecutable);
79 }
80
81 void JSModuleRecord::link(ExecState* exec, JSValue scriptFetcher)
82 {
83     VM& vm = exec->vm();
84     auto scope = DECLARE_THROW_SCOPE(vm);
85
86     ModuleProgramExecutable* executable = ModuleProgramExecutable::create(exec, sourceCode());
87     EXCEPTION_ASSERT(!!scope.exception() == !executable);
88     if (!executable) {
89         throwSyntaxError(exec, scope);
90         return;
91     }
92     instantiateDeclarations(exec, executable, scriptFetcher);
93     RETURN_IF_EXCEPTION(scope, void());
94     m_moduleProgramExecutable.set(vm, this, executable);
95 }
96
97 void JSModuleRecord::instantiateDeclarations(ExecState* exec, ModuleProgramExecutable* moduleProgramExecutable, JSValue scriptFetcher)
98 {
99     VM& vm = exec->vm();
100     auto scope = DECLARE_THROW_SCOPE(vm);
101
102     // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
103
104     SymbolTable* symbolTable = moduleProgramExecutable->moduleEnvironmentSymbolTable();
105     JSModuleEnvironment* moduleEnvironment = JSModuleEnvironment::create(vm, exec->lexicalGlobalObject(), exec->lexicalGlobalObject(), symbolTable, jsTDZValue(), this);
106
107     // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
108     // section 15.2.1.16.4 step 9.
109     // Ensure all the indirect exports are correctly resolved to unique bindings.
110     // Even if we avoided duplicate exports in the parser, still ambiguous exports occur due to the star export (`export * from "mod"`).
111     // When we see this type of ambiguity for the indirect exports here, throw a syntax error.
112     for (const auto& pair : exportEntries()) {
113         const ExportEntry& exportEntry = pair.value;
114         if (exportEntry.type == JSModuleRecord::ExportEntry::Type::Indirect) {
115             Resolution resolution = resolveExport(exec, exportEntry.exportName);
116             RETURN_IF_EXCEPTION(scope, void());
117             switch (resolution.type) {
118             case Resolution::Type::NotFound:
119                 throwSyntaxError(exec, scope, makeString("Indirectly exported binding name '", String(exportEntry.exportName.impl()), "' is not found."));
120                 return;
121
122             case Resolution::Type::Ambiguous:
123                 throwSyntaxError(exec, scope, makeString("Indirectly exported binding name '", String(exportEntry.exportName.impl()), "' cannot be resolved due to ambiguous multiple bindings."));
124                 return;
125
126             case Resolution::Type::Error:
127                 throwSyntaxError(exec, scope, makeString("Indirectly exported binding name 'default' cannot be resolved by star export entries."));
128                 return;
129
130             case Resolution::Type::Resolved:
131                 break;
132             }
133         }
134     }
135
136     // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
137     // section 15.2.1.16.4 step 12.
138     // Instantiate namespace objects and initialize the bindings with them if required.
139     // And ensure that all the imports correctly resolved to unique bindings.
140     for (const auto& pair : importEntries()) {
141         const ImportEntry& importEntry = pair.value;
142         AbstractModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest);
143         RETURN_IF_EXCEPTION(scope, void());
144         if (importEntry.type == AbstractModuleRecord::ImportEntryType::Namespace) {
145             JSModuleNamespaceObject* namespaceObject = importedModule->getModuleNamespace(exec);
146             RETURN_IF_EXCEPTION(scope, void());
147             bool putResult = false;
148             symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, importEntry.localName, namespaceObject, /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true, putResult);
149             RETURN_IF_EXCEPTION(scope, void());
150         } else {
151             Resolution resolution = importedModule->resolveExport(exec, importEntry.importName);
152             RETURN_IF_EXCEPTION(scope, void());
153             switch (resolution.type) {
154             case Resolution::Type::NotFound:
155                 throwSyntaxError(exec, scope, makeString("Importing binding name '", String(importEntry.importName.impl()), "' is not found."));
156                 return;
157
158             case Resolution::Type::Ambiguous:
159                 throwSyntaxError(exec, scope, makeString("Importing binding name '", String(importEntry.importName.impl()), "' cannot be resolved due to ambiguous multiple bindings."));
160                 return;
161
162             case Resolution::Type::Error:
163                 throwSyntaxError(exec, scope, makeString("Importing binding name 'default' cannot be resolved by star export entries."));
164                 return;
165
166             case Resolution::Type::Resolved:
167                 break;
168             }
169         }
170     }
171
172     // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
173     // section 15.2.1.16.4 step 14.
174     // Module environment contains the heap allocated "var", "function", "let", "const", and "class".
175     // When creating the environment, we initialized all the slots with empty, it's ok for lexical values.
176     // But for "var" and "function", we should initialize it with undefined. They are contained in the declared variables.
177     for (const auto& variable : declaredVariables()) {
178         SymbolTableEntry entry = symbolTable->get(variable.key.get());
179         VarOffset offset = entry.varOffset();
180         if (!offset.isStack()) {
181             bool putResult = false;
182             symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, Identifier::fromUid(exec, variable.key.get()), jsUndefined(), /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true, putResult);
183             RETURN_IF_EXCEPTION(scope, void());
184         }
185     }
186
187     // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
188     // section 15.2.1.16.4 step 16-a-iv.
189     // Initialize heap allocated function declarations.
190     // They can be called before the body of the module is executed under circular dependencies.
191     UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = moduleProgramExecutable->unlinkedModuleProgramCodeBlock();
192     for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) {
193         UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i);
194         SymbolTableEntry entry = symbolTable->get(unlinkedFunctionExecutable->name().impl());
195         VarOffset offset = entry.varOffset();
196         if (!offset.isStack()) {
197             ASSERT(!unlinkedFunctionExecutable->name().isEmpty());
198             if (vm.typeProfiler() || vm.controlFlowProfiler()) {
199                 vm.functionHasExecutedCache()->insertUnexecutedRange(moduleProgramExecutable->sourceID(),
200                     unlinkedFunctionExecutable->typeProfilingStartOffset(),
201                     unlinkedFunctionExecutable->typeProfilingEndOffset());
202             }
203             JSFunction* function = JSFunction::create(vm, unlinkedFunctionExecutable->link(vm, moduleProgramExecutable->source()), moduleEnvironment);
204             bool putResult = false;
205             symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, unlinkedFunctionExecutable->name(), function, /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true, putResult);
206             RETURN_IF_EXCEPTION(scope, void());
207         }
208     }
209
210     {
211         JSObject* metaProperties = exec->lexicalGlobalObject()->moduleLoader()->createImportMetaProperties(exec, identifierToJSValue(vm, moduleKey()), this, scriptFetcher);
212         RETURN_IF_EXCEPTION(scope, void());
213         bool putResult = false;
214         symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, vm.propertyNames->builtinNames().metaPrivateName(), metaProperties, /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true, putResult);
215         RETURN_IF_EXCEPTION(scope, void());
216     }
217
218     m_moduleEnvironment.set(vm, this, moduleEnvironment);
219 }
220
221 JSValue JSModuleRecord::evaluate(ExecState* exec)
222 {
223     if (!m_moduleProgramExecutable)
224         return jsUndefined();
225     VM& vm = exec->vm();
226     ModuleProgramExecutable* executable = m_moduleProgramExecutable.get();
227     m_moduleProgramExecutable.clear();
228     return vm.interpreter->executeModuleProgram(executable, exec, m_moduleEnvironment.get());
229 }
230
231 } // namespace JSC