Ignore:
Timestamp:
Jan 29, 2020, 10:07:40 AM (5 years ago)
Author:
[email protected]
Message:

[JSC] Give up IC when unknown structure transition happens
https://bugs.webkit.org/show_bug.cgi?id=206846

Reviewed by Mark Lam.

JSTests:

  • stress/ensure-crash.js: Added.
  • stress/incorrect-put-could-generate-invalid-ic-but-still-not-causing-bad-behavior-bad-transition-debug.js: Added.

(shouldBe):
(putter):
(not_string.toString):

  • stress/incorrect-put-could-generate-invalid-ic-but-still-not-causing-bad-behavior-bad-transition.js: Added.

(shouldBe):
(putter):
(not_string.toString):

  • stress/incorrect-put-could-generate-invalid-ic-but-still-not-causing-bad-behavior.js: Added.

(shouldBe):
(putter):
(not_string.toString):

  • stress/incorrect-put-could-generate-invalid-ic-involving-dictionary-flatten.js: Added.

(shouldBe):
(dictionary):
(putter):
(not_string.toString):

Source/JavaScriptCore:

When we are creating Put IC for a new property, we grab the old Structure before performing
the put. For a custom ::put, our convention is that the implemented ::put should mark the PutPropertySlot
as non-cachable. The IC code relies on this in order to work correctly. If we didn't mark it as non-cacheable,
a semantic failure can happen. This patch hardens the code against this semantic failure case by giving up trying
to cache the IC when the newStructure calculated from oldStructure does not match against
the actual structure after the put operation.

  • jit/Repatch.cpp:

(JSC::tryCachePutByID):
(JSC::repatchPutByID):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • runtime/Structure.cpp:

(JSC::Structure::flattenDictionaryStructure):

  • tools/JSDollarVM.cpp:

(JSC::functionCreateObjectDoingSideEffectPutWithoutCorrectSlotStatus):
(JSC::JSDollarVM::finishCreation):
(JSC::JSDollarVM::visitChildren):

  • tools/JSDollarVM.h:

Source/WebCore:

IDL Code Generator should taint PutPropertySlot or taint implemented object to avoid Put IC caching
when it implements custom ::put operation which has side-effect regardless of Structure. Otherwise, IC can be setup
and IC can do fast path without consulting the custom ::put operation.

Test: js/dom/put-override-should-not-use-ic.html

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateHeader):

  • bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.h:
  • bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.h:
  • bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.h:
  • bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.h:
  • bindings/scripts/test/JS/JSTestNamedSetterThrowingException.h:
  • bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.h:
  • bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.h:
  • bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.h:
  • bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.h:
  • bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.h:
  • bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.h:
  • bindings/scripts/test/JS/JSTestPluginInterface.h:

Tools:

Add crash! annotation, which allows us to write a crashing JS test.

  • Scripts/run-jsc-stress-tests:
  • Scripts/webkitruby/jsc-stress-test-writer-default.rb:
  • Scripts/webkitruby/jsc-stress-test-writer-playstation.rb:
  • Scripts/webkitruby/jsc-stress-test-writer-ruby.rb:

