Ignore:
Timestamp:
Aug 7, 2016, 7:48:56 PM (9 years ago)
Author:
Yusuke Suzuki
Message:

[ES6] Module namespace object should not allow unset IC
https://bugs.webkit.org/show_bug.cgi?id=160553

Reviewed by Saam Barati.

JSTests:

  • modules/namespace-object-get-property.js: Added.

(import.as.ns.from.string_appeared_here.shouldThrow):

  • modules/namespace-object-has-property.js: Added.
  • modules/namespace-object-inline-caching.js: Added.

(import.as.A.from.string_appeared_here.import.as.B.from.string_appeared_here.lookup):
(shouldBe.lookup.lookup):
(shouldBe.lookup):

  • modules/namespace-object-inline-caching/a.js: Added.
  • modules/namespace-object-inline-caching/b.js: Added.
  • modules/namespace-object-try-get.js: Added.

(import.as.ns.from.string_appeared_here.tryGetByIdText):
(tryGetByIdTextStrict):

  • modules/namespace-object-typed-array-fast-path.js: Added.
  • test262.yaml:

Source/JavaScriptCore:

Previously, module namespace object accidentally allow "unset IC". But this "unsetness" does not rely on
the structure. We should disable inline caching onto the namespace object. Once it is needed, we should
create the special caching for namespace object like the following: it should be similar to monomorphic IC,
but it caches the object itself instead of the structure. It checks the object itself (And in DFG, it should be
CheckCell) and loads the value from the target module environment directly[1].

And this patch also set setIsTaintedByProxy for the module namespace object to notify to the caller that
this object has impure ::getOwnPropertySlot. Then this function is now renamed to setIsTaintedByOpaqueObject.

We drop the hack in JSModuleNamespaceObject::getOwnPropertySlot since we already introduced InternalMethodType
for ProxyObject. Previously we cannot distinguish ::HasProperty and ::GetOwnProperty. So not to throw any
errors for ::HasProperty case, we used slot.setCustom to delay the observable operation.
But, this hack lacks the support for hasOwnProperty: hasOwnProperty uses GetOwnProperty, so it should throw an error.
However the previous implementation does not throw an error since the delayed observable part (custom function part) is
skipped in hasOwnProperty implementation. We now remove this custom property hack and fix the corresponding failure
in test262.

[1]: https://bugs.webkit.org/show_bug.cgi?id=160590

  • jit/JITOperations.cpp:
  • runtime/ArrayPrototype.cpp:

(JSC::getProperty):

  • runtime/JSGenericTypedArrayViewConstructorInlines.h:

(JSC::constructGenericTypedArrayViewWithArguments):

  • runtime/JSModuleNamespaceObject.cpp:

(JSC::JSModuleNamespaceObject::getOwnPropertySlot):
(JSC::callbackGetter): Deleted.

  • runtime/JSModuleNamespaceObject.h:
  • runtime/PropertySlot.cpp:

(JSC::PropertySlot::getPureResult):

  • runtime/PropertySlot.h:

(JSC::PropertySlot::PropertySlot):
(JSC::PropertySlot::setIsTaintedByOpaqueObject):
(JSC::PropertySlot::isTaintedByOpaqueObject):
(JSC::PropertySlot::setIsTaintedByProxy): Deleted.
(JSC::PropertySlot::isTaintedByProxy): Deleted.

  • runtime/ProxyObject.cpp:

