Inline Cache delete by id/val
authorjustin_michaud@apple.com <justin_michaud@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Feb 2020 01:38:46 +0000 (01:38 +0000)
committerjustin_michaud@apple.com <justin_michaud@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Feb 2020 01:38:46 +0000 (01:38 +0000)
https://bugs.webkit.org/show_bug.cgi?id=207522

JSTests:

Reviewed by Keith Miller and Filip Pizlo.

* microbenchmarks/delete-property-from-prototype-chain.js:
(delete.C.prototype.z):
* microbenchmarks/delete-property-inline-cache-polymorphic.js: Added.
(C):
(noInline.C.foo):
(noInline.foo.F):
(noInline.F):
* microbenchmarks/delete-property-inline-cache.js: Added.
(C):
(noInline.C.D):
(noInline.D.foo):
(noInline.foo.E):
(noInline.E.F):
(noInline.F):
* microbenchmarks/delete-property-keeps-cacheable-structure.js:
* stress/delete-property-check-structure-transition.js:
(sd): Deleted.
(testDeleteIsNotUncacheable): Deleted.
(): Deleted.
(testCanFlatten): Deleted.
(testDeleteWithInlineCache.Object.prototype.globalProperty.42.makeFoo): Deleted.
(testDeleteWithInlineCache.noInline.doTest): Deleted.
(testDeleteWithInlineCache): Deleted.
* stress/delete-property-inline-cache.js: Added.
(assert):
(assert_eq):
(assert_neq):
(assert_throws):
(noInline.assert.noInline.assert_eq.noInline.assert_neq.noInline.assert_throws.testCacheableDeleteById.makeFoo):
(noInline.assert.noInline.assert_eq.noInline.assert_neq.noInline.assert_throws.testCacheableDeleteById):
(noInline.testCacheableDeleteById.testCacheableDeleteByVal.makeFoo2):
(noInline.testCacheableDeleteById.testCacheableDeleteByVal):
(noInline.testCacheableDeleteByVal.testCacheableEmptyDeleteById.makeFoo3):
(noInline.testCacheableDeleteByVal.testCacheableEmptyDeleteById):
(noInline.testCacheableEmptyDeleteById.testCacheableDeleteByIdMiss.makeFoo4):
(noInline.testCacheableEmptyDeleteById.testCacheableDeleteByIdMiss):
(noInline.testCacheableDeleteByIdMiss.testDeleteIndex.makeFoo5):
(noInline.testCacheableDeleteByIdMiss.testDeleteIndex):
(noInline.testDeleteIndex.testPolymorphicDelByVal.makeFoo6):
(noInline.testDeleteIndex.testPolymorphicDelByVal):
(noInline.testPolymorphicDelByVal.testBigintDeleteByVal.makeFoo7):
(noInline.testPolymorphicDelByVal.testBigintDeleteByVal):
(noInline.testBigintDeleteByVal.testSymbolDeleteByVal.makeFoo8):
(noInline.testBigintDeleteByVal.testSymbolDeleteByVal):
(noInline.testSymbolDeleteByVal.testObjDeleteByVal.makeFoo9):
(noInline.testSymbolDeleteByVal.testObjDeleteByVal):
(noInline.testObjDeleteByVal.testStrict.makeFoo10):
(noInline.testObjDeleteByVal.testStrict):
(noInline.testStrict.testOverride.arr.j):
(noInline.testStrict.testOverride):
(noInline.testOverride.testNonObject.deleteIt):
(noInline.testOverride.testNonObject):
(noInline.testNonObject.testNonObjectStrict.deleteIt):
(noInline.testNonObject.testNonObjectStrict):
(noInline.testNonObjectStrict.testExceptionUnwind.mutateThem):
(noInline.testNonObjectStrict.testExceptionUnwind.noInline.deleteIt):
(noInline.testNonObjectStrict.testExceptionUnwind):
(noInline.testExceptionUnwind.testTDZ):
(noInline.testTDZ):

Source/JavaScriptCore:

Reviewed by Keith Miller and Filip Pizlo.

We add inline caching for deleteById/val for baseline only. We also fix a concurrency bug in ICStats used for testing.
We add three new access cases (no inline code is emitted at this time):
- Delete is a cached delete of an existing property
- DeleteMiss is a delete of a property that does not exist
- DeleteNonConfigurable is a delete of a property that exists, but should not be deleted.
There are no conditions required for these caches, since the structure id must change and the prototype does not matter.
This gives the following microbenchmark results:

delete-property-keeps-cacheable-structure (neutral)
delete-property-inline-cache              definitely 3.9096x faster
delete-property-inline-cache-polymorphic  definitely 1.5239x faster
delete-property-from-prototype-chain      (neutral)

* API/JSCallbackObject.h:
* API/JSCallbackObjectFunctions.h:
(JSC::JSCallbackObject<Parent>::deleteProperty):
(JSC::JSCallbackObject<Parent>::deletePropertyByIndex):
* API/JSObjectRef.cpp:
(JSObjectDeletePropertyForKey):
(JSObjectDeleteProperty):
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/AccessCase.cpp:
(JSC::AccessCase::create):
(JSC::AccessCase::createTransition):
(JSC::AccessCase::createDelete):
(JSC::AccessCase::requiresIdentifierNameMatch const):
(JSC::AccessCase::requiresInt32PropertyCheck const):
(JSC::AccessCase::needsScratchFPR const):
(JSC::AccessCase::forEachDependentCell const):
(JSC::AccessCase::doesCalls const):
(JSC::AccessCase::canReplace const):
(JSC::AccessCase::dump const):
(JSC::AccessCase::propagateTransitions const):
(JSC::AccessCase::generateImpl):
* bytecode/AccessCase.h:
(JSC::AccessCase::structure const):
(JSC::AccessCase::newStructure const):
* bytecode/PolymorphicAccess.cpp:
(WTF::printInternal):
* bytecode/StructureStubInfo.cpp:
(JSC::StructureStubInfo::reset):
* bytecode/StructureStubInfo.h:
* debugger/DebuggerScope.cpp:
(JSC::DebuggerScope::deleteProperty):
* debugger/DebuggerScope.h:
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::addDelById):
(JSC::DFG::JITCompiler::addDelByVal):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileDeleteById): Deleted.
(JSC::DFG::SpeculativeJIT::compileDeleteByVal): Deleted.
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileDeleteById):
(JSC::DFG::SpeculativeJIT::compileDeleteByVal):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileDeleteById):
(JSC::DFG::SpeculativeJIT::compileDeleteByVal):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileDelBy):
(JSC::FTL::DFG::LowerDFGToB3::compileDeleteById):
(JSC::FTL::DFG::LowerDFGToB3::compileDeleteByVal):
* jit/ICStats.h:
* jit/JIT.cpp:
(JSC::JIT::privateCompileSlowCases):
(JSC::JIT::link):
* jit/JIT.h:
* jit/JITInlineCacheGenerator.cpp:
(JSC::JITDelByValGenerator::JITDelByValGenerator):
(JSC::JITDelByValGenerator::generateFastPath):
(JSC::JITDelByValGenerator::finalize):
(JSC::JITDelByIdGenerator::JITDelByIdGenerator):
(JSC::JITDelByIdGenerator::generateFastPath):
(JSC::JITDelByIdGenerator::finalize):
* jit/JITInlineCacheGenerator.h:
(JSC::JITDelByValGenerator::JITDelByValGenerator):
(JSC::JITDelByValGenerator::slowPathJump const):
(JSC::JITDelByIdGenerator::JITDelByIdGenerator):
(JSC::JITDelByIdGenerator::slowPathJump const):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_del_by_id):
(JSC::JIT::emitSlow_op_del_by_id):
(JSC::JIT::emit_op_del_by_val):
(JSC::JIT::emitSlow_op_del_by_val):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_del_by_id):
(JSC::JIT::emit_op_del_by_val):
(JSC::JIT::emitSlow_op_del_by_val):
(JSC::JIT::emitSlow_op_del_by_id):
* jit/Repatch.cpp:
(JSC::tryCachePutByID):
(JSC::tryCacheDelBy):
(JSC::repatchDelBy):
(JSC::resetPutByID):
(JSC::resetDelBy):
* jit/Repatch.h:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* runtime/CacheableIdentifierInlines.h:
(JSC::CacheableIdentifier::CacheableIdentifier):
* runtime/ClassInfo.h:
* runtime/ClonedArguments.cpp:
(JSC::ClonedArguments::deleteProperty):
* runtime/ClonedArguments.h:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/DeletePropertySlot.h: Added.
(JSC::DeletePropertySlot::DeletePropertySlot):
(JSC::DeletePropertySlot::setConfigurableMiss):
(JSC::DeletePropertySlot::setNonconfigurable):
(JSC::DeletePropertySlot::setHit):
(JSC::DeletePropertySlot::isCacheableDelete const):
(JSC::DeletePropertySlot::isDeleteHit const):
(JSC::DeletePropertySlot::isConfigurableDeleteMiss const):
(JSC::DeletePropertySlot::isNonconfigurable const):
(JSC::DeletePropertySlot::cachedOffset const):
(JSC::DeletePropertySlot::disableCaching):
(JSC::DeletePropertySlot::isCacheable const):
* runtime/ErrorConstructor.cpp:
(JSC::ErrorConstructor::deleteProperty):
* runtime/ErrorConstructor.h:
* runtime/ErrorInstance.cpp:
(JSC::ErrorInstance::deleteProperty):
* runtime/ErrorInstance.h:
* runtime/GenericArguments.h:
* runtime/GenericArgumentsInlines.h:
(JSC::GenericArguments<Type>::put):
(JSC::GenericArguments<Type>::deleteProperty):
* runtime/GetterSetter.h:
* runtime/JSArray.cpp:
(JSC::JSArray::deleteProperty):
* runtime/JSArray.h:
* runtime/JSCJSValue.h:
* runtime/JSCell.cpp:
(JSC::JSCell::deleteProperty):
* runtime/JSCell.h:
* runtime/JSDataView.cpp:
(JSC::JSDataView::deleteProperty):
* runtime/JSDataView.h:
* runtime/JSFunction.cpp:
(JSC::JSFunction::deleteProperty):
* runtime/JSFunction.h:
* runtime/JSGenericTypedArrayView.h:
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::deleteProperty):
(JSC::JSGenericTypedArrayView<Adaptor>::deletePropertyByIndex):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::addFunction):
* runtime/JSLexicalEnvironment.cpp:
(JSC::JSLexicalEnvironment::deleteProperty):
* runtime/JSLexicalEnvironment.h:
* runtime/JSModuleEnvironment.cpp:
(JSC::JSModuleEnvironment::deleteProperty):
* runtime/JSModuleEnvironment.h:
* runtime/JSModuleNamespaceObject.cpp:
(JSC::JSModuleNamespaceObject::deleteProperty):
* runtime/JSModuleNamespaceObject.h:
* runtime/JSONObject.cpp:
(JSC::Walker::walk):
* runtime/JSObject.cpp:
(JSC::JSObject::deleteProperty):
(JSC::JSObject::deletePropertyByIndex):
(JSC::validateAndApplyPropertyDescriptor):
* runtime/JSObject.h:
* runtime/JSProxy.cpp:
(JSC::JSProxy::deleteProperty):
* runtime/JSProxy.h:
* runtime/JSSymbolTableObject.cpp:
(JSC::JSSymbolTableObject::deleteProperty):
* runtime/JSSymbolTableObject.h:
* runtime/ProxyObject.cpp:
(JSC::ProxyObject::deleteProperty):
* runtime/ProxyObject.h:
* runtime/RegExpObject.cpp:
(JSC::RegExpObject::deleteProperty):
* runtime/RegExpObject.h:
* runtime/StrictEvalActivation.cpp:
(JSC::StrictEvalActivation::deleteProperty):
* runtime/StrictEvalActivation.h:
* runtime/StringObject.cpp:
(JSC::StringObject::deleteProperty):
* runtime/StringObject.h:
* runtime/Structure.cpp:
(JSC::Structure::removePropertyTransition):
(JSC::Structure::removePropertyTransitionFromExistingStructureImpl):
(JSC::Structure::removePropertyTransitionFromExistingStructure):
(JSC::Structure::removePropertyTransitionFromExistingStructureConcurrently):
(JSC::Structure::removeNewPropertyTransition):
(JSC::Structure::dump const):
* runtime/Structure.h:
* runtime/StructureInlines.h:
(JSC::Structure::hasIndexingHeader const):
(JSC::Structure::mayHaveIndexingHeader const):
* tools/JSDollarVM.cpp:
(JSC::functionHasOwnLengthProperty):
(JSC::JSDollarVM::finishCreation):

Source/WebCore:

Reviewed by Keith Miller and Filip Pizlo.

* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::deleteProperty):
* bindings/js/JSLocationCustom.cpp:
(WebCore::JSLocation::deleteProperty):
* bindings/js/JSRemoteDOMWindowCustom.cpp:
(WebCore::JSRemoteDOMWindow::deleteProperty):
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateDeleteProperty):
(GenerateHeader):
(GenerateImplementation):
(GenerateConstructorHelperMethods):
* bindings/scripts/test/JS/JSTestEnabledBySetting.cpp:
(WebCore::JSTestEnabledBySettingPrototype::finishCreation):
* bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp:
(WebCore::JSTestGenerateIsReachablePrototype::finishCreation):
* bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.cpp:
(WebCore::JSTestNamedDeleterNoIdentifier::deleteProperty):
* bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.h:
* bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.cpp:
(WebCore::JSTestNamedDeleterThrowingException::deleteProperty):
* bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.h:
* bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.cpp:
(WebCore::JSTestNamedDeleterWithIdentifier::deleteProperty):
* bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.h:
* bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.cpp:
(WebCore::JSTestNamedDeleterWithIndexedGetter::deleteProperty):
* bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.h:
* bindings/scripts/test/JS/JSTestNode.cpp:
(WebCore::JSTestNodePrototype::finishCreation):
* bindings/scripts/test/JS/JSTestObj.cpp:
(WebCore::JSTestObjConstructor::initializeProperties):
(WebCore::JSTestObjPrototype::finishCreation):
* bridge/NP_jsobject.cpp:
* bridge/objc/WebScriptObject.mm:
(-[WebScriptObject removeWebScriptKey:]):
* bridge/objc/objc_runtime.h:
* bridge/objc/objc_runtime.mm:
(JSC::Bindings::ObjcFallbackObjectImp::deleteProperty):
* bridge/runtime_array.cpp:
(JSC::RuntimeArray::deleteProperty):
* bridge/runtime_array.h:
* bridge/runtime_object.cpp:
(JSC::Bindings::RuntimeObject::deleteProperty):
* bridge/runtime_object.h:

Source/WebKit:

Reviewed by Keith Miller and Filip Pizlo.

* WebProcess/Plugins/Netscape/JSNPObject.cpp:
(WebKit::JSNPObject::deleteProperty):
* WebProcess/Plugins/Netscape/JSNPObject.h:
* WebProcess/Plugins/Netscape/NPJSObject.cpp:
(WebKit::NPJSObject::removeProperty):

Source/WebKitLegacy/mac:

Reviewed by Keith Miller and Filip Pizlo.

* Plugins/Hosted/NetscapePluginInstanceProxy.mm:
(WebKit::NetscapePluginInstanceProxy::removeProperty):

Source/WTF:

Reviewed by Keith Miller and Filip Pizlo.

* wtf/Spectrum.h:
(WTF::Spectrum::add):
(WTF::Spectrum::get const):
(WTF::Spectrum::buildList const):
(WTF::Spectrum::clear):
(WTF::Spectrum::removeIf):
(WTF::Spectrum::begin): Deleted.
(WTF::Spectrum::end): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@257399 268f45cc-cd09-0410-ab3c-d52691b4dbfc

122 files changed:
JSTests/ChangeLog
JSTests/microbenchmarks/delete-property-from-prototype-chain.js
JSTests/microbenchmarks/delete-property-inline-cache-polymorphic.js [new file with mode: 0644]
JSTests/microbenchmarks/delete-property-inline-cache.js [new file with mode: 0644]
JSTests/microbenchmarks/delete-property-keeps-cacheable-structure.js
JSTests/stress/delete-property-check-structure-transition.js
JSTests/stress/delete-property-inline-cache.js [new file with mode: 0644]
Source/JavaScriptCore/API/JSCallbackObject.h
Source/JavaScriptCore/API/JSCallbackObjectFunctions.h
Source/JavaScriptCore/API/JSObjectRef.cpp
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/AccessCase.cpp
Source/JavaScriptCore/bytecode/AccessCase.h
Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp
Source/JavaScriptCore/bytecode/StructureStubInfo.cpp
Source/JavaScriptCore/bytecode/StructureStubInfo.h
Source/JavaScriptCore/debugger/DebuggerScope.cpp
Source/JavaScriptCore/debugger/DebuggerScope.h
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
Source/JavaScriptCore/dfg/DFGJITCompiler.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/ICStats.h
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp
Source/JavaScriptCore/jit/JITInlineCacheGenerator.h
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/jit/Repatch.cpp
Source/JavaScriptCore/jit/Repatch.h
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/runtime/CacheableIdentifierInlines.h
Source/JavaScriptCore/runtime/ClassInfo.h
Source/JavaScriptCore/runtime/ClonedArguments.cpp
Source/JavaScriptCore/runtime/ClonedArguments.h
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/DeletePropertySlot.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/ErrorConstructor.cpp
Source/JavaScriptCore/runtime/ErrorConstructor.h
Source/JavaScriptCore/runtime/ErrorInstance.cpp
Source/JavaScriptCore/runtime/ErrorInstance.h
Source/JavaScriptCore/runtime/GenericArguments.h
Source/JavaScriptCore/runtime/GenericArgumentsInlines.h
Source/JavaScriptCore/runtime/GetterSetter.h
Source/JavaScriptCore/runtime/JSArray.cpp
Source/JavaScriptCore/runtime/JSArray.h
Source/JavaScriptCore/runtime/JSCJSValue.h
Source/JavaScriptCore/runtime/JSCell.cpp
Source/JavaScriptCore/runtime/JSCell.h
Source/JavaScriptCore/runtime/JSDataView.cpp
Source/JavaScriptCore/runtime/JSDataView.h
Source/JavaScriptCore/runtime/JSFunction.cpp
Source/JavaScriptCore/runtime/JSFunction.h
Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h
Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp
Source/JavaScriptCore/runtime/JSLexicalEnvironment.h
Source/JavaScriptCore/runtime/JSModuleEnvironment.cpp
Source/JavaScriptCore/runtime/JSModuleEnvironment.h
Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp
Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h
Source/JavaScriptCore/runtime/JSONObject.cpp
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/JSProxy.cpp
Source/JavaScriptCore/runtime/JSProxy.h
Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
Source/JavaScriptCore/runtime/JSSymbolTableObject.h
Source/JavaScriptCore/runtime/ProxyObject.cpp
Source/JavaScriptCore/runtime/ProxyObject.h
Source/JavaScriptCore/runtime/RegExpObject.cpp
Source/JavaScriptCore/runtime/RegExpObject.h
Source/JavaScriptCore/runtime/StrictEvalActivation.cpp
Source/JavaScriptCore/runtime/StrictEvalActivation.h
Source/JavaScriptCore/runtime/StringObject.cpp
Source/JavaScriptCore/runtime/StringObject.h
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/Structure.h
Source/JavaScriptCore/runtime/StructureInlines.h
Source/JavaScriptCore/tools/JSDollarVM.cpp
Source/WTF/ChangeLog
Source/WTF/wtf/Spectrum.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
Source/WebCore/bindings/js/JSLocationCustom.cpp
Source/WebCore/bindings/js/JSRemoteDOMWindowCustom.cpp
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/test/JS/JSTestEnabledBySetting.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.h
Source/WebCore/bindings/scripts/test/JS/JSTestNode.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
Source/WebCore/bridge/NP_jsobject.cpp
Source/WebCore/bridge/objc/WebScriptObject.mm
Source/WebCore/bridge/objc/objc_runtime.h
Source/WebCore/bridge/objc/objc_runtime.mm
Source/WebCore/bridge/runtime_array.cpp
Source/WebCore/bridge/runtime_array.h
Source/WebCore/bridge/runtime_object.cpp
Source/WebCore/bridge/runtime_object.h
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/Plugins/Netscape/JSNPObject.cpp
Source/WebKit/WebProcess/Plugins/Netscape/JSNPObject.h
Source/WebKit/WebProcess/Plugins/Netscape/NPJSObject.cpp
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm

index 146a755..1f21e7c 100644 (file)
@@ -1,3 +1,70 @@
+2020-02-25  Justin Michaud  <justin_michaud@apple.com>
+
+        Inline Cache delete by id/val
+        https://bugs.webkit.org/show_bug.cgi?id=207522
+
+        Reviewed by Keith Miller and Filip Pizlo. 
+
+        * microbenchmarks/delete-property-from-prototype-chain.js:
+        (delete.C.prototype.z):
+        * microbenchmarks/delete-property-inline-cache-polymorphic.js: Added.
+        (C):
+        (noInline.C.foo):
+        (noInline.foo.F):
+        (noInline.F):
+        * microbenchmarks/delete-property-inline-cache.js: Added.
+        (C):
+        (noInline.C.D):
+        (noInline.D.foo):
+        (noInline.foo.E):
+        (noInline.E.F):
+        (noInline.F):
+        * microbenchmarks/delete-property-keeps-cacheable-structure.js:
+        * stress/delete-property-check-structure-transition.js:
+        (sd): Deleted.
+        (testDeleteIsNotUncacheable): Deleted.
+        (): Deleted.
+        (testCanFlatten): Deleted.
+        (testDeleteWithInlineCache.Object.prototype.globalProperty.42.makeFoo): Deleted.
+        (testDeleteWithInlineCache.noInline.doTest): Deleted.
+        (testDeleteWithInlineCache): Deleted.
+        * stress/delete-property-inline-cache.js: Added.
+        (assert):
+        (assert_eq):
+        (assert_neq):
+        (assert_throws):
+        (noInline.assert.noInline.assert_eq.noInline.assert_neq.noInline.assert_throws.testCacheableDeleteById.makeFoo):
+        (noInline.assert.noInline.assert_eq.noInline.assert_neq.noInline.assert_throws.testCacheableDeleteById):
+        (noInline.testCacheableDeleteById.testCacheableDeleteByVal.makeFoo2):
+        (noInline.testCacheableDeleteById.testCacheableDeleteByVal):
+        (noInline.testCacheableDeleteByVal.testCacheableEmptyDeleteById.makeFoo3):
+        (noInline.testCacheableDeleteByVal.testCacheableEmptyDeleteById):
+        (noInline.testCacheableEmptyDeleteById.testCacheableDeleteByIdMiss.makeFoo4):
+        (noInline.testCacheableEmptyDeleteById.testCacheableDeleteByIdMiss):
+        (noInline.testCacheableDeleteByIdMiss.testDeleteIndex.makeFoo5):
+        (noInline.testCacheableDeleteByIdMiss.testDeleteIndex):
+        (noInline.testDeleteIndex.testPolymorphicDelByVal.makeFoo6):
+        (noInline.testDeleteIndex.testPolymorphicDelByVal):
+        (noInline.testPolymorphicDelByVal.testBigintDeleteByVal.makeFoo7):
+        (noInline.testPolymorphicDelByVal.testBigintDeleteByVal):
+        (noInline.testBigintDeleteByVal.testSymbolDeleteByVal.makeFoo8):
+        (noInline.testBigintDeleteByVal.testSymbolDeleteByVal):
+        (noInline.testSymbolDeleteByVal.testObjDeleteByVal.makeFoo9):
+        (noInline.testSymbolDeleteByVal.testObjDeleteByVal):
+        (noInline.testObjDeleteByVal.testStrict.makeFoo10):
+        (noInline.testObjDeleteByVal.testStrict):
+        (noInline.testStrict.testOverride.arr.j):
+        (noInline.testStrict.testOverride):
+        (noInline.testOverride.testNonObject.deleteIt):
+        (noInline.testOverride.testNonObject):
+        (noInline.testNonObject.testNonObjectStrict.deleteIt):
+        (noInline.testNonObject.testNonObjectStrict):
+        (noInline.testNonObjectStrict.testExceptionUnwind.mutateThem):
+        (noInline.testNonObjectStrict.testExceptionUnwind.noInline.deleteIt):
+        (noInline.testNonObjectStrict.testExceptionUnwind):
+        (noInline.testExceptionUnwind.testTDZ):
+        (noInline.testTDZ):
+
 2020-02-19  Ross Kirsling  <ross.kirsling@sony.com>
 
         Computed Properties with increment sometimes produces incorrect results
