From 1f8a9f66cf95c3ea5a8819c87157ac00d4b1ef0c Mon Sep 17 00:00:00 2001 From: Filip Pizlo Date: Thu, 21 Mar 2013 18:13:57 +0100 Subject: Named lookups on HTML documents produce inconsistent results in JavaScriptCore bindings https://bugs.webkit.org/show_bug.cgi?id=104623 Reviewed by Geoffrey Garen. Source/JavaScriptCore: Add the notion of objects that HasImpureGetOwnPropertySlot, and use that to inhibit prototype chain caching in some cases. This appears to be perf-neutral on benchmarks that we track. * dfg/DFGRepatch.cpp: (JSC::DFG::tryCacheGetByID): (JSC::DFG::tryBuildGetByIDProtoList): * jit/JITStubs.cpp: (JSC::JITThunks::tryCacheGetByID): (JSC::DEFINE_STUB_FUNCTION): * runtime/JSTypeInfo.h: (JSC): (JSC::TypeInfo::hasImpureGetOwnPropertySlot): * runtime/Operations.h: (JSC::normalizePrototypeChainForChainAccess): Source/WebCore: All DOM objects that have named getters or directly override getOwnPropertySlot are now marked as HasImpureGetOwnPropertySlot. Tests: fast/js/prototype-chain-caching-with-impure-get-own-property-slot-traps fast/js/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps * bindings/scripts/CodeGeneratorJS.pm: (GenerateHeader): LayoutTests: * fast/js/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-expected.txt: Added. * fast/js/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps.html: Added. * fast/js/prototype-chain-caching-with-impure-get-own-property-slot-traps-expected.txt: Added. * fast/js/prototype-chain-caching-with-impure-get-own-property-slot-traps.html: Added. * fast/js/script-tests/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps.js: Added. (f): * fast/js/script-tests/prototype-chain-caching-with-impure-get-own-property-slot-traps.js: Added. (f): Change-Id: Ie17e39f2b8139778455e28aca9428698f4dd362f git-svn-id: http://svn.webkit.org/repository/webkit/trunk@137700 268f45cc-cd09-0410-ab3c-d52691b4dbfc Reviewed-by: Jocelyn Turcotte --- Source/JavaScriptCore/jit/JITStubs.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'Source/JavaScriptCore/jit/JITStubs.cpp') diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index f47ac08ef..fbef1fcb9 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -908,6 +908,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co // Uncacheable: give up. if (!slot.isCacheable()) { + stubInfo->accessType = access_get_by_id_generic; ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -916,6 +917,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co Structure* structure = baseCell->structure(); if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) { + stubInfo->accessType = access_get_by_id_generic; ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -934,6 +936,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co } if (structure->isDictionary()) { + stubInfo->accessType = access_get_by_id_generic; ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -943,6 +946,12 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co JSObject* slotBaseObject = asObject(slot.slotBase()); size_t offset = slot.cachedOffset(); + + if (structure->typeInfo().hasImpureGetOwnPropertySlot()) { + stubInfo->accessType = access_get_by_id_generic; + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); + return; + } // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. @@ -960,9 +969,10 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co } PropertyOffset offset = slot.cachedOffset(); - size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset); + size_t count = normalizePrototypeChainForChainAccess(callFrame, baseValue, slot.slotBase(), propertyName, offset); if (count == InvalidPrototypeChain) { stubInfo->accessType = access_get_by_id_generic; + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -1689,6 +1699,12 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); else if (slot.slotBase() == baseValue.asCell()->structure()->prototypeForLookup(callFrame)) { ASSERT(!baseValue.asCell()->structure()->isDictionary()); + + if (baseValue.asCell()->structure()->typeInfo().hasImpureGetOwnPropertySlot()) { + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); + return JSValue::encode(result); + } + // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. if (slotBaseObject->structure()->isDictionary()) { @@ -1705,7 +1721,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); } } else { - size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset); + size_t count = normalizePrototypeChainForChainAccess(callFrame, baseValue, slot.slotBase(), propertyName, offset); if (count == InvalidPrototypeChain) { ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); return JSValue::encode(result); -- cgit v1.2.1