JSModuleEnvironment.cpp
1 /* 2 * Copyright (C) 2015-2019 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 "JSCInlines.h" 34 35 namespace JSC { 36 37 const ClassInfo JSModuleEnvironment::s_info = { "JSModuleEnvironment", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSModuleEnvironment) }; 38 39 JSModuleEnvironment* JSModuleEnvironment::create( 40 VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue, AbstractModuleRecord* moduleRecord) 41 { 42 // JSLexicalEnvironment has the storage to store the variable slots after the its class storage. 43 // Because the offset of the variable slots are fixed in the JSLexicalEnvironment, inheritting these class and adding new member field is not allowed, 44 // the new member will overlap the variable slots. 45 // To keep the JSModuleEnvironment compatible to the JSLexicalEnvironment but add the new member to store the AbstractModuleRecord, we additionally allocate 46 // the storage after the variable slots. 47 // 48 // JSLexicalEnvironment: 49 // [ JSLexicalEnvironment ][ variable slots ] 50 // 51 // JSModuleEnvironment: 52 // [ JSLexicalEnvironment ][ variable slots ][ additional slots for JSModuleEnvironment ] 53 JSModuleEnvironment* result = 54 new ( 55 NotNull, 56 allocateCell<JSModuleEnvironment>(vm.heap, JSModuleEnvironment::allocationSize(symbolTable))) 57 JSModuleEnvironment(vm, structure, currentScope, symbolTable); 58 result->finishCreation(vm, initialValue, moduleRecord); 59 return result; 60 } 61 62 void JSModuleEnvironment::finishCreation(VM& vm, JSValue initialValue, AbstractModuleRecord* moduleRecord) 63 { 64 Base::finishCreation(vm, initialValue); 65 this->moduleRecordSlot().set(vm, this, moduleRecord); 66 } 67 68 void JSModuleEnvironment::visitChildren(JSCell* cell, SlotVisitor& visitor) 69 { 70 JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell); 71 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 72 Base::visitChildren(thisObject, visitor); 73 visitor.appendValues(thisObject->variables(), thisObject->symbolTable()->scopeSize()); 74 visitor.append(thisObject->moduleRecordSlot()); 75 } 76 77 bool JSModuleEnvironment::getOwnPropertySlot(JSObject* cell, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) 78 { 79 VM& vm = globalObject->vm(); 80 auto scope = DECLARE_THROW_SCOPE(vm); 81 JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell); 82 AbstractModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(globalObject, Identifier::fromUid(vm, propertyName.uid())); 83 RETURN_IF_EXCEPTION(scope, false); 84 if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved) { 85 // When resolveImport resolves the resolution, the imported module environment must have the binding. 86 JSModuleEnvironment* importedModuleEnvironment = resolution.moduleRecord->moduleEnvironment(); 87 PropertySlot redirectSlot(importedModuleEnvironment, PropertySlot::InternalMethodType::Get); 88 bool result = importedModuleEnvironment->methodTable(vm)->getOwnPropertySlot(importedModuleEnvironment, globalObject, resolution.localName, redirectSlot); 89 ASSERT_UNUSED(result, result); 90 ASSERT(redirectSlot.isValue()); 91 JSValue value = redirectSlot.getValue(globalObject, resolution.localName); 92 scope.assertNoException(); 93 slot.setValue(thisObject, redirectSlot.attributes(), value); 94 return true; 95 } 96 return Base::getOwnPropertySlot(thisObject, globalObject, propertyName, slot); 97 } 98 99 void JSModuleEnvironment::getOwnSpecialPropertyNames(JSObject* cell, JSGlobalObject*, PropertyNameArray& propertyNamesArray, DontEnumPropertiesMode) 100 { 101 JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell); 102 if (propertyNamesArray.includeStringProperties()) { 103 for (const auto& pair : thisObject->moduleRecord()->importEntries()) { 104 const AbstractModuleRecord::ImportEntry& importEntry = pair.value; 105 if (importEntry.type == AbstractModuleRecord::ImportEntryType::Single) 106 propertyNamesArray.add(importEntry.localName); 107 } 108 } 109 } 110 111 bool JSModuleEnvironment::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot) 112 { 113 VM& vm = globalObject->vm(); 114 auto scope = DECLARE_THROW_SCOPE(vm); 115 116 JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell); 117 // All imported bindings are immutable. 118 AbstractModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(globalObject, Identifier::fromUid(vm, propertyName.uid())); 119 RETURN_IF_EXCEPTION(scope, false); 120 if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved) { 121 throwTypeError(globalObject, scope, ReadonlyPropertyWriteError); 122 return false; 123 } 124 RELEASE_AND_RETURN(scope, Base::put(thisObject, globalObject, propertyName, value, slot)); 125 } 126 127 bool JSModuleEnvironment::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot) 128 { 129 VM& vm = globalObject->vm(); 130 auto scope = DECLARE_THROW_SCOPE(vm); 131 132 JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell); 133 // All imported bindings are immutable. 134 AbstractModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(globalObject, Identifier::fromUid(vm, propertyName.uid())); 135 RETURN_IF_EXCEPTION(scope, false); 136 if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved) 137 return false; 138 return Base::deleteProperty(thisObject, globalObject, propertyName, slot); 139 } 140 141 } // namespace JSC