LayoutTests:

  • js/dom/put-override-should-not-use-ic-expected.txt: Added.
  • js/dom/put-override-should-not-use-ic.html: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/tools/JSDollarVM.cpp

    r253344 r255365  
    683683};
    684684
     685class ObjectDoingSideEffectPutWithoutCorrectSlotStatus : public JSNonFinalObject {
     686    using Base = JSNonFinalObject;
     687public:
     688    ObjectDoingSideEffectPutWithoutCorrectSlotStatus(VM& vm, Structure* structure)
     689        : Base(vm, structure)
     690    {
     691        DollarVMAssertScope assertScope;
     692    }
     693
     694    DECLARE_INFO;
     695
     696    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     697    {
     698        DollarVMAssertScope assertScope;
     699        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     700    }
     701
     702    static ObjectDoingSideEffectPutWithoutCorrectSlotStatus* create(VM& vm, Structure* structure)
     703    {
     704        DollarVMAssertScope assertScope;
     705        ObjectDoingSideEffectPutWithoutCorrectSlotStatus* accessor = new (NotNull, allocateCell<ObjectDoingSideEffectPutWithoutCorrectSlotStatus>(vm.heap)) ObjectDoingSideEffectPutWithoutCorrectSlotStatus(vm, structure);
     706        accessor->finishCreation(vm);
     707        return accessor;
     708    }
     709
     710    static bool put(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
     711    {
     712        DollarVMAssertScope assertScope;
     713        auto* thisObject = jsCast<ObjectDoingSideEffectPutWithoutCorrectSlotStatus*>(cell);
     714        auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm());
     715        auto* string = value.toString(globalObject);
     716        RETURN_IF_EXCEPTION(throwScope, false);
     717        RELEASE_AND_RETURN(throwScope, Base::put(thisObject, globalObject, propertyName, string, slot));
     718    }
     719};
     720
    685721class DOMJITNode : public JSNonFinalObject {
    686722public:
     
    13061342
    13071343const ClassInfo StaticCustomAccessor::s_info = { "StaticCustomAccessor", &Base::s_info, &staticCustomAccessorTable, nullptr, CREATE_METHOD_TABLE(StaticCustomAccessor) };
     1344const ClassInfo ObjectDoingSideEffectPutWithoutCorrectSlotStatus::s_info = { "ObjectDoingSideEffectPutWithoutCorrectSlotStatus", &Base::s_info, &staticCustomAccessorTable, nullptr, CREATE_METHOD_TABLE(ObjectDoingSideEffectPutWithoutCorrectSlotStatus) };
    13081345
    13091346ElementHandleOwner* Element::handleOwner()
     
    22572294}
    22582295
     2296static EncodedJSValue JSC_HOST_CALL functionCreateObjectDoingSideEffectPutWithoutCorrectSlotStatus(JSGlobalObject* globalObject, CallFrame* callFrame)
     2297{
     2298    DollarVMAssertScope assertScope;
     2299    VM& vm = globalObject->vm();
     2300    JSLockHolder lock(vm);
     2301
     2302    auto* dollarVM = jsDynamicCast<JSDollarVM*>(vm, callFrame->thisValue());
     2303    RELEASE_ASSERT(dollarVM);
     2304    auto* result = ObjectDoingSideEffectPutWithoutCorrectSlotStatus::create(vm, dollarVM->objectDoingSideEffectPutWithoutCorrectSlotStatusStructure());
     2305    return JSValue::encode(result);
     2306}
     2307
    22592308static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(JSGlobalObject* globalObject, CallFrame* callFrame)
    22602309{
     
    28012850#endif
    28022851    addFunction(vm, "createStaticCustomAccessor", functionCreateStaticCustomAccessor, 0);
     2852    addFunction(vm, "createObjectDoingSideEffectPutWithoutCorrectSlotStatus", functionCreateObjectDoingSideEffectPutWithoutCorrectSlotStatus, 0);
    28032853    addFunction(vm, "getPrivateProperty", functionGetPrivateProperty, 2);
    28042854    addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
     
    28472897    addFunction(vm, "isWasmSupported", functionIsWasmSupported, 0);
    28482898    addFunction(vm, "make16BitStringIfPossible", functionMake16BitStringIfPossible, 1);
     2899
     2900    m_objectDoingSideEffectPutWithoutCorrectSlotStatusStructure.set(vm, this, ObjectDoingSideEffectPutWithoutCorrectSlotStatus::createStructure(vm, globalObject, jsNull()));
    28492901}
    28502902
     
    28632915}
    28642916
     2917void JSDollarVM::visitChildren(JSCell* cell, SlotVisitor& visitor)
     2918{
     2919    JSDollarVM* thisObject = jsCast<JSDollarVM*>(cell);
     2920    Base::visitChildren(thisObject, visitor);
     2921    visitor.append(thisObject->m_objectDoingSideEffectPutWithoutCorrectSlotStatusStructure);
     2922}
     2923
    28652924} // namespace JSC
    28662925
Note: See TracChangeset for help on using the changeset viewer.