index 49a31b7..54bba82 100644 (file)
@@ -1,4 +1,4 @@
-//@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
+//@ skip if $model =~ /^Apple Watch/
 function assert(b) {
     if (!b)
         throw new Error;
@@ -28,7 +28,7 @@ function doTest(zVal) {
 }
 noInline(doTest);
 
-for (let i=0; i<10000; ++i) {
+for (let i = 0; i < 10000; ++i) {
     const X = { i }
     C.prototype.z = X
     doTest(X)
@@ -36,7 +36,7 @@ for (let i=0; i<10000; ++i) {
 
 delete C.prototype.z
 
-for (let i=0; i<1000000; ++i) {
+for (let i = 0; i < 2000000; ++i) {
     getZ({z: i})
     doTest(undefined)
 }
diff --git a/JSTests/microbenchmarks/delete-property-inline-cache-polymorphic.js b/JSTests/microbenchmarks/delete-property-inline-cache-polymorphic.js
new file mode 100644 (file)
index 0000000..a6b86d5
--- /dev/null
@@ -0,0 +1,41 @@
+//@ skip if $model =~ /^Apple Watch/
+
+function C(prop) {
+    this[prop] = 4
+    delete this[prop]
+}
+noInline(C)
+
+function foo(o, prop) {
+    delete o[prop]
+}
+noInline(foo)
+
+function F(prop) {
+    this[prop] = 4
+    foo(this, prop)
+}
+noInline(F)
+
+for (let i = 0; i < 100000; ++i) {
+    new C("foo1")
+    new F("foo1")
+    new C("foo2")
+    new F("foo2")
+    new C("foo3")
+    new F("foo3")
+    new C("foo4")
+    new F("foo4")
+    new C("foo5")
+    new F("foo5")
+    new C("foo6")
+    new F("foo6")
+    new C("foo7")
+    new F("foo7")
+    new C("foo8")
+    new F("foo8")
+    new C("foo9")
+    new F("foo9")
+    new C("foo10")
+    new F("foo10")
+}
diff --git a/JSTests/microbenchmarks/delete-property-inline-cache.js b/JSTests/microbenchmarks/delete-property-inline-cache.js
new file mode 100644 (file)
index 0000000..c00863c
--- /dev/null
@@ -0,0 +1,35 @@
+//@ skip if $model =~ /^Apple Watch/
+
+function C() {
+    this.x = 4;
+    delete this.x
+}
+noInline(C)
+
+function D() {
+    delete this.x
+}
+noInline(D)
+
+function foo(o) {
+    delete o.x
+}
+noInline(foo)
+
+function E() {
+    this.x = 4
+    foo(this)
+}
+noInline(E)
+
+function F() {
+    foo(this)
+}
+noInline(F)
+
+for (let i = 0; i < 10000000; ++i) {
+    new C
+    new D
+    new E
+    new F
+}
index 7795dc5..a939aae 100644 (file)
@@ -24,5 +24,5 @@ function doTest() {
 }
 noInline(doTest);
 
-for (let i=0; i<10000000; ++i) doTest()
+for (let i = 0; i < 5000000; ++i) doTest()
 
index 403c7c0..a4ba1e4 100644 (file)
@@ -12,6 +12,9 @@ function assert_neq(a, b) {
     if (a === b)
         throw new Error("assertion failed: " + a + " !== " + b);
 }
+noInline(assert)
+noInline(assert_eq)
+noInline(assert_neq)
 
 function sd(obj) {
     let data = $vm.getStructureTransitionList(obj)
@@ -31,6 +34,8 @@ function sid(obj) {
     let data = sd(obj)
     return data[data.length-1].id
 }
+noInline(sd)
+noInline(sid)
 
 function testDeleteIsNotUncacheable(i) {
     let foo = {}
@@ -62,6 +67,7 @@ function testDeleteIsNotUncacheable(i) {
     assert_eq($vm.getConcurrently(foo, "bar"+i), 1)
     assert(foo["bar" + i] === 1)
 }
+noInline(testDeleteIsNotUncacheable)
 
 function testCanMaterializeDeletes(i) {
     let foo = {}
@@ -100,6 +106,8 @@ function testCanMaterializeDeletes(i) {
     assert_eq(data[data.length-2].property, "bar" + i)
 }
 
+noInline(testCanMaterializeDeletes)
+
 function testCanFlatten(i) {
     let foo = {}
     for (let j=0; j<500; ++j) {
@@ -131,6 +139,7 @@ function testCanFlatten(i) {
             assert_eq(val, undefined)
     }
 }
+noInline(testCanFlatten)
 
 function testDeleteWithInlineCache() {
     Object.prototype.globalProperty = 42
@@ -175,6 +184,7 @@ function testDeleteWithInlineCache() {
 
     doTest(undefined)
 }
+noInline(testDeleteWithInlineCache)
 
 testDeleteWithInlineCache()
 
diff --git a/JSTests/stress/delete-property-inline-cache.js b/JSTests/stress/delete-property-inline-cache.js
new file mode 100644 (file)
index 0000000..3df00d5
--- /dev/null
@@ -0,0 +1,568 @@
+//@ runDefault("--useBigInt=true")
+
+function assert(condition) {
+    if (!condition)
+        throw new Error("assertion failed");
+}
+
+function assert_eq(a, b) {
+    if (a !== b)
+        throw new Error("assertion failed: " + a + " === " + b);
+}
+
+function assert_neq(a, b) {
+    if (a === b)
+        throw new Error("assertion failed: " + a + " !== " + b);
+}
+
+function assert_throws(fun) {
+    let threw = false;
+    try {
+        fun()
+    } catch {
+        threw = true
+    }
+    assert(threw)
+}
+noInline(assert)
+noInline(assert_eq)
+noInline(assert_neq)
+noInline(assert_throws)
+
+function testCacheableDeleteById() {
+    function makeFoo() {
+        let foo = {}
+        foo.baz = 1
+        foo.bar = 2
+        delete foo.baz
+        return foo
+    }
+    noInline(makeFoo)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = makeFoo()
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert(foo.bar === 2)
+        assert_eq(Object.keys(foo).length, 1)
+        assert(!("baz" in foo))
+        foo.bag = 1
+        assert(foo.bag == 1)
+        foo["bug" + j] = 3
+        assert(foo["bug" + j] == 3)
+        assert(!("baz" in foo))
+    }
+}
+noInline(testCacheableDeleteById)
+
+function testCacheableDeleteByVal() {
+    function makeFoo2() {
+        let foo = {}
+        foo.baz = 1
+        foo.bar = 2
+        delete foo["baz"]
+        return foo
+    }
+    noInline(makeFoo2)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = makeFoo2()
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert(foo.bar === 2)
+        assert_eq(Object.keys(foo).length, 1)
+        assert(!("baz" in foo))
+        foo.bag = 1
+        assert(foo.bag == 1)
+        foo["bug" + j] = 3
+        assert(foo["bug" + j] == 3)
+        assert(!("baz" in foo))
+
+    }
+}
+noInline(testCacheableDeleteByVal)
+
+function testCacheableEmptyDeleteById() {
+    function makeFoo3() {
+        let foo = {}
+        foo.baz = 1
+        foo.bar = 2
+        assert_eq(delete foo.bar, true)
+        delete foo.baz
+        return foo
+    }
+    noInline(makeFoo3)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = makeFoo3()
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert_eq(Object.keys(foo).length, 0)
+        assert(!("baz" in foo))
+        assert(!("bar" in foo))
+        foo.bag = 1
+        assert(foo.bag == 1)
+        foo["bug" + j] = 3
+        assert(foo["bug" + j] == 3)
+        assert(!("baz" in foo))
+        assert(!("bar" in foo))
+    }
+}
+noInline(testCacheableEmptyDeleteById)
+
+function testCacheableDeleteByIdMiss() {
+    function makeFoo4() {
+        let foo = {}
+        foo.baz = 1
+        foo.bar = 2
+        assert_eq(delete foo.baz, true)
+        assert_eq(delete foo.baz, true)
+        assert_eq(delete foo.baz, true)
+
+        Object.defineProperty(foo, 'foobar', {
+          value: 42,
+          configurable: false
+        });
+        assert_eq(delete foo.foobar, false)
+        assert_eq(delete foo.foobar, false)
+        assert_eq(foo.foobar, 42)
+        return foo
+    }
+    noInline(makeFoo4)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = makeFoo4()
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert(foo.bar === 2)
+        assert_eq(Object.keys(foo).length, 1)
+        assert(!("baz" in foo))
+        foo.bag = 1
+        assert(foo.bag == 1)
+        foo["bug" + j] = 3
+        assert(foo["bug" + j] == 3)
+        assert(!("baz" in foo))
+    }
+}
+noInline(testCacheableDeleteByIdMiss)
+
+function testDeleteIndex() {
+    function makeFoo5() {
+        let foo = {}
+        foo.baz = 1
+        foo.bar = 2
+        foo[0] = 23
+        foo[1] = 25
+        assert_eq(delete foo.bar, true)
+        assert_eq(delete foo[1], true)
+        delete foo.baz
+        return foo
+    }
+    noInline(makeFoo5)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = makeFoo5()
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert_eq(Object.keys(foo).length, 1)
+        assert(!("baz" in foo))
+        assert(!("bar" in foo))
+        foo.bag = 1
+        assert(foo.bag == 1)
+        foo["bug" + j] = 3
+        assert(foo["bug" + j] == 3)
+        assert(!("baz" in foo))
+        assert(!("bar" in foo))
+        assert_eq(foo[0], 23)
+        assert_eq(foo[1], undefined)
+        foo[1] = 1
+        assert_eq(foo[1], 1)
+    }
+}
+noInline(testDeleteIndex)
+
+function testPolymorphicDelByVal(i) {
+    function makeFoo6() {
+        let foo = {}
+        foo["baz"+i] = 1
+        foo.bar = 2
+        delete foo["baz"+i]
+        return foo
+    }
+    noInline(makeFoo6)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = makeFoo6()
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert(foo.bar === 2)
+        assert_eq(Object.keys(foo).length, 1)
+        assert(!("baz"+i in foo))
+        foo.bag = 1
+        assert(foo.bag == 1)
+        foo["bug" + j] = 3
+        assert(foo["bug" + j] == 3)
+        assert(!("baz"+i in foo))
+
+    }
+}
+noInline(testPolymorphicDelByVal)
+
+function testBigintDeleteByVal() {
+    function makeFoo7() {
+        let foo = {}
+        foo[1234567890123456789012345678901234567890n] = 1
+        foo.bar = 2
+        delete foo[1234567890123456789012345678901234567890n]
+        return foo
+    }
+    noInline(makeFoo7)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = makeFoo7()
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert(foo.bar === 2)
+        assert_eq(Object.keys(foo).length, 1)
+        assert(!(1234567890123456789012345678901234567890n in foo))
+        foo.bag = 1
+        assert(foo.bag == 1)
+        foo["bug" + j] = 3
+        assert(foo["bug" + j] == 3)
+        assert(!("baz" in foo))
+
+    }
+}
+noInline(testBigintDeleteByVal)
+
+function testSymbolDeleteByVal() {
+    const symbol = Symbol('foo');
+
+    function makeFoo8() {
+        let foo = {}
+        foo[symbol] = 1
+        assert(!(Symbol('foo') in foo))
+        assert(symbol in foo)
+        foo.bar = 2
+        delete foo[symbol]
+        return foo
+    }
+    noInline(makeFoo8)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = makeFoo8()
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert(foo.bar === 2)
+        assert_eq(Object.keys(foo).length, 1)
+        assert(!(symbol in foo))
+        foo.bag = 1
+        assert(foo.bag == 1)
+        foo["bug" + j] = 3
+        assert(foo["bug" + j] == 3)
+        assert(!("baz" in foo))
+
+    }
+}
+noInline(testSymbolDeleteByVal)
+
+function testObjDeleteByVal() {
+    const symbol = { i: "foo" };
+
+    function makeFoo9() {
+        let foo = {}
+        foo[symbol] = 1
+        assert(symbol in foo)
+        assert(!({ i: "foo" } in foo))
+        foo.bar = 2
+        delete foo[symbol]
+        return foo
+    }
+    noInline(makeFoo9)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = makeFoo9()
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert(foo.bar === 2)
+        assert_eq(Object.keys(foo).length, 1)
+        assert(!(symbol in foo))
+        foo.bag = 1
+        assert(foo.bag == 1)
+        foo["bug" + j] = 3
+        assert(foo["bug" + j] == 3)
+        assert(!("baz" in foo))
+
+    }
+}
+noInline(testObjDeleteByVal)
+
+function testStrict() {
+    "use strict";
+
+    function makeFoo10() {
+        let foo = {}
+        foo.baz = 1
+        foo.bar = 2
+        assert_eq(delete foo.baz, true)
+        assert_eq(delete foo.baz, true)
+
+        Object.defineProperty(foo, 'foobar', {
+          value: 42,
+          configurable: false
+        });
+        assert_throws(() => delete foo.foobar)
+        assert_eq(foo.foobar, 42)
+        return foo
+    }
+    noInline(makeFoo10)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = makeFoo10()
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert(foo.bar === 2)
+        assert_eq(Object.keys(foo).length, 1)
+        assert(!("baz" in foo))
+        foo.bag = 1
+        assert(foo.bag == 1)
+        foo["bug" + j] = 3
+        assert(foo["bug" + j] == 3)
+        assert(!("baz" in foo))
+    }
+}
+noInline(testStrict)
+
+function testOverride() {
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = function() { }
+        assert_eq($vm.hasOwnLengthProperty(arr[j]), true)
+        delete arr[j].length
+        assert_eq($vm.hasOwnLengthProperty(arr[j]), false)
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert_eq(Object.keys(foo).length, 0)
+        assert(!("baz" in foo))
+        foo.bag = 1
+        assert(foo.bag == 1)
+        foo["bug" + j] = 3
+        assert(foo["bug" + j] == 3)
+        assert(!("baz" in foo))
+    }
+}
+noInline(testOverride)
+
+function testNonObject() {
+    function deleteIt(foo) {
+        assert(delete foo.baz)
+        return foo
+    }
+    noInline(deleteIt)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = { baz: j }
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert("baz" in foo)
+        deleteIt(foo)
+        assert(!("baz" in foo))
+    }
+
+    assert(deleteIt("baz") == "baz")
+    deleteIt(Symbol("hi"))
+}
+noInline(testNonObject)
+
+function testNonObjectStrict() {
+    "use strict";
+
+    function deleteIt(foo) {
+        assert(delete foo["baz"])
+        return foo
+    }
+    noInline(deleteIt)
+
+    arr = new Array(50)
+
+    for (let j = 0; j < 50; ++j) {
+        arr[j] = { baz: j }
+    }
+
+    for (let j = 0; j < 50; ++j) {
+        const foo = arr[j]
+
+        assert("baz" in foo)
+        deleteIt(foo)
+        deleteIt(5)
+        assert(!("baz" in foo))
+    }
+
+    assert(deleteIt("baz") == "baz")
+    deleteIt(Symbol("hi"))
+
+    let foo = {}
+    Object.defineProperty(foo, 'baz', {
+      value: 42,
+      configurable: false
+    });
+    assert_throws(() => deleteIt(foo))
+}
+noInline(testNonObjectStrict)
+
+function testExceptionUnwind() {
+    "use strict";
+
+    function mutateThem(a,b,c,d,e,f,g,h,i) {
+        g.i = 42
+    }
+    noInline(mutateThem)
+
+    function deleteIt(foo) {
+        let caught = false
+
+        try {
+            var a = { i: 1 }
+            var v = { i: 10 }
+            var b = { i: 100 }
+            var c = { i: 1000 }
+            var d = { i: 10000 }
+            var e = { i: 100000 }
+            var f = { i: 1000000 }
+            var g = { i: 10000000 }
+            var h = { i: 100000000 }
+            var i = { i: 1000000000 }
+
+            mutateThem(a,b,c,d,e,f,g,h,i)
+
+            delete foo["baz"]
+
+            a = b = c = d = e = f = g = h = i
+        } catch {
+            assert_eq(a.i, 1)
+            assert_eq(i.i, 1000000000)
+            assert_eq(g.i, 42)
+            caught = true
+        }
+        return caught
+    }
+    noInline(deleteIt)
+
+    for (let j = 0; j < 100000; ++j) {
+        assert(!deleteIt({ j, baz: 5 }))
+    }
+
+    let foo = {}
+    Object.defineProperty(foo, 'baz', {
+      value: 42,
+      configurable: false
+    });
+
+    assert(deleteIt(foo))
+}
+noInline(testExceptionUnwind)
+
+function testTDZ() {
+    delete foo.x
+    let foo = { x: 5 }
+}
+noInline(testTDZ)
+
+function testPolyProto() {
+    function makeFoo11() {
+        class C {
+            constructor() {
+                this.x = 42
+            }
+        }
+        return new C
+    }
+    noInline(makeFoo11)
+
+    for (let i = 0; i < 1000; ++i) {
+        let o = makeFoo11()
+        assert_eq(o.x, 42)
+        assert(delete o.x)
+        assert(!("x" in o))
+
+    }
+}
+noInline(testPolyProto)
+
+for (let i = 0; i < 1000; ++i) {
+    testCacheableDeleteById()
+    testCacheableDeleteByVal()
+    testCacheableEmptyDeleteById()
+    testCacheableDeleteByIdMiss()
+    testDeleteIndex()
+    testPolymorphicDelByVal(i)
+    testBigintDeleteByVal()
+    testSymbolDeleteByVal()
+    testStrict()
+    testOverride()
+    testNonObject()
+    testNonObjectStrict()
+    assert_throws(testTDZ)
+    testPolyProto()
+}
+
+testExceptionUnwind()
index 034b357..92ca924 100644 (file)
@@ -202,7 +202,7 @@ private:
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     static bool putByIndex(JSCell*, JSGlobalObject*, unsigned, JSValue, bool shouldThrow);
 
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned);
 
     static bool customHasInstance(JSObject*, JSGlobalObject*, JSValue);
index cd511bf..02cedc7 100644 (file)
@@ -373,7 +373,7 @@ bool JSCallbackObject<Parent>::putByIndex(JSCell* cell, JSGlobalObject* globalOb
 }
 
 template <class Parent>
-bool JSCallbackObject<Parent>::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool JSCallbackObject<Parent>::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     VM& vm = getVM(globalObject);
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -418,7 +418,7 @@ bool JSCallbackObject<Parent>::deleteProperty(JSCell* cell, JSGlobalObject* glob
         }
     }
 
-    return Parent::deleteProperty(thisObject, globalObject, propertyName);
+    return Parent::deleteProperty(thisObject, globalObject, propertyName, slot);
 }
 
 template <class Parent>
@@ -426,7 +426,7 @@ bool JSCallbackObject<Parent>::deletePropertyByIndex(JSCell* cell, JSGlobalObjec
 {
     VM& vm = getVM(globalObject);
     JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell);
-    return thisObject->methodTable(vm)->deleteProperty(thisObject, globalObject, Identifier::from(vm, propertyName));
+    return JSCell::deleteProperty(thisObject, globalObject, Identifier::from(vm, propertyName));
 }
 
 template <class Parent>
index f7f9dab..9db8528 100644 (file)
@@ -479,7 +479,7 @@ bool JSObjectDeletePropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueR
     if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow)
         return false;
 
-    bool result = jsObject->methodTable(vm)->deleteProperty(jsObject, globalObject, ident);
+    bool result = JSCell::deleteProperty(jsObject, globalObject, ident);
     handleExceptionIfNeeded(scope, ctx, exception);
     return result;
 }
@@ -534,7 +534,7 @@ bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr
 
     JSObject* jsObject = toJS(object);
 
-    bool result = jsObject->methodTable(vm)->deleteProperty(jsObject, globalObject, propertyName->identifier(&vm));
+    bool result = JSCell::deleteProperty(jsObject, globalObject, propertyName->identifier(&vm));
     handleExceptionIfNeeded(scope, ctx, exception);
     return result;
 }
index 91e427c..7556e95 100644 (file)
@@ -815,6 +815,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
     runtime/DateInstance.h
     runtime/DateInstanceCache.h
     runtime/DefinePropertyAttributes.h
+    runtime/DeletePropertySlot.h
     runtime/DirectArgumentsOffset.h
     runtime/DirectEvalExecutable.h
     runtime/DisallowScope.h
