8168b78255ca86494d8f6d8922f6a1ec676bfc32
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSModuleEnvironment.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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "JSModuleEnvironment.h"
31
32 #include "AbstractModuleRecord.h"
33 #include "Interpreter.h"
34 #include "JSCInlines.h"
35 #include "JSFunction.h"
36
37 using namespace std;
38
39 namespace JSC {
40
41 const ClassInfo JSModuleEnvironment::s_info = { "JSModuleEnvironment", &Base::s_info, 0, CREATE_METHOD_TABLE(JSModuleEnvironment) };
42
43 JSModuleEnvironment* JSModuleEnvironment::create(
44     VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue, AbstractModuleRecord* moduleRecord)
45 {
46     // JSLexicalEnvironment (precisely, JSEnvironmentRecord) has the storage to store the variable slots after the its class storage.
47     // Because the offset of the variable slots are fixed in the JSEnvironmentRecord, inheritting these class and adding new member field is not allowed,
48     // the new member will overlap the variable slots.
49     // To keep the JSModuleEnvironment compatible to the JSLexicalEnvironment but add the new member to store the AbstractModuleRecord, we additionally allocate
50     // the storage after the variable slots.
51     //
52     // JSLexicalEnvironment:
53     //     [ JSLexicalEnvironment ][ variable slots ]
54     //
55     // JSModuleEnvironment:
56     //     [ JSLexicalEnvironment ][ variable slots ][ additional slots for JSModuleEnvironment ]
57     JSModuleEnvironment* result =
58         new (
59             NotNull,
60             allocateCell<JSModuleEnvironment>(vm.heap, JSModuleEnvironment::allocationSize(symbolTable)))
61         JSModuleEnvironment(vm, structure, currentScope, symbolTable);
62     result->finishCreation(vm, initialValue, moduleRecord);
63     return result;
64 }
65
66 void JSModuleEnvironment::finishCreation(VM& vm, JSValue initialValue, AbstractModuleRecord* moduleRecord)
67 {
68     Base::finishCreation(vm, initialValue);
69     this->moduleRecordSlot().set(vm, this, moduleRecord);
70 }
71
72 void JSModuleEnvironment::visitChildren(JSCell* cell, SlotVisitor& visitor)
73 {
74     JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
75     Base::visitChildren(thisObject, visitor);
76     visitor.appendValues(thisObject->variables(), thisObject->symbolTable()->scopeSize());
77     visitor.append(&thisObject->moduleRecordSlot());
78 }
79
80 bool JSModuleEnvironment::getOwnPropertySlot(JSObject* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
81 {
82     VM& vm = exec->vm();
83     auto scope = DECLARE_THROW_SCOPE(vm);
84     JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
85     AbstractModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
86     if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved) {
87         // When resolveImport resolves the resolution, the imported module environment must have the binding.
88         JSModuleEnvironment* importedModuleEnvironment = resolution.moduleRecord->moduleEnvironment();
89         PropertySlot redirectSlot(importedModuleEnvironment, PropertySlot::InternalMethodType::Get);
90         bool result = importedModuleEnvironment->methodTable(vm)->getOwnPropertySlot(importedModuleEnvironment, exec, resolution.localName, redirectSlot);
91         ASSERT_UNUSED(result, result);
92         ASSERT(redirectSlot.isValue());
93         JSValue value = redirectSlot.getValue(exec, resolution.localName);
94         ASSERT_UNUSED(scope, !scope.exception());
95         slot.setValue(thisObject, redirectSlot.attributes(), value);
96         return true;
97     }
98     return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
99 }
100
101 void JSModuleEnvironment::getOwnNonIndexPropertyNames(JSObject* cell, ExecState* exec, PropertyNameArray& propertyNamesArray, EnumerationMode mode)
102 {
103     JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
104     if (propertyNamesArray.includeStringProperties()) {
105         for (const auto& pair : thisObject->moduleRecord()->importEntries()) {
106             const AbstractModuleRecord::ImportEntry& importEntry = pair.value;
107             if (!importEntry.isNamespace(exec->vm()))
108                 propertyNamesArray.add(importEntry.localName);
109         }
110     }
111     return Base::getOwnNonIndexPropertyNames(thisObject, exec, propertyNamesArray, mode);
112 }
113
114 bool JSModuleEnvironment::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
115 {
116     VM& vm = exec->vm();
117     auto scope = DECLARE_THROW_SCOPE(vm);
118
119     JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
120     // All imported bindings are immutable.
121     AbstractModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
122     if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved) {
123         throwTypeError(exec, scope, ASCIILiteral(ReadonlyPropertyWriteError));
124         return false;
125     }
126     return Base::put(thisObject, exec, propertyName, value, slot);
127 }
128
129 bool JSModuleEnvironment::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
130 {
131     JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
132     // All imported bindings are immutable.
133     AbstractModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
134     if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved)
135         return false;
136     return Base::deleteProperty(thisObject, exec, propertyName);
137 }
138
139 } // namespace JSC