diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/bytecode/StructureStubInfo.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/bytecode/StructureStubInfo.h')
-rw-r--r-- | Source/JavaScriptCore/bytecode/StructureStubInfo.h | 378 |
1 files changed, 152 insertions, 226 deletions
diff --git a/Source/JavaScriptCore/bytecode/StructureStubInfo.h b/Source/JavaScriptCore/bytecode/StructureStubInfo.h index 5463f3e95..b091e2157 100644 --- a/Source/JavaScriptCore/bytecode/StructureStubInfo.h +++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2008-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,266 +23,194 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef StructureStubInfo_h -#define StructureStubInfo_h - -#include <wtf/Platform.h> +#pragma once +#include "CodeBlock.h" #include "CodeOrigin.h" #include "Instruction.h" #include "JITStubRoutine.h" #include "MacroAssembler.h" -#include "Opcode.h" -#include "PolymorphicAccessStructureList.h" +#include "ObjectPropertyConditionSet.h" +#include "Options.h" #include "RegisterSet.h" #include "Structure.h" +#include "StructureSet.h" #include "StructureStubClearingWatchpoint.h" -#include <wtf/OwnPtr.h> namespace JSC { #if ENABLE(JIT) -class PolymorphicPutByIdList; +class AccessCase; +class AccessGenerationResult; +class PolymorphicAccess; -enum AccessType { - access_get_by_id_self, - access_get_by_id_proto, - access_get_by_id_chain, - access_get_by_id_self_list, - access_get_by_id_proto_list, - access_put_by_id_transition_normal, - access_put_by_id_transition_direct, - access_put_by_id_replace, - access_put_by_id_list, - access_unset, - access_get_by_id_generic, - access_put_by_id_generic, - access_get_array_length, - access_get_string_length, - access_in_list +enum class AccessType : int8_t { + Get, + TryGet, + Put, + In }; -inline bool isGetByIdAccess(AccessType accessType) -{ - switch (accessType) { - case access_get_by_id_self: - case access_get_by_id_proto: - case access_get_by_id_chain: - case access_get_by_id_self_list: - case access_get_by_id_proto_list: - case access_get_by_id_generic: - case access_get_array_length: - case access_get_string_length: - return true; - default: - return false; - } -} - -inline bool isPutByIdAccess(AccessType accessType) -{ - switch (accessType) { - case access_put_by_id_transition_normal: - case access_put_by_id_transition_direct: - case access_put_by_id_replace: - case access_put_by_id_list: - case access_put_by_id_generic: - return true; - default: - return false; - } -} - -inline bool isInAccess(AccessType accessType) -{ - switch (accessType) { - case access_in_list: - return true; - default: - return false; - } -} - -struct StructureStubInfo { - StructureStubInfo() - : accessType(access_unset) - , seen(false) - , resetByGC(false) - { - } - - void initGetByIdSelf(VM& vm, JSCell* owner, Structure* baseObjectStructure) - { - accessType = access_get_by_id_self; - - u.getByIdSelf.baseObjectStructure.set(vm, owner, baseObjectStructure); - } - - void initGetByIdChain(VM& vm, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain, unsigned count, bool isDirect) - { - accessType = access_get_by_id_chain; - - u.getByIdChain.baseObjectStructure.set(vm, owner, baseObjectStructure); - u.getByIdChain.chain.set(vm, owner, chain); - u.getByIdChain.count = count; - u.getByIdChain.isDirect = isDirect; - } - - void initGetByIdSelfList(PolymorphicAccessStructureList* structureList, int listSize, bool didSelfPatching = false) - { - accessType = access_get_by_id_self_list; - - u.getByIdSelfList.structureList = structureList; - u.getByIdSelfList.listSize = listSize; - u.getByIdSelfList.didSelfPatching = didSelfPatching; - } +enum class CacheType : int8_t { + Unset, + GetByIdSelf, + PutByIdReplace, + Stub, + ArrayLength +}; - void initGetByIdProtoList(PolymorphicAccessStructureList* structureList, int listSize) - { - accessType = access_get_by_id_proto_list; +class StructureStubInfo { + WTF_MAKE_NONCOPYABLE(StructureStubInfo); + WTF_MAKE_FAST_ALLOCATED; +public: + StructureStubInfo(AccessType); + ~StructureStubInfo(); - u.getByIdProtoList.structureList = structureList; - u.getByIdProtoList.listSize = listSize; - } + void initGetByIdSelf(CodeBlock*, Structure* baseObjectStructure, PropertyOffset); + void initArrayLength(); + void initPutByIdReplace(CodeBlock*, Structure* baseObjectStructure, PropertyOffset); + void initStub(CodeBlock*, std::unique_ptr<PolymorphicAccess>); - // PutById* + AccessGenerationResult addAccessCase(CodeBlock*, const Identifier&, std::unique_ptr<AccessCase>); - void initPutByIdTransition(VM& vm, JSCell* owner, Structure* previousStructure, Structure* structure, StructureChain* chain, bool isDirect) - { - if (isDirect) - accessType = access_put_by_id_transition_direct; - else - accessType = access_put_by_id_transition_normal; + void reset(CodeBlock*); - u.putByIdTransition.previousStructure.set(vm, owner, previousStructure); - u.putByIdTransition.structure.set(vm, owner, structure); - u.putByIdTransition.chain.set(vm, owner, chain); - } + void deref(); + void aboutToDie(); - void initPutByIdReplace(VM& vm, JSCell* owner, Structure* baseObjectStructure) - { - accessType = access_put_by_id_replace; + // Check if the stub has weak references that are dead. If it does, then it resets itself, + // either entirely or just enough to ensure that those dead pointers don't get used anymore. + void visitWeakReferences(CodeBlock*); - u.putByIdReplace.baseObjectStructure.set(vm, owner, baseObjectStructure); - } + // This returns true if it has marked everything that it will ever mark. + bool propagateTransitions(SlotVisitor&); - void initPutByIdList(PolymorphicPutByIdList* list) - { - accessType = access_put_by_id_list; - u.putByIdList.list = list; - } - - void initInList(PolymorphicAccessStructureList* list, int listSize) + ALWAYS_INLINE bool considerCaching(CodeBlock* codeBlock, Structure* structure) { - accessType = access_in_list; - u.inList.structureList = list; - u.inList.listSize = listSize; - } + // We never cache non-cells. + if (!structure) + return false; - void reset() - { - deref(); - accessType = access_unset; - stubRoutine.clear(); - watchpoints.clear(); - } - - void deref(); - - bool visitWeakReferences(); + // This method is called from the Optimize variants of IC slow paths. The first part of this + // method tries to determine if the Optimize variant should really behave like the + // non-Optimize variant and leave the IC untouched. + // + // If we determine that we should do something to the IC then the next order of business is + // to determine if this Structure would impact the IC at all. We know that it won't, if we + // have already buffered something on its behalf. That's what the bufferedStructures set is + // for. - bool seenOnce() - { - return seen; + everConsidered = true; + if (!countdown) { + // Check if we have been doing repatching too frequently. If so, then we should cool off + // for a while. + WTF::incrementWithSaturation(repatchCount); + if (repatchCount > Options::repatchCountForCoolDown()) { + // We've been repatching too much, so don't do it now. + repatchCount = 0; + // The amount of time we require for cool-down depends on the number of times we've + // had to cool down in the past. The relationship is exponential. The max value we + // allow here is 2^256 - 2, since the slow paths may increment the count to indicate + // that they'd like to temporarily skip patching just this once. + countdown = WTF::leftShiftWithSaturation( + static_cast<uint8_t>(Options::initialCoolDownCount()), + numberOfCoolDowns, + static_cast<uint8_t>(std::numeric_limits<uint8_t>::max() - 1)); + WTF::incrementWithSaturation(numberOfCoolDowns); + + // We may still have had something buffered. Trigger generation now. + bufferingCountdown = 0; + return true; + } + + // We don't want to return false due to buffering indefinitely. + if (!bufferingCountdown) { + // Note that when this returns true, it's possible that we will not even get an + // AccessCase because this may cause Repatch.cpp to simply do an in-place + // repatching. + return true; + } + + bufferingCountdown--; + + // Now protect the IC buffering. We want to proceed only if this is a structure that + // we don't already have a case buffered for. Note that if this returns true but the + // bufferingCountdown is not zero then we will buffer the access case for later without + // immediately generating code for it. + bool isNewlyAdded = bufferedStructures.add(structure); + if (isNewlyAdded) { + VM& vm = *codeBlock->vm(); + vm.heap.writeBarrier(codeBlock); + } + return isNewlyAdded; + } + countdown--; + return false; } - void setSeen() - { - seen = true; - } - - StructureStubClearingWatchpoint* addWatchpoint(CodeBlock* codeBlock) - { - return WatchpointsOnStructureStubInfo::ensureReferenceAndAddWatchpoint( - watchpoints, codeBlock, this); - } - - int8_t accessType; - bool seen : 1; - bool resetByGC : 1; + bool containsPC(void* pc) const; CodeOrigin codeOrigin; + CallSiteIndex callSiteIndex; + union { + struct { + WriteBarrierBase<Structure> baseObjectStructure; + PropertyOffset offset; + } byIdSelf; + PolymorphicAccess* stub; + } u; + + // Represents those structures that already have buffered AccessCases in the PolymorphicAccess. + // Note that it's always safe to clear this. If we clear it prematurely, then if we see the same + // structure again during this buffering countdown, we will create an AccessCase object for it. + // That's not so bad - we'll get rid of the redundant ones once we regenerate. + StructureSet bufferedStructures; + struct { - int8_t registersFlushed; - int8_t callFrameRegister; + CodeLocationLabel start; // This is either the start of the inline IC for *byId caches, or the location of patchable jump for 'in' caches. + RegisterSet usedRegisters; + uint32_t inlineSize; + int32_t deltaFromStartToSlowPathCallLocation; + int32_t deltaFromStartToSlowPathStart; + int8_t baseGPR; + int8_t valueGPR; #if USE(JSVALUE32_64) int8_t valueTagGPR; -#endif - int8_t valueGPR; - RegisterSet usedRegisters; - int32_t deltaCallToDone; - int32_t deltaCallToStorageLoad; - int32_t deltaCallToJump; - int32_t deltaCallToSlowCase; - int32_t deltaCheckImmToCall; -#if USE(JSVALUE64) - int32_t deltaCallToLoadOrStore; -#else - int32_t deltaCallToTagLoadOrStore; - int32_t deltaCallToPayloadLoadOrStore; + int8_t baseTagGPR; #endif } patch; - union { - struct { - // It would be unwise to put anything here, as it will surely be overwritten. - } unset; - struct { - WriteBarrierBase<Structure> baseObjectStructure; - } getByIdSelf; - struct { - WriteBarrierBase<Structure> baseObjectStructure; - WriteBarrierBase<Structure> prototypeStructure; - bool isDirect; - } getByIdProto; - struct { - WriteBarrierBase<Structure> baseObjectStructure; - WriteBarrierBase<StructureChain> chain; - unsigned count : 31; - bool isDirect : 1; - } getByIdChain; - struct { - PolymorphicAccessStructureList* structureList; - int listSize : 31; - bool didSelfPatching : 1; - } getByIdSelfList; - struct { - PolymorphicAccessStructureList* structureList; - int listSize; - } getByIdProtoList; - struct { - WriteBarrierBase<Structure> previousStructure; - WriteBarrierBase<Structure> structure; - WriteBarrierBase<StructureChain> chain; - } putByIdTransition; - struct { - WriteBarrierBase<Structure> baseObjectStructure; - } putByIdReplace; - struct { - PolymorphicPutByIdList* list; - } putByIdList; - struct { - PolymorphicAccessStructureList* structureList; - int listSize; - } inList; - } u; + CodeLocationCall slowPathCallLocation() { return patch.start.callAtOffset(patch.deltaFromStartToSlowPathCallLocation); } + CodeLocationLabel doneLocation() { return patch.start.labelAtOffset(patch.inlineSize); } + CodeLocationLabel slowPathStartLocation() { return patch.start.labelAtOffset(patch.deltaFromStartToSlowPathStart); } + CodeLocationJump patchableJumpForIn() + { + ASSERT(accessType == AccessType::In); + return patch.start.jumpAtOffset(0); + } + + JSValueRegs valueRegs() const + { + return JSValueRegs( +#if USE(JSVALUE32_64) + static_cast<GPRReg>(patch.valueTagGPR), +#endif + static_cast<GPRReg>(patch.valueGPR)); + } + - RefPtr<JITStubRoutine> stubRoutine; - CodeLocationCall callReturnLocation; - RefPtr<WatchpointsOnStructureStubInfo> watchpoints; + AccessType accessType; + CacheType cacheType; + uint8_t countdown; // We repatch only when this is zero. If not zero, we decrement. + uint8_t repatchCount; + uint8_t numberOfCoolDowns; + uint8_t bufferingCountdown; + bool resetByGC : 1; + bool tookSlowPath : 1; + bool everConsidered : 1; }; inline CodeOrigin getStructureStubInfoCodeOrigin(StructureStubInfo& structureStubInfo) @@ -290,14 +218,12 @@ inline CodeOrigin getStructureStubInfoCodeOrigin(StructureStubInfo& structureStu return structureStubInfo.codeOrigin; } -typedef HashMap<CodeOrigin, StructureStubInfo*> StubInfoMap; - #else -typedef HashMap<int, void*> StubInfoMap; +class StructureStubInfo; #endif // ENABLE(JIT) -} // namespace JSC +typedef HashMap<CodeOrigin, StructureStubInfo*, CodeOriginApproximateHash> StubInfoMap; -#endif // StructureStubInfo_h +} // namespace JSC |