index 00d9174..e16eb4b 100644 (file)
@@ -1,3 +1,213 @@
+2020-02-25  Justin Michaud  <justin_michaud@apple.com>
+
+        Inline Cache delete by id/val
+        https://bugs.webkit.org/show_bug.cgi?id=207522
+
+        Reviewed by Keith Miller and Filip Pizlo.
+
+        We add inline caching for deleteById/val for baseline only. We also fix a concurrency bug in ICStats used for testing.
+        We add three new access cases (no inline code is emitted at this time): 
+        - Delete is a cached delete of an existing property
+        - DeleteMiss is a delete of a property that does not exist
+        - DeleteNonConfigurable is a delete of a property that exists, but should not be deleted.
+        There are no conditions required for these caches, since the structure id must change and the prototype does not matter.
+        This gives the following microbenchmark results:
+
+        delete-property-keeps-cacheable-structure (neutral)
+        delete-property-inline-cache              definitely 3.9096x faster
+        delete-property-inline-cache-polymorphic  definitely 1.5239x faster
+        delete-property-from-prototype-chain      (neutral)
+
+        * API/JSCallbackObject.h:
+        * API/JSCallbackObjectFunctions.h:
+        (JSC::JSCallbackObject<Parent>::deleteProperty):
+        (JSC::JSCallbackObject<Parent>::deletePropertyByIndex):
+        * API/JSObjectRef.cpp:
+        (JSObjectDeletePropertyForKey):
+        (JSObjectDeleteProperty):
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/AccessCase.cpp:
+        (JSC::AccessCase::create):
+        (JSC::AccessCase::createTransition):
+        (JSC::AccessCase::createDelete):
+        (JSC::AccessCase::requiresIdentifierNameMatch const):
+        (JSC::AccessCase::requiresInt32PropertyCheck const):
+        (JSC::AccessCase::needsScratchFPR const):
+        (JSC::AccessCase::forEachDependentCell const):
+        (JSC::AccessCase::doesCalls const):
+        (JSC::AccessCase::canReplace const):
+        (JSC::AccessCase::dump const):
+        (JSC::AccessCase::propagateTransitions const):
+        (JSC::AccessCase::generateImpl):
+        * bytecode/AccessCase.h:
+        (JSC::AccessCase::structure const):
+        (JSC::AccessCase::newStructure const):
+        * bytecode/PolymorphicAccess.cpp:
+        (WTF::printInternal):
+        * bytecode/StructureStubInfo.cpp:
+        (JSC::StructureStubInfo::reset):
+        * bytecode/StructureStubInfo.h:
+        * debugger/DebuggerScope.cpp:
+        (JSC::DebuggerScope::deleteProperty):
+        * debugger/DebuggerScope.h:
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::link):
+        * dfg/DFGJITCompiler.h:
+        (JSC::DFG::JITCompiler::addDelById):
+        (JSC::DFG::JITCompiler::addDelByVal):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileDeleteById): Deleted.
+        (JSC::DFG::SpeculativeJIT::compileDeleteByVal): Deleted.
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compileDeleteById):
+        (JSC::DFG::SpeculativeJIT::compileDeleteByVal):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compileDeleteById):
+        (JSC::DFG::SpeculativeJIT::compileDeleteByVal):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileDelBy):
+        (JSC::FTL::DFG::LowerDFGToB3::compileDeleteById):
+        (JSC::FTL::DFG::LowerDFGToB3::compileDeleteByVal):
+        * jit/ICStats.h:
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileSlowCases):
+        (JSC::JIT::link):
+        * jit/JIT.h:
+        * jit/JITInlineCacheGenerator.cpp:
+        (JSC::JITDelByValGenerator::JITDelByValGenerator):
+        (JSC::JITDelByValGenerator::generateFastPath):
+        (JSC::JITDelByValGenerator::finalize):
+        (JSC::JITDelByIdGenerator::JITDelByIdGenerator):
+        (JSC::JITDelByIdGenerator::generateFastPath):
+        (JSC::JITDelByIdGenerator::finalize):
+        * jit/JITInlineCacheGenerator.h:
+        (JSC::JITDelByValGenerator::JITDelByValGenerator):
+        (JSC::JITDelByValGenerator::slowPathJump const):
+        (JSC::JITDelByIdGenerator::JITDelByIdGenerator):
+        (JSC::JITDelByIdGenerator::slowPathJump const):
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_del_by_id):
+        (JSC::JIT::emitSlow_op_del_by_id):
+        (JSC::JIT::emit_op_del_by_val):
+        (JSC::JIT::emitSlow_op_del_by_val):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_del_by_id):
+        (JSC::JIT::emit_op_del_by_val):
+        (JSC::JIT::emitSlow_op_del_by_val):
+        (JSC::JIT::emitSlow_op_del_by_id):
+        * jit/Repatch.cpp:
+        (JSC::tryCachePutByID):
+        (JSC::tryCacheDelBy):
+        (JSC::repatchDelBy):
+        (JSC::resetPutByID):
+        (JSC::resetDelBy):
+        * jit/Repatch.h:
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * runtime/CacheableIdentifierInlines.h:
+        (JSC::CacheableIdentifier::CacheableIdentifier):
+        * runtime/ClassInfo.h:
+        * runtime/ClonedArguments.cpp:
+        (JSC::ClonedArguments::deleteProperty):
+        * runtime/ClonedArguments.h:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/DeletePropertySlot.h: Added.
+        (JSC::DeletePropertySlot::DeletePropertySlot):
+        (JSC::DeletePropertySlot::setConfigurableMiss):
+        (JSC::DeletePropertySlot::setNonconfigurable):
+        (JSC::DeletePropertySlot::setHit):
+        (JSC::DeletePropertySlot::isCacheableDelete const):
+        (JSC::DeletePropertySlot::isDeleteHit const):
+        (JSC::DeletePropertySlot::isConfigurableDeleteMiss const):
+        (JSC::DeletePropertySlot::isNonconfigurable const):
+        (JSC::DeletePropertySlot::cachedOffset const):
+        (JSC::DeletePropertySlot::disableCaching):
+        (JSC::DeletePropertySlot::isCacheable const):
+        * runtime/ErrorConstructor.cpp:
+        (JSC::ErrorConstructor::deleteProperty):
+        * runtime/ErrorConstructor.h:
+        * runtime/ErrorInstance.cpp:
+        (JSC::ErrorInstance::deleteProperty):
+        * runtime/ErrorInstance.h:
+        * runtime/GenericArguments.h:
+        * runtime/GenericArgumentsInlines.h:
+        (JSC::GenericArguments<Type>::put):
+        (JSC::GenericArguments<Type>::deleteProperty):
+        * runtime/GetterSetter.h:
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::deleteProperty):
+        * runtime/JSArray.h:
+        * runtime/JSCJSValue.h:
+        * runtime/JSCell.cpp:
+        (JSC::JSCell::deleteProperty):
+        * runtime/JSCell.h:
+        * runtime/JSDataView.cpp:
+        (JSC::JSDataView::deleteProperty):
+        * runtime/JSDataView.h:
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::deleteProperty):
+        * runtime/JSFunction.h:
+        * runtime/JSGenericTypedArrayView.h:
+        * runtime/JSGenericTypedArrayViewInlines.h:
+        (JSC::JSGenericTypedArrayView<Adaptor>::deleteProperty):
+        (JSC::JSGenericTypedArrayView<Adaptor>::deletePropertyByIndex):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::addFunction):
+        * runtime/JSLexicalEnvironment.cpp:
+        (JSC::JSLexicalEnvironment::deleteProperty):
+        * runtime/JSLexicalEnvironment.h:
+        * runtime/JSModuleEnvironment.cpp:
+        (JSC::JSModuleEnvironment::deleteProperty):
+        * runtime/JSModuleEnvironment.h:
+        * runtime/JSModuleNamespaceObject.cpp:
+        (JSC::JSModuleNamespaceObject::deleteProperty):
+        * runtime/JSModuleNamespaceObject.h:
+        * runtime/JSONObject.cpp:
+        (JSC::Walker::walk):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::deleteProperty):
+        (JSC::JSObject::deletePropertyByIndex):
+        (JSC::validateAndApplyPropertyDescriptor):
+        * runtime/JSObject.h:
+        * runtime/JSProxy.cpp:
+        (JSC::JSProxy::deleteProperty):
+        * runtime/JSProxy.h:
+        * runtime/JSSymbolTableObject.cpp:
+        (JSC::JSSymbolTableObject::deleteProperty):
+        * runtime/JSSymbolTableObject.h:
+        * runtime/ProxyObject.cpp:
+        (JSC::ProxyObject::deleteProperty):
+        * runtime/ProxyObject.h:
+        * runtime/RegExpObject.cpp:
+        (JSC::RegExpObject::deleteProperty):
+        * runtime/RegExpObject.h:
+        * runtime/StrictEvalActivation.cpp:
+        (JSC::StrictEvalActivation::deleteProperty):
+        * runtime/StrictEvalActivation.h:
+        * runtime/StringObject.cpp:
+        (JSC::StringObject::deleteProperty):
+        * runtime/StringObject.h:
+        * runtime/Structure.cpp:
+        (JSC::Structure::removePropertyTransition):
+        (JSC::Structure::removePropertyTransitionFromExistingStructureImpl):
+        (JSC::Structure::removePropertyTransitionFromExistingStructure):
+        (JSC::Structure::removePropertyTransitionFromExistingStructureConcurrently):
+        (JSC::Structure::removeNewPropertyTransition):
+        (JSC::Structure::dump const):
+        * runtime/Structure.h:
+        * runtime/StructureInlines.h:
+        (JSC::Structure::hasIndexingHeader const):
+        (JSC::Structure::mayHaveIndexingHeader const):
+        * tools/JSDollarVM.cpp:
+        (JSC::functionHasOwnLengthProperty):
+        (JSC::JSDollarVM::finishCreation):
+
 2020-02-24  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [WTF] Attach WARN_UNUSED_RETURN to makeScopeExit and fix existing wrong usage
index af42c2a..fb74565 100644 (file)
                70ECA6061AFDBEA200449739 /* JSTemplateObjectDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 70ECA6011AFDBEA200449739 /* JSTemplateObjectDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; };
                70ECA6091AFDBEA200449739 /* TemplateObjectDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 70ECA6041AFDBEA200449739 /* TemplateObjectDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; };
                72AAF7CE1D0D31B3005E60BE /* JSCustomGetterSetterFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 72AAF7CC1D0D318B005E60BE /* JSCustomGetterSetterFunction.h */; };
+               734B655523F5C10400A069D1 /* DeletePropertySlot.h in Headers */ = {isa = PBXBuildFile; fileRef = 734B655423F4A33100A069D1 /* DeletePropertySlot.h */; settings = {ATTRIBUTES = (Private, ); }; };
                73E3799422E0EF6500933565 /* B3ReduceLoopStrength.h in Headers */ = {isa = PBXBuildFile; fileRef = 73E3799322E0EF4F00933565 /* B3ReduceLoopStrength.h */; };
                7593C898BE714A64BE93A6E7 /* WasmContextInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = A27958D7FA1142B0AC9E364D /* WasmContextInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
                790081391E95A8EC0052D7CD /* WasmModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 790081371E95A8EC0052D7CD /* WasmModule.h */; settings = {ATTRIBUTES = (Private, ); }; };
                70ECA6041AFDBEA200449739 /* TemplateObjectDescriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateObjectDescriptor.h; sourceTree = "<group>"; };
                72AAF7CB1D0D318B005E60BE /* JSCustomGetterSetterFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCustomGetterSetterFunction.cpp; sourceTree = "<group>"; };
                72AAF7CC1D0D318B005E60BE /* JSCustomGetterSetterFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCustomGetterSetterFunction.h; sourceTree = "<group>"; };
+               734B655423F4A33100A069D1 /* DeletePropertySlot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeletePropertySlot.h; sourceTree = "<group>"; };
                73E3799322E0EF4F00933565 /* B3ReduceLoopStrength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3ReduceLoopStrength.h; path = b3/B3ReduceLoopStrength.h; sourceTree = "<group>"; };
                73E3799522E0EF9100933565 /* B3ReduceLoopStrength.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3ReduceLoopStrength.cpp; path = b3/B3ReduceLoopStrength.cpp; sourceTree = "<group>"; };
                77B25CB2C3094A92A38E1DB3 /* JSModuleLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModuleLoader.h; sourceTree = "<group>"; };
                                BCD203470E17135E002C7E82 /* DatePrototype.cpp */,
                                BCD203480E17135E002C7E82 /* DatePrototype.h */,
                                169948EDE68D4054B01EF797 /* DefinePropertyAttributes.h */,
+                               734B655423F4A33100A069D1 /* DeletePropertySlot.h */,
                                0FE0500F1AA9091100D33B33 /* DirectArguments.cpp */,
                                0FE050101AA9091100D33B33 /* DirectArguments.h */,
                                0FE0500D1AA9091100D33B33 /* DirectArgumentsOffset.cpp */,
                                FE5068651AE246390009DAB7 /* DeferredSourceDump.h in Headers */,
                                473DA4A4764C45FE871B0485 /* DefinePropertyAttributes.h in Headers */,
                                0FBB73BB1DEF8645002C009E /* DeleteAllCodeEffort.h in Headers */,
