/ runtime / JSModuleEnvironment.cpp
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