(JSC::ProxyObject::getOwnPropertySlotCommon):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp

    r204160 r204248  
    9999}
    100100
    101 static EncodedJSValue callbackGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName propertyName)
    102 {
    103     JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(JSValue::decode(thisValue));
    104     JSModuleRecord* moduleRecord = thisObject->moduleRecord();
    105 
    106     JSModuleRecord::Resolution resolution = moduleRecord->resolveExport(exec, Identifier::fromUid(exec, propertyName.uid()));
    107     ASSERT(resolution.type != JSModuleRecord::Resolution::Type::NotFound && resolution.type != JSModuleRecord::Resolution::Type::Ambiguous);
    108 
    109     JSModuleRecord* targetModule = resolution.moduleRecord;
    110     JSModuleEnvironment* targetEnvironment = targetModule->moduleEnvironment();
    111 
    112     PropertySlot trampolineSlot(targetEnvironment, PropertySlot::InternalMethodType::Get);
    113     if (!targetEnvironment->methodTable(exec->vm())->getOwnPropertySlot(targetEnvironment, exec, resolution.localName, trampolineSlot))
    114         return JSValue::encode(jsUndefined());
    115 
    116     JSValue value = trampolineSlot.getValue(exec, propertyName);
    117     if (exec->hadException())
    118         return JSValue::encode(jsUndefined());
    119 
    120     // If the value is filled with TDZ value, throw a reference error.
    121     if (!value)
    122         return throwVMError(exec, createTDZError(exec));
    123     return JSValue::encode(value);
    124 }
    125 
    126101bool JSModuleNamespaceObject::getOwnPropertySlot(JSObject* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
    127102{
     
    136111        return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
    137112
     113    // FIXME: Add IC for module namespace object.
     114    // https://bugs.webkit.org/show_bug.cgi?id=160590
     115    slot.disableCaching();
     116    slot.setIsTaintedByOpaqueObject();
    138117    if (!thisObject->m_exports.contains(propertyName.uid()))
    139118        return false;
    140119
    141     // https://esdiscuss.org/topic/march-24-meeting-notes
    142     // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-getownproperty-p
    143     // section 9.4.6.5, step 6.
    144     // This property will be seen as writable: true, enumerable:true, configurable: false.
    145     // But this does not mean that this property is writable by users.
    146     //
    147     // In JSC, getOwnPropertySlot is not designed to throw any errors. But looking up the value from the module
    148     // environment may throw error if the loaded variable is the TDZ value. To workaround, we set the custom
    149     // getter function. When it is called, it looks up the variable and throws an error if the variable is not
    150     // initialized.
    151     slot.setCustom(thisObject, DontDelete, callbackGetter);
    152     return true;
     120    switch (slot.internalMethodType()) {
     121    case PropertySlot::InternalMethodType::Get:
     122    case PropertySlot::InternalMethodType::GetOwnProperty: {
     123        JSModuleRecord* moduleRecord = thisObject->moduleRecord();
     124
     125        JSModuleRecord::Resolution resolution = moduleRecord->resolveExport(exec, Identifier::fromUid(exec, propertyName.uid()));
     126        ASSERT(resolution.type != JSModuleRecord::Resolution::Type::NotFound && resolution.type != JSModuleRecord::Resolution::Type::Ambiguous);
     127
     128        JSModuleRecord* targetModule = resolution.moduleRecord;
     129        JSModuleEnvironment* targetEnvironment = targetModule->moduleEnvironment();
     130
     131        PropertySlot trampolineSlot(targetEnvironment, PropertySlot::InternalMethodType::Get);
     132        bool found = targetEnvironment->methodTable(exec->vm())->getOwnPropertySlot(targetEnvironment, exec, resolution.localName, trampolineSlot);
     133        ASSERT_UNUSED(found, found);
     134
     135        JSValue value = trampolineSlot.getValue(exec, propertyName);
     136        ASSERT(!exec->hadException());
     137
     138        // If the value is filled with TDZ value, throw a reference error.
     139        if (!value) {
     140            throwVMError(exec, createTDZError(exec));
     141            return false;
     142        }
     143
     144        slot.setValue(thisObject, DontDelete, value);
     145        return true;
     146    }
     147    case PropertySlot::InternalMethodType::HasProperty: {
     148        // Do not perform [[Get]] for [[HasProperty]].
     149        // [[Get]] / [[GetOwnProperty]] onto namespace object could throw an error while [[HasProperty]] just returns true here.
     150        // https://tc39.github.io/ecma262/#sec-module-namespace-exotic-objects-hasproperty-p
     151        slot.setValue(thisObject, DontDelete, jsUndefined());
     152        return true;
     153    }
     154
     155    case PropertySlot::InternalMethodType::VMInquiry:
     156        return false;
     157    }
     158
     159    RELEASE_ASSERT_NOT_REACHED();
     160    return false;
    153161}
    154162
Note: See TracChangeset for help on using the changeset viewer.