+                               734B655523F5C10400A069D1 /* DeletePropertySlot.h in Headers */,
                                0F96303C1D4192CD005609D9 /* DestructionMode.h in Headers */,
                                A77A423E17A0BBFD00A8DB81 /* DFGAbstractHeap.h in Headers */,
                                A704D90317A0BAA8006BA554 /* DFGAbstractInterpreter.h in Headers */,
                0867D690FE84028FC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        attributes = {
-                               BuildIndependentTargetsInParallel = YES;
                                DefaultBuildSystemTypeForWorkspace = Original;
                                LastSwiftUpdateCheck = 0700;
                                LastUpgradeCheck = 1000;
index def6752..7cab9c1 100644 (file)
@@ -73,6 +73,8 @@ std::unique_ptr<AccessCase> AccessCase::create(VM& vm, JSCell* owner, AccessType
     switch (type) {
     case InHit:
     case InMiss:
+    case DeleteNonConfigurable:
+    case DeleteMiss:
         break;
     case ArrayLength:
     case StringLength:
@@ -106,7 +108,7 @@ std::unique_ptr<AccessCase> AccessCase::create(VM& vm, JSCell* owner, AccessType
     return std::unique_ptr<AccessCase>(new AccessCase(vm, owner, type, identifier, offset, structure, conditionSet, WTFMove(prototypeAccessChain)));
 }
 
-std::unique_ptr<AccessCase> AccessCase::create(
+std::unique_ptr<AccessCase> AccessCase::createTransition(
     VM& vm, JSCell* owner, CacheableIdentifier identifier, PropertyOffset offset, Structure* oldStructure, Structure* newStructure,
     const ObjectPropertyConditionSet& conditionSet, std::unique_ptr<PolyProtoAccessChain> prototypeAccessChain)
 {
@@ -123,6 +125,22 @@ std::unique_ptr<AccessCase> AccessCase::create(
     return std::unique_ptr<AccessCase>(new AccessCase(vm, owner, Transition, identifier, offset, newStructure, conditionSet, WTFMove(prototypeAccessChain)));
 }
 
+std::unique_ptr<AccessCase> AccessCase::createDelete(
+    VM& vm, JSCell* owner, CacheableIdentifier identifier, PropertyOffset offset, Structure* oldStructure, Structure* newStructure)
+{
+    RELEASE_ASSERT(oldStructure == newStructure->previousID(vm));
+    if (!newStructure->outOfLineCapacity() && oldStructure->outOfLineCapacity()) {
+        // We do not cache this case so that we do not need to check the jscell.
+        // See the Delete code below.
+        bool mayNeedToCheckCell;
+        newStructure->mayHaveIndexingHeader(mayNeedToCheckCell);
+
+        if (mayNeedToCheckCell)
+            return nullptr;
+    }
+    return std::unique_ptr<AccessCase>(new AccessCase(vm, owner, Delete, identifier, offset, newStructure, { }, { }));
+}
+
 AccessCase::~AccessCase()
 {
 }
@@ -262,6 +280,9 @@ bool AccessCase::requiresIdentifierNameMatch() const
     case Load:
     // We don't currently have a by_val for these puts, but we do care about the identifier.
     case Transition:
+    case Delete:
+    case DeleteNonConfigurable:
+    case DeleteMiss:
     case Replace: 
     case Miss:
     case GetGetter:
@@ -309,6 +330,9 @@ bool AccessCase::requiresInt32PropertyCheck() const
     switch (m_type) {
     case Load:
     case Transition:
+    case Delete:
+    case DeleteNonConfigurable:
+    case DeleteMiss:
     case Replace: 
     case Miss:
     case GetGetter:
@@ -356,6 +380,9 @@ bool AccessCase::needsScratchFPR() const
     switch (m_type) {
     case Load:
     case Transition:
+    case Delete:
+    case DeleteNonConfigurable:
+    case DeleteMiss:
     case Replace: 
     case Miss:
     case GetGetter:
@@ -447,6 +474,9 @@ void AccessCase::forEachDependentCell(VM& vm, const Functor& functor) const
     case CustomAccessorSetter:
     case Load:
     case Transition:
+    case Delete:
+    case DeleteNonConfigurable:
+    case DeleteMiss:
     case Replace:
     case Miss:
     case GetGetter:
@@ -492,6 +522,9 @@ bool AccessCase::doesCalls(VM& vm, Vector<JSCell*>* cellsToMarkIfDoesCalls) cons
     case CustomAccessorSetter:
         doesCalls = true;
         break;
+    case Delete:
+    case DeleteNonConfigurable:
+    case DeleteMiss:
     case Load:
     case Replace:
     case Miss:
@@ -614,6 +647,9 @@ bool AccessCase::canReplace(const AccessCase& other) const
 
     case Load:
     case Transition:
+    case Delete:
+    case DeleteNonConfigurable:
+    case DeleteMiss:
     case Replace:
     case Miss:
     case GetGetter:
@@ -663,7 +699,7 @@ void AccessCase::dump(PrintStream& out) const
         out.print(comma, "prototype access chain = ");
         m_polyProtoAccessChain->dump(structure(), out);
     } else {
-        if (m_type == Transition)
+        if (m_type == Transition || m_type == Delete)
             out.print(comma, "structure = ", pointerDump(structure()), " -> ", pointerDump(newStructure()));
         else if (m_structure)
             out.print(comma, "structure = ", pointerDump(m_structure.get()));
@@ -705,6 +741,7 @@ bool AccessCase::propagateTransitions(SlotVisitor& visitor) const
 
     switch (m_type) {
     case Transition:
+    case Delete:
         if (visitor.vm().heap.isMarked(m_structure->previousID(visitor.vm())))
             visitor.appendUnbarriered(m_structure.get());
         else
@@ -1851,7 +1888,7 @@ void AccessCase::generateImpl(AccessGenerationState& state)
                 state.restoreLiveRegistersFromStackForCall(spillState, resultRegisterToExclude);
             }
         }
-        
+
         if (isInlineOffset(m_offset)) {
             jit.storeValue(
                 valueRegs,
@@ -1896,6 +1933,71 @@ void AccessCase::generateImpl(AccessGenerationState& state)
             RELEASE_ASSERT(slowPath.empty());
         return;
     }
+
+    case Delete: {
+        ScratchRegisterAllocator allocator(stubInfo.usedRegisters);
+        allocator.lock(stubInfo.baseRegs());
+        allocator.lock(valueRegs);
+        allocator.lock(baseGPR);
+        allocator.lock(scratchGPR);
+        ASSERT(structure()->transitionWatchpointSetHasBeenInvalidated());
+        ASSERT(newStructure()->isPropertyDeletionTransition());
+        ASSERT(baseGPR != valueRegs.gpr());
+        ASSERT(baseGPR != scratchGPR);
+        ASSERT(valueRegs.gpr() != scratchGPR);
+
+        ScratchRegisterAllocator::PreservedState preservedState =
+            allocator.preserveReusedRegistersByPushing(jit, ScratchRegisterAllocator::ExtraStackSpace::NoExtraSpace);
+
+        bool mayNeedToCheckCell;
+        bool hasIndexingHeader = newStructure()->mayHaveIndexingHeader(mayNeedToCheckCell);
+        // We do not cache this case yet so that we do not need to check the jscell.
+        // See Structure::hasIndexingHeader and JSObject::deleteProperty.
+        ASSERT(!mayNeedToCheckCell);
+        // Clear the butterfly if we have no properties, since our put code expects this.
+        bool shouldNukeStructureAndClearButterfly = !newStructure()->outOfLineCapacity() && structure()->outOfLineCapacity() && !hasIndexingHeader;
+
+        jit.moveValue(JSValue(), valueRegs);
+
+        if (shouldNukeStructureAndClearButterfly) {
+            jit.nukeStructureAndStoreButterfly(vm, valueRegs.payloadGPR(), baseGPR);
+        } else if (isInlineOffset(m_offset)) {
+            jit.storeValue(
+                valueRegs,
+                CCallHelpers::Address(
+                    baseGPR,
+                    JSObject::offsetOfInlineStorage() +
+                    offsetInInlineStorage(m_offset) * sizeof(JSValue)));
+        } else {
+            jit.loadPtr(CCallHelpers::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR);
+            jit.storeValue(
+                valueRegs,
+                CCallHelpers::Address(scratchGPR, offsetInButterfly(m_offset) * sizeof(JSValue)));
+        }
+
+        uint32_t structureBits = bitwise_cast<uint32_t>(newStructure()->id());
+        jit.store32(
+            CCallHelpers::TrustedImm32(structureBits),
+            CCallHelpers::Address(baseGPR, JSCell::structureIDOffset()));
+
+        jit.move(MacroAssembler::TrustedImm32(true), valueRegs.payloadGPR());
+
+        allocator.restoreReusedRegistersByPopping(jit, preservedState);
+        state.succeed();
+        return;
+    }
+
+    case DeleteNonConfigurable: {
+        jit.move(MacroAssembler::TrustedImm32(false), valueRegs.payloadGPR());
+        state.succeed();
+        return;
+    }
+
+    case DeleteMiss: {
+        jit.move(MacroAssembler::TrustedImm32(true), valueRegs.payloadGPR());
+        state.succeed();
+        return;
+    }
         
     case ArrayLength: {
         jit.loadPtr(CCallHelpers::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR);
index a767767..a3479d1 100644 (file)
@@ -85,6 +85,9 @@ public:
     enum AccessType : uint8_t {
         Load,
         Transition,
+        Delete,
+        DeleteNonConfigurable,
+        DeleteMiss,
         Replace,
         Miss,
         GetGetter,
@@ -145,9 +148,11 @@ public:
     static std::unique_ptr<AccessCase> create(VM&, JSCell* owner, AccessType, CacheableIdentifier, PropertyOffset = invalidOffset,
         Structure* = nullptr, const ObjectPropertyConditionSet& = ObjectPropertyConditionSet(), std::unique_ptr<PolyProtoAccessChain> = nullptr);
 
-    // This create method should be used for transitions.
-    static std::unique_ptr<AccessCase> create(VM&, JSCell* owner, CacheableIdentifier, PropertyOffset, Structure* oldStructure,
+    static std::unique_ptr<AccessCase> createTransition(VM&, JSCell* owner, CacheableIdentifier, PropertyOffset, Structure* oldStructure,
         Structure* newStructure, const ObjectPropertyConditionSet&, std::unique_ptr<PolyProtoAccessChain>);
+
+    static std::unique_ptr<AccessCase> createDelete(VM&, JSCell* owner, CacheableIdentifier, PropertyOffset, Structure* oldStructure,
+        Structure* newStructure);
     
     static std::unique_ptr<AccessCase> fromStructureStubInfo(VM&, JSCell* owner, CacheableIdentifier, StructureStubInfo&);
 
@@ -157,7 +162,7 @@ public:
 
     Structure* structure() const
     {
-        if (m_type == Transition)
+        if (m_type == Transition || m_type == Delete)
             return m_structure->previousID(m_structure->vm());
         return m_structure.get();
     }
@@ -165,7 +170,7 @@ public:
 
     Structure* newStructure() const
     {
-        ASSERT(m_type == Transition);
+        ASSERT(m_type == Transition || m_type == Delete);
         return m_structure.get();
     }
 
index 132409c..b166c30 100644 (file)
@@ -795,6 +795,15 @@ void printInternal(PrintStream& out, AccessCase::AccessType type)
     case AccessCase::Transition:
         out.print("Transition");
         return;
+    case AccessCase::Delete:
+        out.print("Delete");
+        return;
+    case AccessCase::DeleteNonConfigurable:
+        out.print("DeleteNonConfigurable");
+        return;
+    case AccessCase::DeleteMiss:
+        out.print("DeleteMiss");
+        return;
     case AccessCase::Replace:
         out.print("Replace");
         return;
index 6178737..96a1bae 100644 (file)
@@ -276,6 +276,12 @@ void StructureStubInfo::reset(CodeBlock* codeBlock)
     case AccessType::InstanceOf:
         resetInstanceOf(*this);
         break;
+    case AccessType::DeleteByID:
+        resetDelBy(codeBlock, *this, DelByKind::Normal);
+        break;
+    case AccessType::DeleteByVal:
+        resetDelBy(codeBlock, *this, DelByKind::NormalByVal);
+        break;
     }
     
     deref();
index ddce85e..b575bdd 100644 (file)
@@ -55,7 +55,9 @@ enum class AccessType : int8_t {
     GetByVal,
     Put,
     In,
-    InstanceOf
+    InstanceOf,
+    DeleteByID,
+    DeleteByVal
 };
 
 enum class CacheType : int8_t {
index 26e2829..48b5b86 100644 (file)
@@ -129,14 +129,14 @@ bool DebuggerScope::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName
     return thisObject->methodTable(globalObject->vm())->put(thisObject, globalObject, propertyName, value, slot);
 }
 
-bool DebuggerScope::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool DebuggerScope::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     DebuggerScope* scope = jsCast<DebuggerScope*>(cell);
     ASSERT(scope->isValid());
     if (!scope->isValid())
         return false;
     JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
-    return thisObject->methodTable(globalObject->vm())->deleteProperty(thisObject, globalObject, propertyName);
+    return thisObject->methodTable(globalObject->vm())->deleteProperty(thisObject, globalObject, propertyName, slot);
 }
 
 void DebuggerScope::getOwnPropertyNames(JSObject* object, JSGlobalObject* globalObject, PropertyNameArray& propertyNames, EnumerationMode mode)
index ff4ce1b..4327c1f 100644 (file)
@@ -51,7 +51,7 @@ public:
     static String toStringName(const JSObject*, JSGlobalObject*);
     static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     static void getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
 
index 7ffa38e..e97de10 100644 (file)
@@ -1618,6 +1618,22 @@ private:
             break;
         }
 
+        case DeleteByVal: {
+#if USE(JSVALUE64)
+            if (node->child2()->shouldSpeculateCell())
+                fixEdge<CellUse>(node->child2());
+#endif
+            FALLTHROUGH;
+        }
+
+        case DeleteById: {
+#if USE(JSVALUE64)
+            if (node->child1()->shouldSpeculateCell())
+                fixEdge<CellUse>(node->child1());
+#endif
+            break;
+        }
+
         case GetById:
         case GetByIdFlush: {
             // FIXME: This should be done in the ByteCodeParser based on reading the
@@ -2518,8 +2534,6 @@ private:
         case NewAsyncGenerator:
         case NewArrayIterator:
         case NewRegexp:
-        case DeleteById:
-        case DeleteByVal:
         case IsTypedArrayView:
         case IsEmpty:
         case IsUndefined:
index e3e208d..3871591 100644 (file)
@@ -246,6 +246,8 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
     finalizeInlineCaches(m_getByIdsWithThis, linkBuffer);
     finalizeInlineCaches(m_getByVals, linkBuffer);
     finalizeInlineCaches(m_putByIds, linkBuffer);
+    finalizeInlineCaches(m_delByIds, linkBuffer);
+    finalizeInlineCaches(m_delByVals, linkBuffer);
     finalizeInlineCaches(m_inByIds, linkBuffer);
     finalizeInlineCaches(m_instanceOfs, linkBuffer);
 
index 4880874..2fb6ad8 100644 (file)
@@ -191,7 +191,17 @@ public:
     {
         m_putByIds.append(InlineCacheWrapper<JITPutByIdGenerator>(gen, slowPath));
     }
-    
+
+    void addDelById(const JITDelByIdGenerator& gen, SlowPathGenerator* slowPath)
+    {
+        m_delByIds.append(InlineCacheWrapper<JITDelByIdGenerator>(gen, slowPath));
+    }
+
+    void addDelByVal(const JITDelByValGenerator& gen, SlowPathGenerator* slowPath)
+    {
+        m_delByVals.append(InlineCacheWrapper<JITDelByValGenerator>(gen, slowPath));
+    }
+
     void addInstanceOf(const JITInstanceOfGenerator& gen, SlowPathGenerator* slowPath)
     {
         m_instanceOfs.append(InlineCacheWrapper<JITInstanceOfGenerator>(gen, slowPath));
@@ -348,6 +358,8 @@ private:
     Vector<InlineCacheWrapper<JITGetByIdWithThisGenerator>, 4> m_getByIdsWithThis;
     Vector<InlineCacheWrapper<JITGetByValGenerator>, 4> m_getByVals;
     Vector<InlineCacheWrapper<JITPutByIdGenerator>, 4> m_putByIds;
+    Vector<InlineCacheWrapper<JITDelByIdGenerator>, 4> m_delByIds;
+    Vector<InlineCacheWrapper<JITDelByValGenerator>, 4> m_delByVals;
     Vector<InlineCacheWrapper<JITInByIdGenerator>, 4> m_inByIds;
     Vector<InlineCacheWrapper<JITInstanceOfGenerator>, 4> m_instanceOfs;
     Vector<JSCallRecord, 4> m_jsCalls;
index 17ba2b2..02e8d06 100644 (file)
@@ -1145,43 +1145,6 @@ void SpeculativeJIT::compileInByVal(Node* node)
     blessedBooleanResult(resultRegs.payloadGPR(), node, UseChildrenCalledExplicitly);
 }
 
-void SpeculativeJIT::compileDeleteById(Node* node)
-{
-    JSValueOperand value(this, node->child1());
-    GPRFlushedCallResult result(this);
-
-    JSValueRegs valueRegs = value.jsValueRegs();
-    GPRReg resultGPR = result.gpr();
-
-    value.use();
-
-    flushRegisters();
-    callOperation(operationDeleteById, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueRegs, identifierUID(node->identifierNumber()));
-    m_jit.exceptionCheck();
-
-    unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
-}
-
-void SpeculativeJIT::compileDeleteByVal(Node* node)
-{
-    JSValueOperand base(this, node->child1());
-    JSValueOperand key(this, node->child2());
-    GPRFlushedCallResult result(this);
-
-    JSValueRegs baseRegs = base.jsValueRegs();
-    JSValueRegs keyRegs = key.jsValueRegs();
-    GPRReg resultGPR = result.gpr();
-
-    base.use();
-    key.use();
-
-    flushRegisters();
-    callOperation(operationDeleteByVal, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs, keyRegs);
-    m_jit.exceptionCheck();
-
-    unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
-}
-
 void SpeculativeJIT::compilePushWithScope(Node* node)
 {
     SpeculateCellOperand currentScope(this, node->child1());
index ecfc903..b019d85 100644 (file)
@@ -4278,6 +4278,45 @@ void SpeculativeJIT::blessBoolean(GPRReg)
 {
 }
 
+void SpeculativeJIT::compileDeleteById(Node* node)
+{
+    // FIXME: We should support inline caching on 32 bits.
+    // See <https://bugs.webkit.org/show_bug.cgi?id=208207>.
+    JSValueOperand value(this, node->child1());
+    GPRFlushedCallResult result(this);
+
+    JSValueRegs valueRegs = value.jsValueRegs();
+    GPRReg resultGPR = result.gpr();
+
+    value.use();
+
+    flushRegisters();
+    callOperation(operationDeleteByIdGeneric, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), nullptr, valueRegs, identifierUID(node->identifierNumber()));
+    m_jit.exceptionCheck();
+
+    unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
+}
+
+void SpeculativeJIT::compileDeleteByVal(Node* node)
+{
+    JSValueOperand base(this, node->child1());
+    JSValueOperand key(this, node->child2());
+    GPRFlushedCallResult result(this);
+
+    JSValueRegs baseRegs = base.jsValueRegs();
+    JSValueRegs keyRegs = key.jsValueRegs();
+    GPRReg resultGPR = result.gpr();
+
+    base.use();
+    key.use();
+
+    flushRegisters();
+    callOperation(operationDeleteByValGeneric, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), nullptr, baseRegs, keyRegs);
+    m_jit.exceptionCheck();
+
+    unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
+}
+
 void SpeculativeJIT::compileArithRandom(Node* node)
 {
     JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
index 3728b85..b07cb25 100644 (file)
@@ -5439,6 +5439,88 @@ void SpeculativeJIT::compileStringCodePointAt(Node* node)
     int32Result(scratch1GPR, m_currentNode);
 }
 
+void SpeculativeJIT::compileDeleteById(Node* node)
+{
+    speculate(node, node->child1());
+
+    GPRTemporary result(this);
+    GPRTemporary scratch(this);
+    JSValueOperand base(this, node->child1(), ManualOperandSpeculation);
+
+    auto* property = identifierUID(node->identifierNumber());
+    JITCompiler::JumpList slowCases;
+
+    JSValueRegs baseRegs = base.jsValueRegs();
+    GPRReg scratchGPR = scratch.gpr();
+    GPRReg resultGPR = result.gpr();
+
+    if (needsTypeCheck(node->child1(), SpecCell))
+        slowCases.append(m_jit.branchIfNotCell(baseRegs));
+
+    CodeOrigin codeOrigin = node->origin.semantic;
+    CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
+    RegisterSet usedRegisters = this->usedRegisters();
+
+    JITDelByIdGenerator gen(
+        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
+        baseRegs, resultGPR, scratchGPR);
+
+    gen.generateFastPath(m_jit);
+    slowCases.append(gen.slowPathJump());
+
+    std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
+        slowCases, this, operationDeleteByIdOptimize,
+        resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), gen.stubInfo(), baseRegs, property);
+
+    m_jit.addDelById(gen, slowPath.get());
+    addSlowPathGenerator(WTFMove(slowPath));
+
+    unblessedBooleanResult(resultGPR, node);
+}
+
+void SpeculativeJIT::compileDeleteByVal(Node* node)
+{
+    speculate(node, node->child1());
+    speculate(node, node->child2());
+
+    GPRTemporary result(this);
+    GPRTemporary scratch(this);
+    JSValueOperand base(this, node->child1(), ManualOperandSpeculation);
+    JSValueOperand key(this, node->child2(), ManualOperandSpeculation);
+
+    JITCompiler::JumpList slowCases;
+
+    JSValueRegs baseRegs = base.jsValueRegs();
+    JSValueRegs keyRegs = key.jsValueRegs();
+    GPRReg scratchGPR = scratch.gpr();
+    GPRReg resultGPR = result.gpr();
+
+    if (needsTypeCheck(node->child1(), SpecCell))
+        slowCases.append(m_jit.branchIfNotCell(baseRegs));
+    if (needsTypeCheck(node->child2(), SpecCell))
+        slowCases.append(m_jit.branchIfNotCell(keyRegs));
+
+    CodeOrigin codeOrigin = node->origin.semantic;
+    CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
+    RegisterSet usedRegisters = this->usedRegisters();
+
+    JITDelByValGenerator gen(
+        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
+        baseRegs, keyRegs, resultGPR, scratchGPR);
+
+    gen.generateFastPath(m_jit);
+    slowCases.append(gen.slowPathJump());
+
+    std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
+        slowCases, this, operationDeleteByValOptimize,
+        resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), gen.stubInfo(), baseRegs, keyRegs);
+
+    m_jit.addDelByVal(gen, slowPath.get());
+    addSlowPathGenerator(WTFMove(slowPath));
+
+    unblessedBooleanResult(resultGPR, node);
+}
+
 void SpeculativeJIT::compileDateGet(Node* node)
 {
     SpeculateCellOperand base(this, node->child1());
index 4bebef2..8036390 100644 (file)
@@ -5144,20 +5144,168 @@ private:
             weakPointer(globalObject), base, subscript, m_out.constInt32(m_node->accessorAttributes()), accessor);
     }
 
+    template<DelByKind kind, typename SubscriptKind>
+    void compileDelBy(LValue base, SubscriptKind subscriptValue)
+    {
+        PatchpointValue* patchpoint;
+        if constexpr (kind == DelByKind::Normal) {
+            patchpoint = m_out.patchpoint(Int64);
+            patchpoint->append(ConstrainedValue(base, ValueRep::SomeLateRegister));
+        } else {
+            patchpoint = m_out.patchpoint(Int64);
+            patchpoint->append(ConstrainedValue(base, ValueRep::SomeLateRegister));
+            patchpoint->append(ConstrainedValue(subscriptValue, ValueRep::SomeLateRegister));
+        }
+        patchpoint->clobber(RegisterSet::macroScratchRegisters());
+        patchpoint->numGPScratchRegisters = 1;
+
+        RefPtr<PatchpointExceptionHandle> exceptionHandle =
+            preparePatchpointForExceptions(patchpoint);
+
+        State* state = &m_ftlState;
+        Node* node = m_node;
+        patchpoint->setGenerator(
+            [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+                AllowMacroScratchRegisterUsage allowScratch(jit);
+
+                CallSiteIndex callSiteIndex =
+                    state->jitCode->common.addUniqueCallSiteIndex(node->origin.semantic);
+
+                Box<CCallHelpers::JumpList> exceptions =
+                    exceptionHandle->scheduleExitCreation(params)->jumps(jit);
+                CCallHelpers::JumpList slowCases;
+
+                auto base = JSValueRegs(params[1].gpr());
+                auto returnGPR = params[0].gpr();
+                ASSERT(base.gpr() != returnGPR);
+                ASSERT(base.gpr() != params.gpScratch(0));
+                ASSERT(returnGPR != params.gpScratch(0));
+
+                if (node->child1().useKind() == UntypedUse)
+                    slowCases.append(jit.branchIfNotCell(base));
+
+                constexpr auto optimizationFunction = [&] () {
+                    if constexpr (kind == DelByKind::Normal)
+                        return operationDeleteByIdOptimize;
+                    else
+                        return operationDeleteByValOptimize;
+                }();
+
+                const auto subscript = [&] {
+                    if constexpr (kind == DelByKind::Normal)
+                        return CCallHelpers::TrustedImmPtr(subscriptValue);
+                    else {
+                        ASSERT(base.gpr() != params[2].gpr());
+                        ASSERT(params.gpScratch(0) != params[2].gpr());
+                        if (node->child2().useKind() == UntypedUse)
+                            slowCases.append(jit.branchIfNotCell(JSValueRegs(params[2].gpr())));
+                        return JSValueRegs(params[2].gpr());
+                    }
+                }();
+
+                const auto generator = [&] {
+                    if constexpr (kind == DelByKind::Normal) {
+                        return Box<JITDelByIdGenerator>::create(
+                            jit.codeBlock(), node->origin.semantic, callSiteIndex,
+                            params.unavailableRegisters(), base,
+                            returnGPR, params.gpScratch(0));
+                    } else {
+                        return Box<JITDelByValGenerator>::create(
+                            jit.codeBlock(), node->origin.semantic, callSiteIndex,
+                            params.unavailableRegisters(), base,
+                            subscript, returnGPR, params.gpScratch(0));
+                    }
+                }();
+
+                generator->generateFastPath(jit);
+                slowCases.append(generator->slowPathJump());
+                CCallHelpers::Label done = jit.label();
+
+                params.addLatePath(
+                    [=] (CCallHelpers& jit) {
+                        AllowMacroScratchRegisterUsage allowScratch(jit);
+
+                        slowCases.link(&jit);
+                        CCallHelpers::Label slowPathBegin = jit.label();
+                        CCallHelpers::Call slowPathCall = callOperation(
+                            *state, params.unavailableRegisters(), jit, node->origin.semantic,
+                            exceptions.get(), optimizationFunction, returnGPR,
+                            jit.codeBlock()->globalObjectFor(node->origin.semantic),
+                            CCallHelpers::TrustedImmPtr(generator->stubInfo()), base,
+                            subscript).call();
+                        jit.jump().linkTo(done, &jit);
+
+                        generator->reportSlowPathCall(slowPathBegin, slowPathCall);
+
+                        jit.addLinkTask(
+                            [=] (LinkBuffer& linkBuffer) {
+                                generator->finalize(linkBuffer, linkBuffer);
+                            });
+                    });
+            });
+
+        setBoolean(m_out.notZero64(patchpoint));
+    }
+
     void compileDeleteById()
     {
-        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
-        LValue base = lowJSValue(m_node->child1());
-        auto uid = m_graph.identifiers()[m_node->identifierNumber()];
-        setBoolean(m_out.notZero64(vmCall(Int64, operationDeleteById, weakPointer(globalObject), base, m_out.constIntPtr(uid))));
+        LValue base;
+
+        switch (m_node->child1().useKind()) {
+        case CellUse: {
+            base = lowCell(m_node->child1());
+            break;
+        }
+
+        case UntypedUse: {
+            base = lowJSValue(m_node->child1());
+            break;
+        }
+
+        default:
+            DFG_CRASH(m_graph, m_node, "Bad use kind");
+            return;
+        }
+        compileDelBy<DelByKind::Normal>(base, m_graph.identifiers()[m_node->identifierNumber()]);
     }
 
     void compileDeleteByVal()
     {
-        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
-        LValue base = lowJSValue(m_node->child1());
-        LValue subscript = lowJSValue(m_node->child2());
-        setBoolean(m_out.notZero64(vmCall(Int64, operationDeleteByVal, weakPointer(globalObject), base, subscript)));
+        LValue base;
+        LValue subscript;
+
+        switch (m_node->child1().useKind()) {
+        case CellUse: {
+            base = lowCell(m_node->child1());
+            break;
+        }
+
+        case UntypedUse: {
+            base = lowJSValue(m_node->child1());
+            break;
+        }
+
+        default:
+            DFG_CRASH(m_graph, m_node, "Bad use kind");
+            return;
+        }
+
+        switch (m_node->child2().useKind()) {
+        case CellUse: {
+            subscript = lowCell(m_node->child2());
+            break;
+        }
+
+        case UntypedUse: {
+            subscript = lowJSValue(m_node->child2());
+            break;
+        }
+
+        default:
+            DFG_CRASH(m_graph, m_node, "Bad use kind");
+            return;
+        }
+        compileDelBy<DelByKind::NormalByVal>(base, subscript);
     }
     
     void compileArrayPush()
index 5d30928..9040df3 100644 (file)
@@ -70,7 +70,9 @@ namespace JSC {
     macro(PutByIdAddAccessCase) \
     macro(PutByIdReplaceWithJump) \
     macro(PutByIdSelfPatch) \
-    macro(InByIdSelfPatch)
+    macro(InByIdSelfPatch) \
+    macro(DelByReplaceWithJump) \
+    macro(DelByReplaceWithGeneric)
 
 class ICEvent {
 public:
index 091c4f7..c6e61b8 100644 (file)
@@ -500,6 +500,8 @@ void JIT::privateCompileSlowCases()
     m_getByIdWithThisIndex = 0;
     m_putByIdIndex = 0;
     m_inByIdIndex = 0;
+    m_delByValIndex = 0;
+    m_delByIdIndex = 0;
     m_instanceOfIndex = 0;
     m_byValInstructionIndex = 0;
     m_callLinkInfoIndex = 0;
@@ -580,6 +582,8 @@ void JIT::privateCompileSlowCases()
         DEFINE_SLOWCASE_OP(op_put_by_id)
         case op_put_by_val_direct:
         DEFINE_SLOWCASE_OP(op_put_by_val)
+        DEFINE_SLOWCASE_OP(op_del_by_val)
+        DEFINE_SLOWCASE_OP(op_del_by_id)
         DEFINE_SLOWCASE_OP(op_sub)
         DEFINE_SLOWCASE_OP(op_has_indexed_property)
         DEFINE_SLOWCASE_OP(op_get_from_scope)
@@ -875,6 +879,8 @@ CompilationResult JIT::link()
     finalizeInlineCaches(m_getByVals, patchBuffer);
     finalizeInlineCaches(m_getByIdsWithThis, patchBuffer);
     finalizeInlineCaches(m_putByIds, patchBuffer);
+    finalizeInlineCaches(m_delByIds, patchBuffer);
+    finalizeInlineCaches(m_delByVals, patchBuffer);
     finalizeInlineCaches(m_inByIds, patchBuffer);
     finalizeInlineCaches(m_instanceOfs, patchBuffer);
 
index 7b44074..6716661 100644 (file)
@@ -500,7 +500,9 @@ namespace JSC {
         void emit_op_identity_with_profile(const Instruction*);
         void emit_op_debug(const Instruction*);
         void emit_op_del_by_id(const Instruction*);
+        void emitSlow_op_del_by_id(const Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emit_op_del_by_val(const Instruction*);
+        void emitSlow_op_del_by_val(const Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emit_op_div(const Instruction*);
         void emit_op_end(const Instruction*);
         void emit_op_enter(const Instruction*);
@@ -913,6 +915,8 @@ namespace JSC {
         Vector<JITGetByIdWithThisGenerator> m_getByIdsWithThis;
         Vector<JITPutByIdGenerator> m_putByIds;
         Vector<JITInByIdGenerator> m_inByIds;
+        Vector<JITDelByIdGenerator> m_delByIds;
+        Vector<JITDelByValGenerator> m_delByVals;
         Vector<JITInstanceOfGenerator> m_instanceOfs;
         Vector<ByValCompilationInfo> m_byValCompilationInfo;
         Vector<CallCompilationInfo> m_callCompilationInfo;
@@ -934,6 +938,8 @@ namespace JSC {
         unsigned m_getByIdWithThisIndex { UINT_MAX };
         unsigned m_putByIdIndex { UINT_MAX };
         unsigned m_inByIdIndex { UINT_MAX };
+        unsigned m_delByValIndex { UINT_MAX };
+        unsigned m_delByIdIndex { UINT_MAX };
         unsigned m_instanceOfIndex { UINT_MAX };
         unsigned m_byValInstructionIndex { UINT_MAX };
         unsigned m_callLinkInfoIndex { UINT_MAX };
index 920b720..f411021 100644 (file)
@@ -162,6 +162,68 @@ V_JITOperation_GSsiJJI JITPutByIdGenerator::slowPathFunction()
     return operationPutByIdNonStrictOptimize;
 }
 
+JITDelByValGenerator::JITDelByValGenerator(CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSiteIndex, const RegisterSet& usedRegisters, JSValueRegs base, JSValueRegs property, GPRReg result, GPRReg scratch)
+    : Base(codeBlock, codeOrigin, callSiteIndex, AccessType::DeleteByVal, usedRegisters)
+{
+    m_stubInfo->hasConstantIdentifier = false;
+    ASSERT(base.payloadGPR() != result);
+    m_stubInfo->baseGPR = base.payloadGPR();
+    m_stubInfo->regs.propertyGPR = property.payloadGPR();
+    m_stubInfo->valueGPR = result;
+#if USE(JSVALUE32_64)
+    m_stubInfo->baseTagGPR = base.tagGPR();
+    m_stubInfo->valueTagGPR = InvalidGPRReg;
+    m_stubInfo->v.propertyTagGPR = property.tagGPR();
+#endif
+    m_stubInfo->usedRegisters.clear(scratch);
+}
+
+void JITDelByValGenerator::generateFastPath(MacroAssembler& jit)
+{
+    m_start = jit.label();
+    m_slowPathJump = jit.patchableJump();
+    m_done = jit.label();
+}
+
+void JITDelByValGenerator::finalize(
+    LinkBuffer& fastPath, LinkBuffer& slowPath)
+{
+    ASSERT(m_slowPathJump.m_jump.isSet());
+    Base::finalize(
+        fastPath, slowPath, fastPath.locationOf<JITStubRoutinePtrTag>(m_start));
+}
+
+JITDelByIdGenerator::JITDelByIdGenerator(CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSiteIndex, const RegisterSet& usedRegisters, JSValueRegs base, GPRReg result, GPRReg scratch)
+    : Base(codeBlock, codeOrigin, callSiteIndex, AccessType::DeleteByID, usedRegisters)
+{
+    m_stubInfo->hasConstantIdentifier = true;
+    ASSERT(base.payloadGPR() != result);
+    m_stubInfo->baseGPR = base.payloadGPR();
+    m_stubInfo->regs.propertyGPR = InvalidGPRReg;
+    m_stubInfo->valueGPR = result;
+#if USE(JSVALUE32_64)
+    m_stubInfo->baseTagGPR = base.tagGPR();
+    m_stubInfo->valueTagGPR = InvalidGPRReg;
+    m_stubInfo->v.propertyTagGPR = InvalidGPRReg;
+#endif
+    m_stubInfo->usedRegisters.clear(scratch);
+}
+
+void JITDelByIdGenerator::generateFastPath(MacroAssembler& jit)
+{
+    m_start = jit.label();
+    m_slowPathJump = jit.patchableJump();
+    m_done = jit.label();
+}
+
+void JITDelByIdGenerator::finalize(
+    LinkBuffer& fastPath, LinkBuffer& slowPath)
+{
+    ASSERT(m_slowPathJump.m_jump.isSet());
+    Base::finalize(
+        fastPath, slowPath, fastPath.locationOf<JITStubRoutinePtrTag>(m_start));
+}
+
 JITInByIdGenerator::JITInByIdGenerator(
     CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, const RegisterSet& usedRegisters,
     UniquedStringImpl* propertyName, JSValueRegs base, JSValueRegs value)
index bfb9021..26e700f 100644 (file)
@@ -142,6 +142,56 @@ private:
     PutKind m_putKind;
 };
 
+class JITDelByValGenerator : public JITInlineCacheGenerator {
+    using Base = JITInlineCacheGenerator;
+public:
+    JITDelByValGenerator() { }
+
+    JITDelByValGenerator(
+        CodeBlock*, CodeOrigin, CallSiteIndex, const RegisterSet& usedRegisters,
+        JSValueRegs base, JSValueRegs property, GPRReg result, GPRReg scratch);
+
+    MacroAssembler::Jump slowPathJump() const
+    {
+        ASSERT(m_slowPathJump.m_jump.isSet());
+        return m_slowPathJump.m_jump;
+    }
+
+    void finalize(
+        LinkBuffer& fastPathLinkBuffer, LinkBuffer& slowPathLinkBuffer);
+
+    void generateFastPath(MacroAssembler&);
+
+private:
+    MacroAssembler::Label m_start;
+    MacroAssembler::PatchableJump m_slowPathJump;
+};
+
+class JITDelByIdGenerator : public JITInlineCacheGenerator {
+    using Base = JITInlineCacheGenerator;
+public:
+    JITDelByIdGenerator() { }
+
+    JITDelByIdGenerator(
+        CodeBlock*, CodeOrigin, CallSiteIndex, const RegisterSet& usedRegisters,
+        JSValueRegs base, GPRReg result, GPRReg scratch);
+
+    MacroAssembler::Jump slowPathJump() const
+    {
+        ASSERT(m_slowPathJump.m_jump.isSet());
+        return m_slowPathJump.m_jump;
+    }
+
+    void finalize(
+        LinkBuffer& fastPathLinkBuffer, LinkBuffer& slowPathLinkBuffer);
+
+    void generateFastPath(MacroAssembler&);
+
+private:
+    MacroAssembler::Label m_start;
+    MacroAssembler::PatchableJump m_slowPathJump;
+};
+
 class JITInByIdGenerator : public JITByIdGenerator {
 public:
     JITInByIdGenerator() { }
index e362673..7bdf1f7 100644 (file)
@@ -2142,7 +2142,7 @@ EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(JSGlobalObject*
     return JSValue::encode(jsBoolean(object->hasPropertyGeneric(globalObject, index, PropertySlot::InternalMethodType::GetOwnProperty)));
 }
     
-static bool deleteById(JSGlobalObject* globalObject, CallFrame* callFrame, VM& vm, JSValue base, UniquedStringImpl* uid)
+static bool deleteById(JSGlobalObject* globalObject, CallFrame* callFrame, VM& vm, DeletePropertySlot& slot, JSValue base, UniquedStringImpl* uid)
 {
     auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -2150,31 +2150,51 @@ static bool deleteById(JSGlobalObject* globalObject, CallFrame* callFrame, VM& v
     RETURN_IF_EXCEPTION(scope, false);
     if (!baseObj)
         return false;
-    bool couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, globalObject, Identifier::fromUid(vm, uid));
+    bool couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, globalObject, Identifier::fromUid(vm, uid), slot);
     RETURN_IF_EXCEPTION(scope, false);
     if (!couldDelete && callFrame->codeBlock()->isStrictMode())
         throwTypeError(globalObject, scope, UnableToDeletePropertyError);
     return couldDelete;
 }
 
-
-EncodedJSValue JIT_OPERATION operationDeleteByIdJSResult(JSGlobalObject* globalObject, EncodedJSValue encodedBase, UniquedStringImpl* uid)
+size_t JIT_OPERATION operationDeleteByIdOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedBase, UniquedStringImpl* uid)
 {
     VM& vm = globalObject->vm();
     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
-    return JSValue::encode(jsBoolean(deleteById(globalObject, callFrame, vm, JSValue::decode(encodedBase), uid)));
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue baseValue = JSValue::decode(encodedBase);
+
+    DeletePropertySlot slot;
+    Structure* oldStructure = baseValue.structureOrNull();
+
+    bool result = deleteById(globalObject, callFrame, vm, slot, baseValue, uid);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+    if (baseValue.isObject()) {
+        const Identifier propertyName = Identifier::fromUid(vm, uid);
+        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+        if (!parseIndex(propertyName)) {
+            CodeBlock* codeBlock = callFrame->codeBlock();
+            if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull()))
+                repatchDelBy(globalObject, codeBlock, slot, baseValue, oldStructure, propertyName, *stubInfo, DelByKind::Normal);
+        }
+    }
+
+    return result;
 }
 
-size_t JIT_OPERATION operationDeleteById(JSGlobalObject* globalObject, EncodedJSValue encodedBase, UniquedStringImpl* uid)
+size_t JIT_OPERATION operationDeleteByIdGeneric(JSGlobalObject* globalObject, StructureStubInfo*, EncodedJSValue encodedBase, UniquedStringImpl* uid)
 {
     VM& vm = globalObject->vm();
     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
-    return deleteById(globalObject, callFrame, vm, JSValue::decode(encodedBase), uid);
+    DeletePropertySlot slot;
+    return deleteById(globalObject, callFrame, vm, slot, JSValue::decode(encodedBase), uid);
 }
 
-static bool deleteByVal(JSGlobalObject* globalObject, CallFrame* callFrame, VM& vm, JSValue base, JSValue key)
+static bool deleteByVal(JSGlobalObject* globalObject, CallFrame* callFrame, VM& vm, DeletePropertySlot& slot, JSValue base, JSValue key)
 {
     auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -2190,7 +2210,7 @@ static bool deleteByVal(JSGlobalObject* globalObject, CallFrame* callFrame, VM&
     else {
         Identifier property = key.toPropertyKey(globalObject);
         RETURN_IF_EXCEPTION(scope, false);
-        couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, globalObject, property);
+        couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, globalObject, property, slot);
     }
     RETURN_IF_EXCEPTION(scope, false);
     if (!couldDelete && callFrame->codeBlock()->isStrictMode())
@@ -2198,20 +2218,42 @@ static bool deleteByVal(JSGlobalObject* globalObject, CallFrame* callFrame, VM&
     return couldDelete;
 }
 
-EncodedJSValue JIT_OPERATION operationDeleteByValJSResult(JSGlobalObject* globalObject, EncodedJSValue encodedBase,  EncodedJSValue encodedKey)
+size_t JIT_OPERATION operationDeleteByValOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
 {
     VM& vm = globalObject->vm();
     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
-    return JSValue::encode(jsBoolean(deleteByVal(globalObject, callFrame, vm, JSValue::decode(encodedBase), JSValue::decode(encodedKey))));
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue baseValue = JSValue::decode(encodedBase);
+    JSValue subscript = JSValue::decode(encodedSubscript);
+
+    DeletePropertySlot slot;
+    Structure* oldStructure = baseValue.structureOrNull();
+
+    bool result = deleteByVal(globalObject, callFrame, vm, slot, baseValue, subscript);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+    if (baseValue.isObject() && CacheableIdentifier::isCacheableIdentifierCell(subscript)) {
+        const Identifier propertyName = subscript.toPropertyKey(globalObject);
+        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+        if (subscript.isSymbol() || !parseIndex(propertyName)) {
+            CodeBlock* codeBlock = callFrame->codeBlock();
+            if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull()))
+                repatchDelBy(globalObject, codeBlock, slot, baseValue, oldStructure, propertyName, *stubInfo, DelByKind::NormalByVal);
+        }
+    }
+
+    return result;
 }
 
-size_t JIT_OPERATION operationDeleteByVal(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedKey)
+size_t JIT_OPERATION operationDeleteByValGeneric(JSGlobalObject* globalObject, StructureStubInfo*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
 {
     VM& vm = globalObject->vm();
     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
-    return deleteByVal(globalObject, callFrame, vm, JSValue::decode(encodedBase), JSValue::decode(encodedKey));
+    DeletePropertySlot slot;
+    return deleteByVal(globalObject, callFrame, vm, slot, JSValue::decode(encodedBase), JSValue::decode(encodedSubscript));
 }
 
 JSCell* JIT_OPERATION operationPushWithScope(JSGlobalObject* globalObject, JSCell* currentScopeCell, EncodedJSValue objectValue)
index 6210c5a..600fca2 100644 (file)
@@ -251,10 +251,10 @@ EncodedJSValue JIT_OPERATION operationGetByValGeneric(JSGlobalObject*, Structure
 EncodedJSValue JIT_OPERATION operationGetByVal(JSGlobalObject*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(JSGlobalObject*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(JSGlobalObject*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo*) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationDeleteByIdJSResult(JSGlobalObject*, EncodedJSValue base, UniquedStringImpl*) WTF_INTERNAL;
-size_t JIT_OPERATION operationDeleteById(JSGlobalObject*, EncodedJSValue base, UniquedStringImpl*) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationDeleteByValJSResult(JSGlobalObject*, EncodedJSValue base, EncodedJSValue target) WTF_INTERNAL;
-size_t JIT_OPERATION operationDeleteByVal(JSGlobalObject*, EncodedJSValue base, EncodedJSValue target) WTF_INTERNAL;
+size_t JIT_OPERATION operationDeleteByIdOptimize(JSGlobalObject*, StructureStubInfo*, EncodedJSValue base, UniquedStringImpl*) WTF_INTERNAL;
+size_t JIT_OPERATION operationDeleteByIdGeneric(JSGlobalObject*, StructureStubInfo*, EncodedJSValue base, UniquedStringImpl*) WTF_INTERNAL;
+size_t JIT_OPERATION operationDeleteByValOptimize(JSGlobalObject*, StructureStubInfo*, EncodedJSValue base, EncodedJSValue target) WTF_INTERNAL;
+size_t JIT_OPERATION operationDeleteByValGeneric(JSGlobalObject*, StructureStubInfo*, EncodedJSValue base, EncodedJSValue target) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationPushWithScope(JSGlobalObject*, JSCell* currentScopeCell, EncodedJSValue object) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationPushWithScopeObject(JSGlobalObject* globalObject, JSCell* currentScopeCell, JSObject* object) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationGetPNames(JSGlobalObject*, JSObject*) WTF_INTERNAL;
index abf52f7..2ba0fa6 100644 (file)
@@ -387,9 +387,39 @@ void JIT::emit_op_del_by_id(const Instruction* currentInstruction)
     auto bytecode = currentInstruction->as<OpDelById>();
     VirtualRegister dst = bytecode.m_dst;
     VirtualRegister base = bytecode.m_base;
-    int property = bytecode.m_property;
+
+    emitGetVirtualRegister(base, regT1);
+    emitJumpSlowCaseIfNotJSCell(regT1, base);
+    JITDelByIdGenerator gen(
+        m_codeBlock, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), RegisterSet::stubUnavailableRegisters(),
+        JSValueRegs(regT1), regT0, regT2);
+    gen.generateFastPath(*this);
+    addSlowCase(gen.slowPathJump());
+    m_delByIds.append(gen);
+
+    boxBoolean(regT0, JSValueRegs(regT0));
+    emitPutVirtualRegister(dst, JSValueRegs(regT0));
+}
+
+void JIT::emitSlow_op_del_by_id(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkAllSlowCases(iter);
+
+    auto bytecode = currentInstruction->as<OpDelById>();
+    VirtualRegister dst = bytecode.m_dst;
+    VirtualRegister base = bytecode.m_base;
+    UniquedStringImpl* uid = m_codeBlock->identifier(bytecode.m_property).impl();
+
+    JITDelByIdGenerator& gen = m_delByIds[m_delByIdIndex++];
+
+    Label coldPathBegin = label();
+
     emitGetVirtualRegister(base, regT0);
-    callOperation(operationDeleteByIdJSResult, dst, TrustedImmPtr(m_codeBlock->globalObject()), regT0, m_codeBlock->identifier(property).impl());
+    Call call = callOperation(operationDeleteByIdOptimize, TrustedImmPtr(m_codeBlock->globalObject()), gen.stubInfo(), regT0, uid);
+    gen.reportSlowPathCall(coldPathBegin, call);
+
+    boxBoolean(regT0, JSValueRegs(regT0));
+    emitPutVirtualRegister(dst, JSValueRegs(regT0));
 }
 
 void JIT::emit_op_del_by_val(const Instruction* currentInstruction)
@@ -398,9 +428,42 @@ void JIT::emit_op_del_by_val(const Instruction* currentInstruction)
     VirtualRegister dst = bytecode.m_dst;
     VirtualRegister base = bytecode.m_base;
     VirtualRegister property = bytecode.m_property;
+
+    emitGetVirtualRegister(base, regT1);
+    emitJumpSlowCaseIfNotJSCell(regT1, base);
+    emitGetVirtualRegister(property, regT0);
+    emitJumpSlowCaseIfNotJSCell(regT0, property);
+    JITDelByValGenerator gen(
+        m_codeBlock, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), RegisterSet::stubUnavailableRegisters(),
+        JSValueRegs(regT1), JSValueRegs(regT0), regT0, regT2);
+    gen.generateFastPath(*this);
+    addSlowCase(gen.slowPathJump());
+    m_delByVals.append(gen);
+
+    boxBoolean(regT0, JSValueRegs(regT0));
+    emitPutVirtualRegister(dst, JSValueRegs(regT0));
+}
+
+void JIT::emitSlow_op_del_by_val(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkAllSlowCases(iter);
+
+    auto bytecode = currentInstruction->as<OpDelByVal>();
+    VirtualRegister dst = bytecode.m_dst;
+    VirtualRegister base = bytecode.m_base;
+    VirtualRegister property = bytecode.m_property;
+
+    JITDelByValGenerator& gen = m_delByVals[m_delByValIndex++];
+
+    Label coldPathBegin = label();
+
     emitGetVirtualRegister(base, regT0);
     emitGetVirtualRegister(property, regT1);
-    callOperation(operationDeleteByValJSResult, dst, TrustedImmPtr(m_codeBlock->globalObject()), regT0, regT1);
+    Call call = callOperation(operationDeleteByValOptimize, TrustedImmPtr(m_codeBlock->globalObject()), gen.stubInfo(), regT0, regT1);
+    gen.reportSlowPathCall(coldPathBegin, call);
+
+    boxBoolean(regT0, JSValueRegs(regT0));
+    emitPutVirtualRegister(dst, JSValueRegs(regT0));
 }
 
 void JIT::emit_op_try_get_by_id(const Instruction* currentInstruction)
index 5cc7df9..b669dd8 100644 (file)
@@ -123,7 +123,9 @@ void JIT::emit_op_del_by_id(const Instruction* currentInstruction)
     VirtualRegister base = bytecode.m_base;
     int property = bytecode.m_property;
     emitLoad(base, regT1, regT0);
-    callOperation(operationDeleteByIdJSResult, dst, m_codeBlock->globalObject(), JSValueRegs(regT1, regT0), m_codeBlock->identifier(property).impl());
+    callOperation(operationDeleteByIdGeneric, m_codeBlock->globalObject(), nullptr, JSValueRegs(regT1, regT0), m_codeBlock->identifier(property).impl());
+    boxBoolean(regT0, JSValueRegs(regT1, regT0));
+    emitPutVirtualRegister(dst, JSValueRegs(regT1, regT0));
 }
 
 void JIT::emit_op_del_by_val(const Instruction* currentInstruction)
@@ -133,9 +135,14 @@ void JIT::emit_op_del_by_val(const Instruction* currentInstruction)
     VirtualRegister base = bytecode.m_base;
     VirtualRegister property = bytecode.m_property;
     emitLoad2(base, regT1, regT0, property, regT3, regT2);
-    callOperation(operationDeleteByValJSResult, dst, m_codeBlock->globalObject(), JSValueRegs(regT1, regT0), JSValueRegs(regT3, regT2));
+    callOperation(operationDeleteByValGeneric, m_codeBlock->globalObject(), nullptr, JSValueRegs(regT1, regT0), JSValueRegs(regT3, regT2));
+    boxBoolean(regT0, JSValueRegs(regT1, regT0));
+    emitPutVirtualRegister(dst, JSValueRegs(regT1, regT0));
 }
 
+void JIT::emitSlow_op_del_by_val(const Instruction*, Vector<SlowCaseEntry>::iterator&) { }
+void JIT::emitSlow_op_del_by_id(const Instruction*, Vector<SlowCaseEntry>::iterator&) { }
+
 void JIT::emit_op_get_by_val(const Instruction* currentInstruction)
 {
     auto bytecode = currentInstruction->as<OpGetByVal>();
index 08696b1..7bf113e 100644 (file)
@@ -641,7 +641,7 @@ static InlineCacheAction tryCachePutByID(JSGlobalObject* globalObject, CodeBlock
                     }
                 }
 
-                newCase = AccessCase::create(vm, codeBlock, ident, offset, oldStructure, newStructure, conditionSet, WTFMove(prototypeAccessChain));
+                newCase = AccessCase::createTransition(vm, codeBlock, ident, offset, oldStructure, newStructure, conditionSet, WTFMove(prototypeAccessChain));
             }
         } else if (slot.isCacheableCustom() || slot.isCacheableSetter()) {
             if (slot.isCacheableCustom()) {
@@ -734,6 +734,73 @@ void repatchPutByID(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue
         ftlThunkAwareRepatchCall(codeBlock, stubInfo.slowPathCallLocation, appropriateGenericPutByIdFunction(slot, putKind));
 }
 
+static InlineCacheAction tryCacheDelBy(JSGlobalObject* globalObject, CodeBlock* codeBlock, DeletePropertySlot& slot, JSValue baseValue, Structure* oldStructure, const Identifier& propertyName, StructureStubInfo& stubInfo, DelByKind)
+{
+    VM& vm = globalObject->vm();
+    AccessGenerationResult result;
+
+    {
+        GCSafeConcurrentJSLocker locker(codeBlock->m_lock, globalObject->vm().heap);
+
+        if (forceICFailure(globalObject))
+            return GiveUpOnCache;
+
+        ASSERT(oldStructure);
+        if (!baseValue.isObject() || !oldStructure->propertyAccessesAreCacheable())
+            return GiveUpOnCache;
+
+        if (!slot.isCacheableDelete())
+            return GiveUpOnCache;
+
+        std::unique_ptr<AccessCase> newCase;
+
+        if (slot.isDeleteHit()) {
+            PropertyOffset newOffset = invalidOffset;
+            Structure* newStructure = Structure::removePropertyTransitionFromExistingStructureConcurrently(oldStructure, propertyName, newOffset);
+            if (!newStructure)
+                return RetryCacheLater;
+            if (!newStructure->propertyAccessesAreCacheable() || newStructure->isDictionary())
+                return GiveUpOnCache;
+            ASSERT(newOffset == slot.cachedOffset());
+            ASSERT(newStructure->previousID(vm) == oldStructure);
+            ASSERT(newStructure->isPropertyDeletionTransition());
+            ASSERT(newStructure->isObject());
+            ASSERT(isValidOffset(newOffset));
+            newCase = AccessCase::createDelete(vm, codeBlock, CacheableIdentifier(propertyName), newOffset, oldStructure, newStructure);
+        } else if (!codeBlock->isStrictMode()) {
+            if (slot.isNonconfigurable())
+                newCase = AccessCase::create(vm, codeBlock, AccessCase::DeleteNonConfigurable, CacheableIdentifier(propertyName), invalidOffset, oldStructure, { }, nullptr);
+            else
+                newCase = AccessCase::create(vm, codeBlock, AccessCase::DeleteMiss, CacheableIdentifier(propertyName), invalidOffset, oldStructure, { }, nullptr);
+        }
+
+        result = stubInfo.addAccessCase(locker, codeBlock, propertyName, WTFMove(newCase));
+
+        if (result.generatedSomeCode()) {
+            RELEASE_ASSERT(result.code());
+            LOG_IC((ICEvent::DelByReplaceWithJump, oldStructure->classInfo(), propertyName));
+            InlineAccess::rewireStubAsJump(stubInfo, CodeLocationLabel<JITStubRoutinePtrTag>(result.code()));
+        }
+    }
+
+    fireWatchpointsAndClearStubIfNeeded(vm, stubInfo, codeBlock, result);
+
+    return result.shouldGiveUpNow() ? GiveUpOnCache : RetryCacheLater;
+}
+
+void repatchDelBy(JSGlobalObject* globalObject, CodeBlock* codeBlock, DeletePropertySlot& slot, JSValue baseValue, Structure* oldStructure, const Identifier& propertyName, StructureStubInfo& stubInfo, DelByKind kind)
+{
+    SuperSamplerScope superSamplerScope(false);
+
+    if (tryCacheDelBy(globalObject, codeBlock, slot, baseValue, oldStructure, propertyName, stubInfo, kind) == GiveUpOnCache) {
+        LOG_IC((ICEvent::DelByReplaceWithGeneric, baseValue.classInfoOrNull(globalObject->vm()), propertyName));
+        if (kind == DelByKind::Normal)
+            ftlThunkAwareRepatchCall(codeBlock, stubInfo.slowPathCallLocation, operationDeleteByIdGeneric);
+        else
+            ftlThunkAwareRepatchCall(codeBlock, stubInfo.slowPathCallLocation, operationDeleteByValGeneric);
+    }
+}
+
 static InlineCacheAction tryCacheInByID(
     JSGlobalObject* globalObject, CodeBlock* codeBlock, JSObject* base, const Identifier& ident,
     bool wasFound, const PropertySlot& slot, StructureStubInfo& stubInfo)
@@ -1391,6 +1458,15 @@ void resetPutByID(CodeBlock* codeBlock, StructureStubInfo& stubInfo)
     InlineAccess::rewireStubAsJump(stubInfo, stubInfo.slowPathStartLocation);
 }
 
+void resetDelBy(CodeBlock* codeBlock, StructureStubInfo& stubInfo, DelByKind kind)
+{
+    if (kind == DelByKind::Normal)
+        ftlThunkAwareRepatchCall(codeBlock, stubInfo.slowPathCallLocation, operationDeleteByIdOptimize);
+    else
+        ftlThunkAwareRepatchCall(codeBlock, stubInfo.slowPathCallLocation, operationDeleteByValOptimize);
+    InlineAccess::rewireStubAsJump(stubInfo, stubInfo.slowPathStartLocation);
+}
+
 static void resetPatchableJump(StructureStubInfo& stubInfo)
 {
     MacroAssembler::repatchJump(stubInfo.patchableJump(), stubInfo.slowPathStartLocation);
index 6f0f264..c1d9959 100644 (file)
@@ -41,9 +41,15 @@ enum class GetByKind {
     Direct
 };
 
+enum class DelByKind {
+    Normal,
+    NormalByVal
+};
+
 void repatchArrayGetByVal(JSGlobalObject*, CodeBlock*, JSValue base, JSValue index, StructureStubInfo&);
 void repatchGetBy(JSGlobalObject*, CodeBlock*, JSValue, CacheableIdentifier, const PropertySlot&, StructureStubInfo&, GetByKind);
 void repatchPutByID(JSGlobalObject*, CodeBlock*, JSValue, Structure*, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
+void repatchDelBy(JSGlobalObject*, CodeBlock*, DeletePropertySlot&, JSValue, Structure*, const Identifier&, StructureStubInfo&, DelByKind);
 void repatchInByID(JSGlobalObject*, CodeBlock*, JSObject*, const Identifier&, bool wasFound, const PropertySlot&, StructureStubInfo&);
 void repatchInstanceOf(JSGlobalObject*, CodeBlock*, JSValue value, JSValue prototype, StructureStubInfo&, bool wasFound);
 void linkFor(VM&, CallFrame*, CallLinkInfo&, CodeBlock*, JSObject* callee, MacroAssemblerCodePtr<JSEntryPtrTag>);
@@ -53,6 +59,7 @@ void unlinkFor(VM&, CallLinkInfo&);
 void linkPolymorphicCall(JSGlobalObject*, CallFrame*, CallLinkInfo&, CallVariant);
 void resetGetBy(CodeBlock*, StructureStubInfo&, GetByKind);
 void resetPutByID(CodeBlock*, StructureStubInfo&);
+void resetDelBy(CodeBlock*, StructureStubInfo&, DelByKind);
 void resetInByID(CodeBlock*, StructureStubInfo&);
 void resetInstanceOf(StructureStubInfo&);
 void ftlThunkAwareRepatchCall(CodeBlock*, CodeLocationCall<JSInternalPtrTag>, FunctionPtr<CFunctionPtrTag> newCalleeFunction);
index b911ee2..2bffc38 100644 (file)
@@ -925,7 +925,7 @@ LLINT_SLOW_PATH_DECL(slow_path_del_by_id)
     auto bytecode = pc->as<OpDelById>();
     JSObject* baseObject = getOperand(callFrame, bytecode.m_base).toObject(globalObject);
     LLINT_CHECK_EXCEPTION();
-    bool couldDelete = baseObject->methodTable(vm)->deleteProperty(baseObject, globalObject, codeBlock->identifier(bytecode.m_property));
+    bool couldDelete = JSCell::deleteProperty(baseObject, globalObject, codeBlock->identifier(bytecode.m_property));
     LLINT_CHECK_EXCEPTION();
     if (!couldDelete && codeBlock->isStrictMode())
         LLINT_THROW(createTypeError(globalObject, UnableToDeletePropertyError));
@@ -1108,7 +1108,7 @@ LLINT_SLOW_PATH_DECL(slow_path_del_by_val)
         LLINT_CHECK_EXCEPTION();
         auto property = subscript.toPropertyKey(globalObject);
         LLINT_CHECK_EXCEPTION();
-        couldDelete = baseObject->methodTable(vm)->deleteProperty(baseObject, globalObject, property);
+        couldDelete = JSCell::deleteProperty(baseObject, globalObject, property);
     }
     LLINT_CHECK_EXCEPTION();
 
index ffb3eb9..107b5d6 100644 (file)
@@ -42,6 +42,7 @@ inline CacheableIdentifier::CacheableIdentifier(const Identifier& identifier)
 
 inline CacheableIdentifier::CacheableIdentifier(JSCell* identifier)
 {
+    ASSERT(isCacheableIdentifierCell(identifier));
     setCellBits(identifier);
 }
 
index fe6c6b7..7a59b8f 100644 (file)
@@ -59,7 +59,7 @@ struct MethodTable {
     using PutByIndexFunctionPtr = bool (*)(JSCell*, JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
     PutByIndexFunctionPtr METHOD_TABLE_ENTRY(putByIndex);
 
-    using DeletePropertyFunctionPtr = bool (*)(JSCell*, JSGlobalObject*, PropertyName);
+    using DeletePropertyFunctionPtr = bool (*)(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     DeletePropertyFunctionPtr METHOD_TABLE_ENTRY(deleteProperty);
 
     using DeletePropertyByIndexFunctionPtr = bool (*)(JSCell*, JSGlobalObject*, unsigned);
index c4f74c0..8ddd98a 100644 (file)
@@ -220,7 +220,7 @@ bool ClonedArguments::put(JSCell* cell, JSGlobalObject* globalObject, PropertyNa
     return Base::put(thisObject, globalObject, ident, value, slot);
 }
 
-bool ClonedArguments::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName ident)
+bool ClonedArguments::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName ident, DeletePropertySlot& slot)
 {
     ClonedArguments* thisObject = jsCast<ClonedArguments*>(cell);
     VM& vm = globalObject->vm();
@@ -229,7 +229,7 @@ bool ClonedArguments::deleteProperty(JSCell* cell, JSGlobalObject* globalObject,
         || ident == vm.propertyNames->iteratorSymbol)
         thisObject->materializeSpecialsIfNecessary(globalObject);
     
-    return Base::deleteProperty(thisObject, globalObject, ident);
+    return Base::deleteProperty(thisObject, globalObject, ident, slot);
 }
 
 bool ClonedArguments::defineOwnProperty(JSObject* object, JSGlobalObject* globalObject, PropertyName ident, const PropertyDescriptor& descriptor, bool shouldThrow)
index fd3a27b..00c5347 100644 (file)
@@ -72,7 +72,7 @@ private:
     static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
     static void getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
     
     bool specialsMaterialized() const { return !m_callee; }
index 0e2bc3a..44d8fb4 100644 (file)
@@ -985,7 +985,7 @@ SLOW_PATH_DECL(slow_path_del_by_val)
         CHECK_EXCEPTION();
         auto property = subscript.toPropertyKey(globalObject);
         CHECK_EXCEPTION();
-        couldDelete = baseObject->methodTable(vm)->deleteProperty(baseObject, globalObject, property);
+        couldDelete = JSCell::deleteProperty(baseObject, globalObject, property);
     }
     CHECK_EXCEPTION();
     
diff --git a/Source/JavaScriptCore/runtime/DeletePropertySlot.h b/Source/JavaScriptCore/runtime/DeletePropertySlot.h
new file mode 100644 (file)
index 0000000..0ad6f6b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#pragma once
+
+#include "PropertyOffset.h"
+#include "PropertySlot.h"
+
+namespace JSC {
+    
+class DeletePropertySlot {
+public:
+    enum Type : uint8_t { Uncacheable, DeleteHit, ConfigurableDeleteMiss, Nonconfigurable };
+
+    DeletePropertySlot()
+        : m_offset(invalidOffset)
+        , m_cacheability(CachingAllowed)
+        , m_type(Uncacheable)
+    {
+    }
+
+    void setConfigurableMiss()
+    {
+        m_type = ConfigurableDeleteMiss;
+    }
+
+    void setNonconfigurable()
+    {
+        m_type = Nonconfigurable;
+    }
+
+    void setHit(PropertyOffset offset)
+    {
+        m_type = DeleteHit;
+        m_offset = offset;
+    }
+
+    bool isCacheableDelete() const { return isCacheable() && m_type != Uncacheable; }
+    bool isDeleteHit() const { return m_type == DeleteHit; }
+    bool isConfigurableDeleteMiss() const { return m_type == ConfigurableDeleteMiss; }
+    bool isNonconfigurable() const { return m_type == Nonconfigurable; }
+
+    PropertyOffset cachedOffset() const
+    {
+        return m_offset;
+    }
+
+    void disableCaching()
+    {
+        m_cacheability = CachingDisallowed;
+    }
+
+private:
+    bool isCacheable() const { return m_cacheability == CachingAllowed; }
+
+    PropertyOffset m_offset;
+    CacheabilityType m_cacheability;
+    Type m_type;
+};
+
+} // namespace JSC
index f1821d5..685c7ac 100644 (file)
@@ -87,7 +87,7 @@ bool ErrorConstructor::put(JSCell* cell, JSGlobalObject* globalObject, PropertyN
     return Base::put(thisObject, globalObject, propertyName, value, slot);
 }
 
-bool ErrorConstructor::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool ErrorConstructor::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     VM& vm = globalObject->vm();
     ErrorConstructor* thisObject = jsCast<ErrorConstructor*>(cell);
@@ -95,7 +95,7 @@ bool ErrorConstructor::deleteProperty(JSCell* cell, JSGlobalObject* globalObject
     if (propertyName == vm.propertyNames->stackTraceLimit)
         thisObject->globalObject()->setStackTraceLimit(WTF::nullopt);
 
-    return Base::deleteProperty(thisObject, globalObject, propertyName);
+    return Base::deleteProperty(thisObject, globalObject, propertyName, slot);
 }
 
 } // namespace JSC
index 93d5271..9a5a463 100644 (file)
@@ -49,7 +49,7 @@ protected:
     void finishCreation(VM&, ErrorPrototype*);
 
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
 
 private:
     ErrorConstructor(VM&, Structure*);
index fd48bbf..1d50cd1 100644 (file)
@@ -297,12 +297,12 @@ bool ErrorInstance::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName
     return Base::put(thisObject, globalObject, propertyName, value, slot);
 }
 
-bool ErrorInstance::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool ErrorInstance::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     VM& vm = globalObject->vm();
     ErrorInstance* thisObject = jsCast<ErrorInstance*>(cell);
     thisObject->materializeErrorInfoIfNeeded(vm, propertyName);
-    return Base::deleteProperty(thisObject, globalObject, propertyName);
+    return Base::deleteProperty(thisObject, globalObject, propertyName, slot);
 }
 
 } // namespace JSC
index f1fac59..400608d 100644 (file)
@@ -99,7 +99,7 @@ protected:
     static void getStructurePropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
 
     void computeErrorInfo(VM&);
 
index ce10f7f..4712167 100644 (file)
@@ -50,7 +50,7 @@ protected:
     static void getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     static bool putByIndex(JSCell*, JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned propertyName);
     static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
     
index b837ec1..a5a9ecb 100644 (file)
@@ -139,8 +139,10 @@ bool GenericArguments<Type>::put(JSCell* cell, JSGlobalObject* globalObject, Pro
         thisObject->setIndexQuickly(vm, index.value(), value);
         return true;
     }
-    
-    RELEASE_AND_RETURN(scope, Base::put(thisObject, globalObject, ident, value, slot));
+
+    auto result = Base::put(thisObject, globalObject, ident, value, slot);
+    RETURN_IF_EXCEPTION(scope, false);
+    RELEASE_AND_RETURN(scope, result);
 }
 
 template<typename Type>
@@ -158,7 +160,7 @@ bool GenericArguments<Type>::putByIndex(JSCell* cell, JSGlobalObject* globalObje
 }
 
 template<typename Type>
-bool GenericArguments<Type>::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName ident)
+bool GenericArguments<Type>::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName ident, DeletePropertySlot& slot)
 {
     Type* thisObject = jsCast<Type*>(cell);
     VM& vm = globalObject->vm();
@@ -175,7 +177,7 @@ bool GenericArguments<Type>::deleteProperty(JSCell* cell, JSGlobalObject* global
     if (Optional<uint32_t> index = parseIndex(ident))
         RELEASE_AND_RETURN(scope, GenericArguments<Type>::deletePropertyByIndex(thisObject, globalObject, *index));
 
-    RELEASE_AND_RETURN(scope, Base::deleteProperty(thisObject, globalObject, ident));
+    RELEASE_AND_RETURN(scope, Base::deleteProperty(thisObject, globalObject, ident, slot));
 }
 
 template<typename Type>
index 03487f6..601f1e4 100644 (file)
@@ -127,7 +127,7 @@ public:
     static bool putByIndex(JSCell*, JSGlobalObject*, unsigned, JSValue, bool) { RELEASE_ASSERT_NOT_REACHED(); return false; }
     static bool setPrototype(JSObject*, JSGlobalObject*, JSValue, bool) { RELEASE_ASSERT_NOT_REACHED(); return false; }
     static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool) { RELEASE_ASSERT_NOT_REACHED(); return false; }
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName) { RELEASE_ASSERT_NOT_REACHED(); return false; }
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&) { RELEASE_ASSERT_NOT_REACHED(); return false; }
 
 private:
     WriteBarrier<JSObject> m_getter;
index 6d07591..bce3655 100644 (file)
@@ -306,7 +306,7 @@ bool JSArray::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName prope
     RELEASE_AND_RETURN(scope, JSObject::put(thisObject, globalObject, propertyName, value, slot));
 }
 
-bool JSArray::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool JSArray::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     VM& vm = globalObject->vm();
     JSArray* thisObject = jsCast<JSArray*>(cell);
@@ -314,7 +314,7 @@ bool JSArray::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, Propert
     if (propertyName == vm.propertyNames->length)
         return false;
 
-    return JSObject::deleteProperty(thisObject, globalObject, propertyName);
+    return JSObject::deleteProperty(thisObject, globalObject, propertyName, slot);
 }
 
 static int compareKeysForQSort(const void* a, const void* b)
index 31165b5..cdc39b5 100644 (file)
@@ -182,7 +182,7 @@ protected:
 
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
 
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
 
 private:
index fe0180d..586af3f 100644 (file)
@@ -40,6 +40,7 @@
 namespace JSC {
 
 class AssemblyHelpers;
+class DeletePropertySlot;
 class JSBigInt;
 class CallFrame;
 class JSCell;
index 271352b..24ed652 100644 (file)
@@ -126,10 +126,17 @@ bool JSCell::putByIndex(JSCell* cell, JSGlobalObject* globalObject, unsigned ide
     return thisObject->methodTable(vm)->putByIndex(thisObject, globalObject, identifier, value, shouldThrow);
 }
 
+bool JSCell::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName identifier, DeletePropertySlot& slot)
+{
+    JSObject* thisObject = cell->toObject(globalObject);
+    return thisObject->methodTable(globalObject->vm())->deleteProperty(thisObject, globalObject, identifier, slot);
+}
+
 bool JSCell::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName identifier)
 {
     JSObject* thisObject = cell->toObject(globalObject);
-    return thisObject->methodTable(globalObject->vm())->deleteProperty(thisObject, globalObject, identifier);
+    DeletePropertySlot slot;
+    return thisObject->methodTable(globalObject->vm())->deleteProperty(thisObject, globalObject, identifier, slot);
 }
 
 bool JSCell::deletePropertyByIndex(JSCell* cell, JSGlobalObject* globalObject, unsigned identifier)
index d5656f8..106749d 100644 (file)
@@ -181,7 +181,8 @@ public:
     static bool putByIndex(JSCell*, JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
     bool putInline(JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
         
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
+    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
     static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned propertyName);
 
     static JSValue toThis(JSCell*, JSGlobalObject*, ECMAMode);
index 146a913..1b25523 100644 (file)
@@ -152,7 +152,7 @@ bool JSDataView::defineOwnProperty(
 }
 
 bool JSDataView::deleteProperty(
-    JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+    JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     VM& vm = globalObject->vm();
     JSDataView* thisObject = jsCast<JSDataView*>(cell);
@@ -160,7 +160,7 @@ bool JSDataView::deleteProperty(
         || propertyName == vm.propertyNames->byteOffset)
         return false;
 
-    return Base::deleteProperty(thisObject, globalObject, propertyName);
+    return Base::deleteProperty(thisObject, globalObject, propertyName, slot);
 }
 
 void JSDataView::getOwnNonIndexPropertyNames(
index 86410e6..98a8cc8 100644 (file)
@@ -72,7 +72,7 @@ protected:
     static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
 
     static void getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
 
index ee85ee0..8b8d506 100644 (file)
@@ -586,7 +586,7 @@ bool JSFunction::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName pr
     RELEASE_AND_RETURN(scope, Base::put(thisObject, globalObject, propertyName, value, slot));
 }
 
-bool JSFunction::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool JSFunction::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -617,7 +617,7 @@ bool JSFunction::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, Prop
         RETURN_IF_EXCEPTION(scope, false);
     }
     
-    RELEASE_AND_RETURN(scope, Base::deleteProperty(thisObject, globalObject, propertyName));
+    RELEASE_AND_RETURN(scope, Base::deleteProperty(thisObject, globalObject, propertyName, slot));
 }
 
 bool JSFunction::defineOwnProperty(JSObject* object, JSGlobalObject* globalObject, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
index addde2a..18ab475 100644 (file)
@@ -179,7 +179,7 @@ protected:
 
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
 
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
 
     static void visitChildren(JSCell*, SlotVisitor&);
 
index f08f852..3b7bbde 100644 (file)
@@ -305,7 +305,7 @@ protected:
     static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
 
     static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned propertyName, PropertySlot&);
     static bool putByIndex(JSCell*, JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
index 0cafbd2..1a0cf59 100644 (file)
@@ -438,7 +438,7 @@ bool JSGenericTypedArrayView<Adaptor>::defineOwnProperty(
 
 template<typename Adaptor>
 bool JSGenericTypedArrayView<Adaptor>::deleteProperty(
-    JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+    JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -450,7 +450,7 @@ bool JSGenericTypedArrayView<Adaptor>::deleteProperty(
     if (parseIndex(propertyName))
         return false;
     
-    return Base::deleteProperty(thisObject, globalObject, propertyName);
+    return Base::deleteProperty(thisObject, globalObject, propertyName, slot);
 }
 
 template<typename Adaptor>
@@ -484,7 +484,7 @@ bool JSGenericTypedArrayView<Adaptor>::deletePropertyByIndex(
     JSCell* cell, JSGlobalObject* globalObject, unsigned propertyName)
 {
     VM& vm = globalObject->vm();
-    return cell->methodTable(vm)->deleteProperty(cell, globalObject, Identifier::from(vm, propertyName));
+    return JSCell::deleteProperty(cell, globalObject, Identifier::from(vm, propertyName));
 }
 
 template<typename Adaptor>
index b3c980a..fe217fb 100644 (file)
@@ -1314,7 +1314,7 @@ void JSGlobalObject::addFunction(JSGlobalObject* globalObject, const Identifier&
 {
     VM& vm = globalObject->vm();
     VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-    methodTable(vm)->deleteProperty(this, globalObject, propertyName);
+    JSCell::deleteProperty(this, globalObject, propertyName);
     addGlobalVar(propertyName);
 }
 
index f345c50..974b92b 100644 (file)
@@ -127,13 +127,13 @@ bool JSLexicalEnvironment::put(JSCell* cell, JSGlobalObject* globalObject, Prope
     return thisObject->putOwnDataProperty(globalObject->vm(), propertyName, value, slot);
 }
 
-bool JSLexicalEnvironment::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool JSLexicalEnvironment::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     VM& vm = globalObject->vm();
     if (propertyName == vm.propertyNames->arguments)
         return false;
 
-    return Base::deleteProperty(cell, globalObject, propertyName);
+    return Base::deleteProperty(cell, globalObject, propertyName, slot);
 }
 
 } // namespace JSC
index d013b51..05e4e65 100644 (file)
@@ -110,7 +110,7 @@ public:
 
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
 
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
 
     DECLARE_INFO;
 
index feb5510..858a942 100644 (file)
@@ -127,7 +127,7 @@ bool JSModuleEnvironment::put(JSCell* cell, JSGlobalObject* globalObject, Proper
     RELEASE_AND_RETURN(scope, Base::put(thisObject, globalObject, propertyName, value, slot));
 }
 
-bool JSModuleEnvironment::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool JSModuleEnvironment::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -138,7 +138,7 @@ bool JSModuleEnvironment::deleteProperty(JSCell* cell, JSGlobalObject* globalObj
     RETURN_IF_EXCEPTION(scope, false);
     if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved)
         return false;
-    return Base::deleteProperty(thisObject, globalObject, propertyName);
+    return Base::deleteProperty(thisObject, globalObject, propertyName, slot);
 }
 
 } // namespace JSC
index daeab66..0130f87 100644 (file)
@@ -77,7 +77,7 @@ public:
     static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
     static void getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
 
 private:
     JSModuleEnvironment(VM&, Structure*, JSScope*, SymbolTable*);
index 2bdb130..1fc6a26 100644 (file)
@@ -199,12 +199,12 @@ bool JSModuleNamespaceObject::putByIndex(JSCell*, JSGlobalObject* globalObject,
     return false;
 }
 
-bool JSModuleNamespaceObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool JSModuleNamespaceObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-delete-p
     JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
     if (propertyName.isSymbol())
-        return JSObject::deleteProperty(thisObject, globalObject, propertyName);
+        return JSObject::deleteProperty(thisObject, globalObject, propertyName, slot);
 
     return !thisObject->m_exports.contains(propertyName.uid());
 }
index 8eef621..811364d 100644 (file)
@@ -56,7 +56,7 @@ public:
     JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned propertyName, PropertySlot&);
     JS_EXPORT_PRIVATE static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     JS_EXPORT_PRIVATE static bool putByIndex(JSCell*, JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
-    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
 
index d0d1721..99b3d08 100644 (file)
@@ -760,7 +760,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
                 JSValue filteredValue = callReviver(object, jsString(vm, prop.string()), outValue);
                 RETURN_IF_EXCEPTION(scope, { });
                 if (filteredValue.isUndefined())
-                    object->methodTable(vm)->deleteProperty(object, m_globalObject, prop);
+                    JSCell::deleteProperty(object, m_globalObject, prop);
                 else
                     object->methodTable(vm)->put(object, m_globalObject, prop, filteredValue, slot);
                 RETURN_IF_EXCEPTION(scope, { });
index 3a5121d..45f4236 100644 (file)
@@ -1972,7 +1972,7 @@ bool JSObject::hasPropertyGeneric(JSGlobalObject* globalObject, unsigned propert
 }
 
 // ECMA 8.6.2.5
-bool JSObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool JSObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     JSObject* thisObject = jsCast<JSObject*>(cell);
     VM& vm = globalObject->vm();
@@ -1999,8 +1999,10 @@ bool JSObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, Proper
 
     bool propertyIsPresent = isValidOffset(structure->get(vm, propertyName, attributes));
     if (propertyIsPresent) {
-        if (attributes & PropertyAttribute::DontDelete && vm.deletePropertyMode() != VM::DeletePropertyMode::IgnoreConfigurable)
+        if (attributes & PropertyAttribute::DontDelete && vm.deletePropertyMode() != VM::DeletePropertyMode::IgnoreConfigurable) {
+            slot.setNonconfigurable();
             return false;
+        }
         DeferredStructureTransitionWatchpointFire deferredWatchpointFire(vm, structure);
 
         PropertyOffset offset = invalidOffset;
@@ -2008,7 +2010,9 @@ bool JSObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, Proper
             offset = structure->removePropertyWithoutTransition(vm, propertyName, [](const GCSafeConcurrentJSCellLocker&, PropertyOffset, PropertyOffset) { });
         else {
             structure = Structure::removePropertyTransition(vm, structure, propertyName, offset, &deferredWatchpointFire);
-            if (thisObject->m_butterfly && !structure->outOfLineCapacity() && !structure->hasIndexingHeader(thisObject)) {
+            slot.setHit(offset);
+            if (!structure->outOfLineCapacity() && thisObject->structure(vm)->outOfLineCapacity() && !structure->hasIndexingHeader(thisObject)) {
+                ASSERT(thisObject->m_butterfly);
                 thisObject->nukeStructureAndSetButterfly(vm, thisObject->structureID(), nullptr);
                 offset = invalidOffset;
                 ASSERT(structure->maxOffset() == invalidOffset);
@@ -2020,7 +2024,8 @@ bool JSObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, Proper
 
         if (offset != invalidOffset)
             thisObject->locationForOffset(offset)->clear();
-    }
+    } else
+        slot.setConfigurableMiss();
 
     return true;
 }
@@ -2031,7 +2036,7 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, JSGlobalObject* globalObject,
     JSObject* thisObject = jsCast<JSObject*>(cell);
     
     if (i > MAX_ARRAY_INDEX)
-        return thisObject->methodTable(vm)->deleteProperty(thisObject, globalObject, Identifier::from(vm, i));
+        return JSCell::deleteProperty(thisObject, globalObject, Identifier::from(vm, i));
     
     switch (thisObject->indexingMode()) {
     case ALL_BLANK_INDEXING_TYPES:
@@ -3625,7 +3630,7 @@ bool validateAndApplyPropertyDescriptor(JSGlobalObject* globalObject, JSObject*
     // A generic descriptor is simply changing the attributes of an existing property
     if (descriptor.isGenericDescriptor()) {
         if (!current.attributesEqual(descriptor) && object) {
-            object->methodTable(vm)->deleteProperty(object, globalObject, propertyName);
+            JSCell::deleteProperty(object, globalObject, propertyName);
             RETURN_IF_EXCEPTION(scope, false);
             return putDescriptor(globalObject, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
         }
@@ -3641,7 +3646,7 @@ bool validateAndApplyPropertyDescriptor(JSGlobalObject* globalObject, JSObject*
         if (!object)
             return true;
 
-        object->methodTable(vm)->deleteProperty(object, globalObject, propertyName);
+        JSCell::deleteProperty(object, globalObject, propertyName);
         RETURN_IF_EXCEPTION(scope, false);
         return putDescriptor(globalObject, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
     }
@@ -3665,7 +3670,7 @@ bool validateAndApplyPropertyDescriptor(JSGlobalObject* globalObject, JSObject*
             return true;
         if (!object)
             return true;
-        object->methodTable(vm)->deleteProperty(object, globalObject, propertyName);
+        JSCell::deleteProperty(object, globalObject, propertyName);
         RETURN_IF_EXCEPTION(scope, false);
         return putDescriptor(globalObject, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
     }
@@ -3718,7 +3723,7 @@ bool validateAndApplyPropertyDescriptor(JSGlobalObject* globalObject, JSObject*
 
     GetterSetter* getterSetter = GetterSetter::create(vm, globalObject, getter, setter);
 
-    object->methodTable(vm)->deleteProperty(object, globalObject, propertyName);
+    JSCell::deleteProperty(object, globalObject, propertyName);
     RETURN_IF_EXCEPTION(scope, false);
     unsigned attrs = descriptor.attributesOverridingCurrent(current);
     object->putDirectAccessor(globalObject, propertyName, getterSetter, attrs | PropertyAttribute::Accessor);
index 651160b..6bda9e1 100644 (file)
@@ -31,6 +31,7 @@
 #include "ClassInfo.h"
 #include "CustomGetterSetter.h"
 #include "DOMAttributeGetterSetter.h"
+#include "DeletePropertySlot.h"
 #include "Heap.h"
 #include "IndexingHeaderInlines.h"
 #include "JSCast.h"
@@ -623,7 +624,7 @@ public:
     bool hasOwnProperty(JSGlobalObject*, PropertyName) const;
     bool hasOwnProperty(JSGlobalObject*, unsigned) const;
 
-    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned propertyName);
 
     JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
index 9c47934..d0bbc2c 100644 (file)
@@ -91,10 +91,10 @@ bool JSProxy::defineOwnProperty(JSObject* object, JSGlobalObject* globalObject,
     return thisObject->target()->methodTable(globalObject->vm())->defineOwnProperty(thisObject->target(), globalObject, propertyName, descriptor, shouldThrow);
 }
 
-bool JSProxy::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool JSProxy::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     JSProxy* thisObject = jsCast<JSProxy*>(cell);
-    return thisObject->target()->methodTable(globalObject->vm())->deleteProperty(thisObject->target(), globalObject, propertyName);
+    return thisObject->target()->methodTable(globalObject->vm())->deleteProperty(thisObject->target(), globalObject, propertyName, slot);
 }
 
 bool JSProxy::isExtensible(JSObject* object, JSGlobalObject* globalObject)
index 351e668..5be7bf0 100644 (file)
@@ -93,7 +93,7 @@ protected:
     JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned, PropertySlot&);
     JS_EXPORT_PRIVATE static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     JS_EXPORT_PRIVATE static bool putByIndex(JSCell*, JSGlobalObject*, unsigned, JSValue, bool shouldThrow);
-    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned);
     JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
index 630e1b7..125f6c3 100644 (file)
@@ -44,13 +44,13 @@ void JSSymbolTableObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(thisObject->m_symbolTable);
 }
 
-bool JSSymbolTableObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool JSSymbolTableObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     JSSymbolTableObject* thisObject = jsCast<JSSymbolTableObject*>(cell);
     if (thisObject->symbolTable()->contains(propertyName.uid()))
         return false;
 
-    return Base::deleteProperty(thisObject, globalObject, propertyName);
+    return Base::deleteProperty(thisObject, globalObject, propertyName, slot);
 }
 
 void JSSymbolTableObject::getOwnNonIndexPropertyNames(JSObject* object, JSGlobalObject* globalObject, PropertyNameArray& propertyNames, EnumerationMode mode)
index c7c1e20..b568e8f 100644 (file)
@@ -43,7 +43,7 @@ public:
 
     SymbolTable* symbolTable() const { return m_symbolTable.get(); }
     
-    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     
     static ptrdiff_t offsetOfSymbolTable() { return OBJECT_OFFSETOF(JSSymbolTableObject, m_symbolTable); }
index b652022..b07e0a0 100644 (file)
@@ -685,12 +685,12 @@ bool ProxyObject::performDelete(JSGlobalObject* globalObject, PropertyName prope
     return true;
 }
 
-bool ProxyObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool ProxyObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
     auto performDefaultDelete = [&] () -> bool {
         JSObject* target = thisObject->target();
-        return target->methodTable(globalObject->vm())->deleteProperty(target, globalObject, propertyName);
+        return target->methodTable(globalObject->vm())->deleteProperty(target, globalObject, propertyName, slot);
     };
     return thisObject->performDelete(globalObject, propertyName, performDefaultDelete);
 }
index 17ca29f..ee5bd90 100644 (file)
@@ -85,7 +85,7 @@ private:
     static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned propertyName, PropertySlot&);
     static CallType getCallData(JSCell*, CallData&);
     static ConstructType getConstructData(JSCell*, ConstructData&);
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned propertyName);
     static bool preventExtensions(JSObject*, JSGlobalObject*);
     static bool isExtensible(JSObject*, JSGlobalObject*);
index 46dcb75..1ce1b4c 100644 (file)
@@ -71,12 +71,12 @@ bool RegExpObject::getOwnPropertySlot(JSObject* object, JSGlobalObject* globalOb
     return Base::getOwnPropertySlot(object, globalObject, propertyName, slot);
 }
 
-bool RegExpObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool RegExpObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     VM& vm = globalObject->vm();
     if (propertyName == vm.propertyNames->lastIndex)
         return false;
-    return Base::deleteProperty(cell, globalObject, propertyName);
+    return Base::deleteProperty(cell, globalObject, propertyName, slot);
 }
 
 void RegExpObject::getOwnNonIndexPropertyNames(JSObject* object, JSGlobalObject* globalObject, PropertyNameArray& propertyNames, EnumerationMode mode)
index 5e99eb3..857ca2e 100644 (file)
@@ -144,7 +144,7 @@ protected:
         m_regExpAndLastIndexIsNotWritableFlag = (m_regExpAndLastIndexIsNotWritableFlag | lastIndexIsNotWritableFlag);
     }
 
-    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
index 5157527..51dbc67 100644 (file)
@@ -40,7 +40,7 @@ StrictEvalActivation::StrictEvalActivation(VM& vm, Structure* structure, JSScope
 {
 }
 
-bool StrictEvalActivation::deleteProperty(JSCell*, JSGlobalObject*, PropertyName)
+bool StrictEvalActivation::deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&)
 {
     return false;
 }
index cdcc21b..241545e 100644 (file)
@@ -46,7 +46,7 @@ public:
         return scope;
     }
 
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
index 477b9ca..486dd92 100644 (file)
@@ -125,7 +125,7 @@ bool StringObject::defineOwnProperty(JSObject* object, JSGlobalObject* globalObj
     RELEASE_AND_RETURN(scope, Base::defineOwnProperty(object, globalObject, propertyName, descriptor, throwException));
 }
 
-bool StringObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName)
+bool StringObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     VM& vm = globalObject->vm();
     StringObject* thisObject = jsCast<StringObject*>(cell);
@@ -134,7 +134,7 @@ bool StringObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, Pr
     Optional<uint32_t> index = parseIndex(propertyName);
     if (index && thisObject->internalValue()->canGetIndex(index.value()))
         return false;
-    return JSObject::deleteProperty(thisObject, globalObject, propertyName);
+    return JSObject::deleteProperty(thisObject, globalObject, propertyName, slot);
 }
 
 bool StringObject::deletePropertyByIndex(JSCell* cell, JSGlobalObject* globalObject, unsigned i)
index a340581..69f26b7 100644 (file)
@@ -57,7 +57,7 @@ public:
     JS_EXPORT_PRIVATE static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     JS_EXPORT_PRIVATE static bool putByIndex(JSCell*, JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
 
-    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned propertyName);
     JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
index 64c800b..832ce44 100644 (file)
@@ -539,8 +539,7 @@ Structure* Structure::addNewPropertyTransition(VM& vm, Structure* structure, Pro
 
 Structure* Structure::removePropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, PropertyOffset& offset, DeferredStructureTransitionWatchpointFire* deferred)
 {
-    Structure* newStructure = removePropertyTransitionFromExistingStructure(
-        vm, structure, propertyName, offset, deferred);
+    Structure* newStructure = removePropertyTransitionFromExistingStructure(structure, propertyName, offset);
     if (newStructure)
         return newStructure;
 
@@ -548,16 +547,13 @@ Structure* Structure::removePropertyTransition(VM& vm, Structure* structure, Pro
         vm, structure, propertyName, offset, deferred);
 }
 
-Structure* Structure::removePropertyTransitionFromExistingStructure(VM& vm, Structure* structure, PropertyName propertyName, PropertyOffset& offset, DeferredStructureTransitionWatchpointFire*)
+Structure* Structure::removePropertyTransitionFromExistingStructureImpl(Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset)
 {
-    ASSERT(!isCompilationThread());
     ASSERT(!structure->isUncacheableDictionary());
     ASSERT(structure->isObject());
 
-    unsigned attributes;
-    structure->get(vm, propertyName, attributes);
-
     constexpr bool isAddition = false;
+    offset = invalidOffset;
     if (Structure* existingTransition = structure->m_transitionTable.get(propertyName.uid(), attributes, isAddition)) {
         validateOffset(existingTransition->transitionOffset(), existingTransition->inlineCapacity());
         offset = existingTransition->transitionOffset();
@@ -567,11 +563,31 @@ Structure* Structure::removePropertyTransitionFromExistingStructure(VM& vm, Stru
     return nullptr;
 }
 
+Structure* Structure::removePropertyTransitionFromExistingStructure(Structure* structure, PropertyName propertyName, PropertyOffset& offset)
+{
+    ASSERT(!isCompilationThread());
+    unsigned attributes = 0;
+    if (structure->getConcurrently(propertyName.uid(), attributes) == invalidOffset)
+        return nullptr;
+    return removePropertyTransitionFromExistingStructureImpl(structure, propertyName, attributes, offset);
+}
+
+Structure* Structure::removePropertyTransitionFromExistingStructureConcurrently(Structure* structure, PropertyName propertyName, PropertyOffset& offset)
+{
+    unsigned attributes = 0;
+    if (structure->getConcurrently(propertyName.uid(), attributes) == invalidOffset)
+        return nullptr;
+    ConcurrentJSCellLocker locker(structure->cellLock());
+    return removePropertyTransitionFromExistingStructureImpl(structure, propertyName, attributes, offset);
+}
+
 Structure* Structure::removeNewPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, PropertyOffset& offset, DeferredStructureTransitionWatchpointFire* deferred)
 {
+    ASSERT(!isCompilationThread());
     ASSERT(!structure->isUncacheableDictionary());
     ASSERT(structure->isObject());
-    ASSERT(!Structure::removePropertyTransitionFromExistingStructure(vm, structure, propertyName, offset, deferred));
+    ASSERT(!Structure::removePropertyTransitionFromExistingStructure(structure, propertyName, offset));
+    ASSERT(structure->getConcurrently(propertyName.uid()) != invalidOffset);
 
     int transitionCount = 0;
     for (auto* s = structure; s && transitionCount <= s_maxTransitionLength; s = s->previousID(vm))
@@ -1203,7 +1219,7 @@ Ref<StructureShape> Structure::toStructureShape(JSValue value, bool& sawPolyProt
 
 void Structure::dump(PrintStream& out) const
 {
-    out.print(RawPointer(this), ":[", classInfo()->className, ", {");
+    out.print(RawPointer(this), ":[", RawPointer(reinterpret_cast<void*>(id())), ", ", classInfo()->className, ", {");
     
     CommaPrinter comma;
     
index 53844b9..320a47a 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "ClassInfo.h"
 #include "ConcurrentJSLock.h"
+#include "DeletePropertySlot.h"
 #include "IndexingType.h"
 #include "JSCJSValue.h"
 #include "JSCast.h"
@@ -192,7 +193,8 @@ public:
     JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
     static Structure* removeNewPropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&, DeferredStructureTransitionWatchpointFire* = nullptr);
     static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&, DeferredStructureTransitionWatchpointFire* = nullptr);
-    static Structure* removePropertyTransitionFromExistingStructure(VM&, Structure*, PropertyName, PropertyOffset&, DeferredStructureTransitionWatchpointFire* = nullptr);
+    static Structure* removePropertyTransitionFromExistingStructure(Structure*, PropertyName, PropertyOffset&);
+    static Structure* removePropertyTransitionFromExistingStructureConcurrently(Structure*, PropertyName, PropertyOffset&);
     static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype, DeferredStructureTransitionWatchpointFire&);
     JS_EXPORT_PRIVATE static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes);
     JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
@@ -530,6 +532,7 @@ public:
     }
     
     bool hasIndexingHeader(const JSCell*) const;
+    bool mayHaveIndexingHeader(bool& mustCheckCell) const;
     
     bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject);
 
@@ -811,6 +814,7 @@ private:
     static Structure* create(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
     
     static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
+    static Structure* removePropertyTransitionFromExistingStructureImpl(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
 
     // This will return the structure that has a usable property table, that property table,
     // and the list of structures that we visited before we got to it. If it returns a
index 23d78fc..3dc17b7 100644 (file)
@@ -252,10 +252,23 @@ inline bool Structure::hasIndexingHeader(const JSCell* cell) const
     
     if (!isTypedView(typedArrayTypeForType(m_blob.type())))
         return false;
-    
+
     return jsCast<const JSArrayBufferView*>(cell)->mode() == WastefulTypedArray;
 }
 
+inline bool Structure::mayHaveIndexingHeader(bool& mustCheckCell) const
+{
+    mustCheckCell = false;
+    if (hasIndexedProperties(indexingType()))
+        return true;
+
+    if (!isTypedView(typedArrayTypeForType(m_blob.type())))
+        return false;
+
+    mustCheckCell = true;
+    return true;
+}
+
 inline bool Structure::masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject)
 {
     return typeInfo().masqueradesAsUndefined() && globalObject() == lexicalGlobalObject;
index 8b846ba..9121bc6 100644 (file)
@@ -556,7 +556,7 @@ public:
         RELEASE_ASSERT_NOT_REACHED();
     }
 
-    static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName)
+    static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&)
     {
         RELEASE_ASSERT_NOT_REACHED();
     }
@@ -2850,6 +2850,15 @@ static EncodedJSValue JSC_HOST_CALL functionGetConcurrently(JSGlobalObject* glob
     return JSValue::encode(result);
 }
 
+static EncodedJSValue JSC_HOST_CALL functionHasOwnLengthProperty(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+
+    JSObject* target = asObject(callFrame->uncheckedArgument(0));
+    JSFunction* function = jsDynamicCast<JSFunction*>(vm, target);
+    return JSValue::encode(jsBoolean(function->areNameAndLengthOriginal(vm)));
+}
+
 void JSDollarVM::finishCreation(VM& vm)
 {
     DollarVMAssertScope assertScope;
@@ -2983,6 +2992,8 @@ void JSDollarVM::finishCreation(VM& vm)
     addFunction(vm, "getStructureTransitionList", JSDollarVMHelper::functionGetStructureTransitionList, 1);
     addFunction(vm, "getConcurrently", functionGetConcurrently, 2);
 
+    addFunction(vm, "hasOwnLengthProperty", functionHasOwnLengthProperty, 1);
+
     m_objectDoingSideEffectPutWithoutCorrectSlotStatusStructure.set(vm, this, ObjectDoingSideEffectPutWithoutCorrectSlotStatus::createStructure(vm, globalObject, jsNull()));
 }
 
index 691a5b7..97fac25 100644 (file)
@@ -1,3 +1,19 @@
+2020-02-25  Justin Michaud  <justin_michaud@apple.com>
+
+        Inline Cache delete by id/val
+        https://bugs.webkit.org/show_bug.cgi?id=207522
+
+        Reviewed by Keith Miller and Filip Pizlo.
+
+        * wtf/Spectrum.h:
+        (WTF::Spectrum::add):
+        (WTF::Spectrum::get const):
+        (WTF::Spectrum::buildList const):
+        (WTF::Spectrum::clear):
+        (WTF::Spectrum::removeIf):
+        (WTF::Spectrum::begin): Deleted.
+        (WTF::Spectrum::end): Deleted.
+
 2020-02-25  Philippe Normand  <pnormand@igalia.com>
 
         [WPE] Enable BACKTRACE_SYMBOLS
index cb8d3bb..4585b10 100644 (file)
@@ -42,6 +42,7 @@ public:
     
     void add(const T& key, CounterType count = 1)
     {
+        Locker locker(m_lock);
         if (!count)
             return;
         typename HashMap<T, CounterType>::AddResult result = m_map.add(key, count);
@@ -58,6 +59,7 @@ public:
     
     CounterType get(const T& key) const
     {
+        Locker locker(m_lock);
         const_iterator iter = m_map.find(key);
         if (iter == m_map.end())
             return 0;
@@ -66,8 +68,6 @@ public:
     
     size_t size() const { return m_map.size(); }
     
-    iterator begin() { return m_map.begin(); }
-    iterator end() { return m_map.end(); }
     const_iterator begin() const { return m_map.begin(); }
     const_iterator end() const { return m_map.end(); }
     
@@ -98,6 +98,7 @@ public:
     // Returns a list ordered from lowest-count to highest-count.
     Vector<KeyAndCount> buildList() const
     {
+        Locker locker(m_lock);
         Vector<KeyAndCount> list;
         for (const_iterator iter = begin(); iter != end(); ++iter)
             list.append(KeyAndCount(iter->key, iter->value));
@@ -106,17 +107,23 @@ public:
         return list;
     }
     
-    void clear() { m_map.clear(); }
+    void clear()
+    {
+        Locker locker(m_lock);
+        m_map.clear();
+    }
     
     template<typename Functor>
     void removeIf(const Functor& functor)
     {
+        Locker locker(m_lock);
         m_map.removeIf([&functor] (typename HashMap<T, CounterType>::KeyValuePairType& pair) {
                 return functor(KeyAndCount(pair.key, pair.value));
             });
     }
     
 private:
+    mutable Lock m_lock;
     HashMap<T, CounterType> m_map;
 };
 
index 727dbb2..bdeaf1f 100644 (file)
@@ -1,3 +1,55 @@
+2020-02-25  Justin Michaud  <justin_michaud@apple.com>
+
+        Inline Cache delete by id/val
+        https://bugs.webkit.org/show_bug.cgi?id=207522
+
+        Reviewed by Keith Miller and Filip Pizlo.
+
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::JSDOMWindow::deleteProperty):
+        * bindings/js/JSLocationCustom.cpp:
+        (WebCore::JSLocation::deleteProperty):
+        * bindings/js/JSRemoteDOMWindowCustom.cpp:
+        (WebCore::JSRemoteDOMWindow::deleteProperty):
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateDeleteProperty):
+        (GenerateHeader):
+        (GenerateImplementation):
+        (GenerateConstructorHelperMethods):
+        * bindings/scripts/test/JS/JSTestEnabledBySetting.cpp:
+        (WebCore::JSTestEnabledBySettingPrototype::finishCreation):
+        * bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp:
+        (WebCore::JSTestGenerateIsReachablePrototype::finishCreation):
+        * bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.cpp:
+        (WebCore::JSTestNamedDeleterNoIdentifier::deleteProperty):
+        * bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.h:
+        * bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.cpp:
+        (WebCore::JSTestNamedDeleterThrowingException::deleteProperty):
+        * bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.h:
+        * bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.cpp:
+        (WebCore::JSTestNamedDeleterWithIdentifier::deleteProperty):
+        * bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.h:
+        * bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.cpp:
+        (WebCore::JSTestNamedDeleterWithIndexedGetter::deleteProperty):
+        * bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.h:
+        * bindings/scripts/test/JS/JSTestNode.cpp:
+        (WebCore::JSTestNodePrototype::finishCreation):
+        * bindings/scripts/test/JS/JSTestObj.cpp:
+        (WebCore::JSTestObjConstructor::initializeProperties):
+        (WebCore::JSTestObjPrototype::finishCreation):
+        * bridge/NP_jsobject.cpp:
+        * bridge/objc/WebScriptObject.mm:
+        (-[WebScriptObject removeWebScriptKey:]):
+        * bridge/objc/objc_runtime.h:
+        * bridge/objc/objc_runtime.mm:
+        (JSC::Bindings::ObjcFallbackObjectImp::deleteProperty):
+        * bridge/runtime_array.cpp:
+        (JSC::RuntimeArray::deleteProperty):
+        * bridge/runtime_array.h:
+        * bridge/runtime_object.cpp:
+        (JSC::Bindings::RuntimeObject::deleteProperty):
+        * bridge/runtime_object.h:
+
 2020-02-25  Ben Nham  <nham@apple.com>
 
         Remove render update throttling
index 4e009fe..a30ced1 100644 (file)
@@ -312,13 +312,13 @@ bool JSDOMWindow::putByIndex(JSCell* cell, JSGlobalObject* lexicalGlobalObject,
     return Base::putByIndex(thisObject, lexicalGlobalObject, index, value, shouldThrow);
 }
 
-bool JSDOMWindow::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName)
+bool JSDOMWindow::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
     // Only allow deleting properties by frames in the same origin.
     if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, thisObject->wrapped(), ThrowSecurityError))
         return false;
-    return Base::deleteProperty(thisObject, lexicalGlobalObject, propertyName);
+    return Base::deleteProperty(thisObject, lexicalGlobalObject, propertyName, slot);
 }
 
 bool JSDOMWindow::deletePropertyByIndex(JSCell* cell, JSGlobalObject* lexicalGlobalObject, unsigned propertyName)
index 1ef06c2..84b9a13 100644 (file)
@@ -163,13 +163,13 @@ bool JSLocation::putByIndex(JSCell* cell, JSGlobalObject* lexicalGlobalObject, u
     return JSObject::putByIndex(cell, lexicalGlobalObject, index, value, shouldThrow);
 }
 
-bool JSLocation::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName)
+bool JSLocation::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     JSLocation* thisObject = jsCast<JSLocation*>(cell);
     // Only allow deleting by frames in the same origin.
     if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, thisObject->wrapped().window(), ThrowSecurityError))
         return false;
-    return Base::deleteProperty(thisObject, lexicalGlobalObject, propertyName);
+    return Base::deleteProperty(thisObject, lexicalGlobalObject, propertyName, slot);
 }
 
 bool JSLocation::deletePropertyByIndex(JSCell* cell, JSGlobalObject* lexicalGlobalObject, unsigned propertyName)
index e2eedfd..0cb67ef 100644 (file)
@@ -82,7 +82,7 @@ bool JSRemoteDOMWindow::putByIndex(JSCell*, JSGlobalObject*, unsigned, JSValue,
     return false;
 }
 
-bool JSRemoteDOMWindow::deleteProperty(JSCell*, JSGlobalObject* lexicalGlobalObject, PropertyName)
+bool JSRemoteDOMWindow::deleteProperty(JSCell*, JSGlobalObject* lexicalGlobalObject, PropertyName, DeletePropertySlot&)
 {
     VM& vm = lexicalGlobalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
index 03dd9c1..b7cd1fc 100644 (file)
@@ -1301,7 +1301,7 @@ sub GenerateDeleteProperty
     # This implements https://heycam.github.io/webidl/#legacy-platform-object-delete for the
     # for the deleteProperty override hook.
 
-    push(@$outputArray, "bool ${className}::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName)\n");
+    push(@$outputArray, "bool ${className}::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, DeletePropertySlot& slot)\n");
     push(@$outputArray, "{\n");
 
     push(@$outputArray, "    auto& thisObject = *jsCast<${className}*>(cell);\n");
@@ -1321,7 +1321,7 @@ sub GenerateDeleteProperty
 
     # FIXME: Instead of calling down JSObject::deleteProperty, perhaps we should implement
     # the remained of the algorithm ourselves.
-    push(@$outputArray, "    return JSObject::deleteProperty(cell, lexicalGlobalObject, propertyName);\n");
+    push(@$outputArray, "    return JSObject::deleteProperty(cell, lexicalGlobalObject, propertyName, slot);\n");
     push(@$outputArray, "}\n\n");
 }
 
@@ -2696,7 +2696,7 @@ sub GenerateHeader
     }
 
     if (InstanceOverridesDeleteProperty($interface)) {
-        push(@headerContent, "    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName);\n");
+        push(@headerContent, "    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::DeletePropertySlot&);\n");
         push(@headerContent, "    static bool deletePropertyByIndex(JSC::JSCell*, JSC::JSGlobalObject*, unsigned);\n");
     }
 
@@ -4324,7 +4324,8 @@ sub GenerateImplementation
             push(@implContent, "        hasDisabledRuntimeProperties = true;\n");
             push(@implContent, "        auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>(\"$name\"), strlen(\"$name\"));\n");
             push(@implContent, "        VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);\n");
-            push(@implContent, "        JSObject::deleteProperty(this, globalObject(), propertyName);\n");
+            push(@implContent, "        DeletePropertySlot slot;\n");
+            push(@implContent, "        JSObject::deleteProperty(this, globalObject(), propertyName, slot);\n");
             push(@implContent, "    }\n");
             push(@implContent, "#endif\n") if $conditionalString;
         }
@@ -7512,7 +7513,8 @@ sub GenerateConstructorHelperMethods
         push(@$outputArray, "    if (!${runtimeEnableConditionalString}) {\n");
         push(@$outputArray, "        auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>(\"$name\"), strlen(\"$name\"));\n");
         push(@$outputArray, "        VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);\n");
-        push(@$outputArray, "        JSObject::deleteProperty(this, &globalObject, propertyName);\n");
+        push(@$outputArray, "        DeletePropertySlot slot;\n");
+        push(@$outputArray, "        JSObject::deleteProperty(this, &globalObject, propertyName, slot);\n");
         push(@$outputArray, "    }\n");
         push(@$outputArray, "#endif\n") if $conditionalString;
     }
index b5ea548..e633239 100644 (file)
@@ -137,7 +137,8 @@ void JSTestEnabledBySettingPrototype::finishCreation(VM& vm)
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("enabledBySettingOperation"), strlen("enabledBySettingOperation"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
 #endif
 #if ENABLE(TEST_FEATURE)
@@ -145,7 +146,8 @@ void JSTestEnabledBySettingPrototype::finishCreation(VM& vm)
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("enabledBySettingAttribute"), strlen("enabledBySettingAttribute"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
 #endif
     if (hasDisabledRuntimeProperties && structure()->isDictionary())
index 80faf35..ef66033 100644 (file)
@@ -108,7 +108,8 @@ void JSTestGenerateIsReachablePrototype::finishCreation(VM& vm)
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("aSecretAttribute"), strlen("aSecretAttribute"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (hasDisabledRuntimeProperties && structure()->isDictionary())
         flattenDictionaryObject(vm);
index bff4c3b..8783e15 100644 (file)
@@ -190,14 +190,14 @@ void JSTestNamedDeleterNoIdentifier::getOwnPropertyNames(JSObject* object, JSGlo
     JSObject::getOwnPropertyNames(object, lexicalGlobalObject, propertyNames, mode);
 }
 
-bool JSTestNamedDeleterNoIdentifier::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName)
+bool JSTestNamedDeleterNoIdentifier::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     auto& thisObject = *jsCast<JSTestNamedDeleterNoIdentifier*>(cell);
     auto& impl = thisObject.wrapped();
     if (isVisibleNamedProperty<OverrideBuiltins::No>(*lexicalGlobalObject, thisObject, propertyName)) {
         return impl.deleteNamedProperty(propertyNameToString(propertyName));
     }
-    return JSObject::deleteProperty(cell, lexicalGlobalObject, propertyName);
+    return JSObject::deleteProperty(cell, lexicalGlobalObject, propertyName, slot);
 }
 
 bool JSTestNamedDeleterNoIdentifier::deletePropertyByIndex(JSCell* cell, JSGlobalObject* lexicalGlobalObject, unsigned index)
index 0ea4bb1..138d4c1 100644 (file)
@@ -42,7 +42,7 @@ public:
     static bool getOwnPropertySlot(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PropertySlot&);
     static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::JSGlobalObject*, unsigned propertyName, JSC::PropertySlot&);
     static void getOwnPropertyNames(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());
-    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName);
+    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::DeletePropertySlot&);
     static bool deletePropertyByIndex(JSC::JSCell*, JSC::JSGlobalObject*, unsigned);
     static void destroy(JSC::JSCell*);
 
index 794d597..579f2a0 100644 (file)
@@ -190,7 +190,7 @@ void JSTestNamedDeleterThrowingException::getOwnPropertyNames(JSObject* object,
     JSObject::getOwnPropertyNames(object, lexicalGlobalObject, propertyNames, mode);
 }
 
-bool JSTestNamedDeleterThrowingException::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName)
+bool JSTestNamedDeleterThrowingException::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     auto& thisObject = *jsCast<JSTestNamedDeleterThrowingException*>(cell);
     auto& impl = thisObject.wrapped();
@@ -204,7 +204,7 @@ bool JSTestNamedDeleterThrowingException::deleteProperty(JSCell* cell, JSGlobalO
 
         return result.releaseReturnValue();
     }
-    return JSObject::deleteProperty(cell, lexicalGlobalObject, propertyName);
+    return JSObject::deleteProperty(cell, lexicalGlobalObject, propertyName, slot);
 }
 
 bool JSTestNamedDeleterThrowingException::deletePropertyByIndex(JSCell* cell, JSGlobalObject* lexicalGlobalObject, unsigned index)
index 791be18..055d3df 100644 (file)
@@ -42,7 +42,7 @@ public:
     static bool getOwnPropertySlot(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PropertySlot&);
     static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::JSGlobalObject*, unsigned propertyName, JSC::PropertySlot&);
     static void getOwnPropertyNames(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());
-    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName);
+    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::DeletePropertySlot&);
     static bool deletePropertyByIndex(JSC::JSCell*, JSC::JSGlobalObject*, unsigned);
     static void destroy(JSC::JSCell*);
 
index b3376e3..25023a3 100644 (file)
@@ -196,7 +196,7 @@ void JSTestNamedDeleterWithIdentifier::getOwnPropertyNames(JSObject* object, JSG
     JSObject::getOwnPropertyNames(object, lexicalGlobalObject, propertyNames, mode);
 }
 
-bool JSTestNamedDeleterWithIdentifier::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName)
+bool JSTestNamedDeleterWithIdentifier::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     auto& thisObject = *jsCast<JSTestNamedDeleterWithIdentifier*>(cell);
     auto& impl = thisObject.wrapped();
@@ -204,7 +204,7 @@ bool JSTestNamedDeleterWithIdentifier::deleteProperty(JSCell* cell, JSGlobalObje
         impl.namedDeleter(propertyNameToString(propertyName));
         return true;
     }
-    return JSObject::deleteProperty(cell, lexicalGlobalObject, propertyName);
+    return JSObject::deleteProperty(cell, lexicalGlobalObject, propertyName, slot);
 }
 
 bool JSTestNamedDeleterWithIdentifier::deletePropertyByIndex(JSCell* cell, JSGlobalObject* lexicalGlobalObject, unsigned index)
index 54e0254..a858a27 100644 (file)
@@ -42,7 +42,7 @@ public:
     static bool getOwnPropertySlot(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PropertySlot&);
     static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::JSGlobalObject*, unsigned propertyName, JSC::PropertySlot&);
     static void getOwnPropertyNames(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());
-    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName);
+    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::DeletePropertySlot&);
     static bool deletePropertyByIndex(JSC::JSCell*, JSC::JSGlobalObject*, unsigned);
     static void destroy(JSC::JSCell*);
 
index e8d9741..f6f366e 100644 (file)
@@ -209,7 +209,7 @@ void JSTestNamedDeleterWithIndexedGetter::getOwnPropertyNames(JSObject* object,
     JSObject::getOwnPropertyNames(object, lexicalGlobalObject, propertyNames, mode);
 }
 
-bool JSTestNamedDeleterWithIndexedGetter::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName)
+bool JSTestNamedDeleterWithIndexedGetter::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     auto& thisObject = *jsCast<JSTestNamedDeleterWithIndexedGetter*>(cell);
     auto& impl = thisObject.wrapped();
@@ -218,7 +218,7 @@ bool JSTestNamedDeleterWithIndexedGetter::deleteProperty(JSCell* cell, JSGlobalO
     if (isVisibleNamedProperty<OverrideBuiltins::No>(*lexicalGlobalObject, thisObject, propertyName)) {
         return impl.deleteNamedProperty(propertyNameToString(propertyName));
     }
-    return JSObject::deleteProperty(cell, lexicalGlobalObject, propertyName);
+    return JSObject::deleteProperty(cell, lexicalGlobalObject, propertyName, slot);
 }
 
 bool JSTestNamedDeleterWithIndexedGetter::deletePropertyByIndex(JSCell* cell, JSGlobalObject* lexicalGlobalObject, unsigned index)
index a9945ba..2fea8d9 100644 (file)
@@ -42,7 +42,7 @@ public:
     static bool getOwnPropertySlot(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PropertySlot&);
     static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::JSGlobalObject*, unsigned propertyName, JSC::PropertySlot&);
     static void getOwnPropertyNames(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());
-    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName);
+    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::DeletePropertySlot&);
     static bool deletePropertyByIndex(JSC::JSCell*, JSC::JSGlobalObject*, unsigned);
     static void destroy(JSC::JSCell*);
 
index 1100aa3..1fb3f1b 100644 (file)
@@ -157,45 +157,52 @@ void JSTestNodePrototype::finishCreation(VM& vm)
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("calculateSecretResult"), strlen("calculateSecretResult"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isSecureContext()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("getSecretBoolean"), strlen("getSecretBoolean"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
 #if ENABLE(TEST_FEATURE)
     if (!(jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isSecureContext() && RuntimeEnabledFeatures::sharedFeatures().testFeatureEnabled())) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("testFeatureGetSecretBoolean"), strlen("testFeatureGetSecretBoolean"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
 #endif
     if (!RuntimeEnabledFeatures::sharedFeatures().domIteratorEnabled()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("entries"), strlen("entries"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!RuntimeEnabledFeatures::sharedFeatures().domIteratorEnabled()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("keys"), strlen("keys"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!RuntimeEnabledFeatures::sharedFeatures().domIteratorEnabled()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("values"), strlen("values"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!RuntimeEnabledFeatures::sharedFeatures().domIteratorEnabled()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("forEach"), strlen("forEach"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (hasDisabledRuntimeProperties && structure()->isDictionary())
         flattenDictionaryObject(vm);
index 4c10710..f568432 100644 (file)
@@ -1984,14 +1984,16 @@ template<> void JSTestObjConstructor::initializeProperties(VM& vm, JSDOMGlobalOb
     if (!RuntimeEnabledFeatures::sharedFeatures().testFeatureEnabled()) {
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("enabledAtRuntimeAttributeStatic"), strlen("enabledAtRuntimeAttributeStatic"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, &globalObject, propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, &globalObject, propertyName, slot);
     }
 #endif
 #if ENABLE(TEST_FEATURE)
     if (!RuntimeEnabledFeatures::sharedFeatures().testFeatureEnabled()) {
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("enabledAtRuntimeOperationStatic"), strlen("enabledAtRuntimeOperationStatic"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, &globalObject, propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, &globalObject, propertyName, slot);
     }
 #endif
 }
@@ -2347,90 +2349,104 @@ void JSTestObjPrototype::finishCreation(VM& vm)
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("enabledAtRuntimeOperation"), strlen("enabledAtRuntimeOperation"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
 #endif
     if (!(worldForDOMObject(*this).someWorld() && RuntimeEnabledFeatures::sharedFeatures().testFeatureEnabled())) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("enabledInSpecificWorldWhenRuntimeFeatureEnabled"), strlen("enabledInSpecificWorldWhenRuntimeFeatureEnabled"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!worldForDOMObject(*this).someWorld()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("worldSpecificMethod"), strlen("worldSpecificMethod"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isSecureContext()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("calculateSecretResult"), strlen("calculateSecretResult"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isSecureContext()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("getSecretBoolean"), strlen("getSecretBoolean"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
 #if ENABLE(TEST_FEATURE)
     if (!(jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isSecureContext() && RuntimeEnabledFeatures::sharedFeatures().testFeatureEnabled())) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("testFeatureGetSecretBoolean"), strlen("testFeatureGetSecretBoolean"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
 #endif
     if (!jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isDocument()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("conditionallyExposedToWindowFunction"), strlen("conditionallyExposedToWindowFunction"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isWorkerGlobalScope()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("conditionallyExposedToWorkerFunction"), strlen("conditionallyExposedToWorkerFunction"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!(jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isSecureContext()|| jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->allowsMediaDevices())) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("mediaDevices"), strlen("mediaDevices"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!(jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isSecureContext()|| jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->hasServiceWorkerScheme())) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("serviceWorkers"), strlen("serviceWorkers"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
 #if ENABLE(TEST_FEATURE)
     if (!(RuntimeEnabledFeatures::sharedFeatures().testFeatureEnabled() && RuntimeEnabledFeatures::sharedFeatures().testFeature1Enabled())) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("enabledAtRuntimeAttribute"), strlen("enabledAtRuntimeAttribute"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
 #endif
     if (!RuntimeEnabledFeatures::sharedFeatures().testFeatureEnabled()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("runtimeConditionallyReadWriteAttribute"), strlen("runtimeConditionallyReadWriteAttribute"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isDocument()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("conditionallyExposedToWindowAttribute"), strlen("conditionallyExposedToWindowAttribute"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     if (!jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isWorkerGlobalScope()) {
         hasDisabledRuntimeProperties = true;
         auto propertyName = Identifier::fromString(vm, reinterpret_cast<const LChar*>("conditionallyExposedToWorkerAttribute"), strlen("conditionallyExposedToWorkerAttribute"));
         VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
-        JSObject::deleteProperty(this, globalObject(), propertyName);
+        DeletePropertySlot slot;
+        JSObject::deleteProperty(this, globalObject(), propertyName, slot);
     }
     // Adding back attribute, but as readonly, after removing the read-write variant above. 
     if (!RuntimeEnabledFeatures::sharedFeatures().testFeatureEnabled())
index feebdef..a417f5c 100644 (file)
@@ -392,7 +392,7 @@ bool _NPN_RemoveProperty(NPP, NPObject* o, NPIdentifier propertyName)
         }
 
         if (i->isString())
-            obj->imp->methodTable(vm)->deleteProperty(obj->imp, lexicalGlobalObject, identifierFromNPIdentifier(lexicalGlobalObject, i->string()));
+            JSCell::deleteProperty(obj->imp, lexicalGlobalObject, identifierFromNPIdentifier(lexicalGlobalObject, i->string()));
         else
             obj->imp->methodTable(vm)->deletePropertyByIndex(obj->imp, lexicalGlobalObject, i->number());
 
index 22f0b8d..de3a43d 100644 (file)
@@ -458,7 +458,7 @@ static void getListFromNSArray(JSC::JSGlobalObject* lexicalGlobalObject, NSArray
     auto scope = DECLARE_CATCH_SCOPE(vm);
     JSC::JSGlobalObject* lexicalGlobalObject = globalObject;
 
-    [self _imp]->methodTable(vm)->deleteProperty([self _imp], lexicalGlobalObject, Identifier::fromString(vm, String(key)));
+    JSC::JSCell::deleteProperty([self _imp], lexicalGlobalObject, Identifier::fromString(vm, String(key)));
 
     if (UNLIKELY(scope.exception())) {
         addExceptionToConsole(lexicalGlobalObject);
index 5ed21f1..6229636 100644 (file)
@@ -133,7 +133,7 @@ private:
     static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     static CallType getCallData(JSCell*, CallData&);
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
 
     bool toBoolean(JSGlobalObject*) const; // FIXME: Currently this is broken because none of the superclasses are marked virtual. We need to solve this in the longer term.
index 19ed19c..6e877d2 100644 (file)
@@ -290,7 +290,7 @@ CallType ObjcFallbackObjectImp::getCallData(JSCell* cell, CallData& callData)
     return CallType::Host;
 }
 
-bool ObjcFallbackObjectImp::deleteProperty(JSCell*, JSGlobalObject*, PropertyName)
+bool ObjcFallbackObjectImp::deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&)
 {
     return false;
 }
index 4d297c7..ec3588f 100644 (file)
@@ -149,7 +149,7 @@ bool RuntimeArray::putByIndex(JSCell* cell, JSGlobalObject* lexicalGlobalObject,
     return thisObject->getConcreteArray()->setValueAt(lexicalGlobalObject, index, value);
 }
 
-bool RuntimeArray::deleteProperty(JSCell*, JSGlobalObject*, PropertyName)
+bool RuntimeArray::deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&)
 {
     return false;
 }
index fcf5e33..29812a6 100644 (file)
@@ -65,7 +65,7 @@ public:
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     static bool putByIndex(JSCell*, JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
     
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned propertyName);
     
     unsigned getLength() const { return m_array->getLength(); }
index a036b66..9d5d60d 100644 (file)
@@ -200,7 +200,7 @@ bool RuntimeObject::put(JSCell* cell, JSGlobalObject* lexicalGlobalObject, Prope
     return result;
 }
 
-bool RuntimeObject::deleteProperty(JSCell*, JSGlobalObject*, PropertyName)
+bool RuntimeObject::deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&)
 {
     // Can never remove a property of a RuntimeObject.
     return false;
index 6cbf7bf..3c10d8b 100644 (file)
@@ -57,7 +57,7 @@ public:
 
     static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
-    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
+    static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
     static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
     static CallType getCallData(JSCell*, CallData&);
     static ConstructType getConstructData(JSCell*, ConstructData&);
index 0cfbb01..ad4e6c0 100644 (file)
@@ -1,3 +1,16 @@
+2020-02-25  Justin Michaud  <justin_michaud@apple.com>
+
+        Inline Cache delete by id/val
+        https://bugs.webkit.org/show_bug.cgi?id=207522
+
+        Reviewed by Keith Miller and Filip Pizlo.
+
+        * WebProcess/Plugins/Netscape/JSNPObject.cpp:
+        (WebKit::JSNPObject::deleteProperty):
+        * WebProcess/Plugins/Netscape/JSNPObject.h:
+        * WebProcess/Plugins/Netscape/NPJSObject.cpp:
+        (WebKit::NPJSObject::removeProperty):
+
 2020-02-25  Ben Nham  <nham@apple.com>
 
         Remove render update throttling
index 2efb225..05d1292 100644 (file)
@@ -361,7 +361,7 @@ bool JSNPObject::put(JSCell* cell, JSGlobalObject* lexicalGlobalObject, Property
     return result;
 }
 
-bool JSNPObject::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName)
+bool JSNPObject::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, DeletePropertySlot& slot)
 {
     return jsCast<JSNPObject*>(cell)->deleteProperty(lexicalGlobalObject, npIdentifierFromIdentifier(propertyName));
 }
index 8558894..4803c0b 100644 (file)
@@ -95,7 +95,7 @@ private:
     static bool getOwnPropertySlot(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PropertySlot&);
     static bool put(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);
 
-    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName);
+    static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::DeletePropertySlot&);
     static bool deletePropertyByIndex(JSC::JSCell*, JSC::JSGlobalObject*, unsigned propertyName);
 
     bool deleteProperty(JSC::JSGlobalObject*, NPIdentifier propertyName);
index 36f28ee..a7fb6b5 100644 (file)
@@ -229,8 +229,8 @@ bool NPJSObject::removeProperty(NPIdentifier propertyName)
             scope.clearException();
             return false;
         }
-        
-        m_jsObject->methodTable(vm)->deleteProperty(m_jsObject.get(), lexicalGlobalObject, identifier);
+
+        JSCell::deleteProperty(m_jsObject.get(), lexicalGlobalObject, identifier);
     } else {
         if (!m_jsObject->hasProperty(lexicalGlobalObject, identifierRep->number())) {
             scope.clearException();
index 36c8f74..1e15530 100644 (file)
@@ -1,3 +1,13 @@
+2020-02-25  Justin Michaud  <justin_michaud@apple.com>
+
+        Inline Cache delete by id/val
+        https://bugs.webkit.org/show_bug.cgi?id=207522
+
+        Reviewed by Keith Miller and Filip Pizlo.
+
+        * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
+        (WebKit::NetscapePluginInstanceProxy::removeProperty):
+
 2020-02-25  Antti Koivisto  <antti@apple.com>
 
         Remove throttling code from RenderLayerCompositor
index 3032afa..dc62d55 100644 (file)
@@ -1141,8 +1141,8 @@ bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, const Identi
         scope.clearException();
         return false;
     }
-    
-    object->methodTable(vm)->deleteProperty(object, lexicalGlobalObject, propertyName);
+
+    JSCell::deleteProperty(object, lexicalGlobalObject, propertyName);
     scope.clearException();
     return true;
 }