diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
commit | a4e969f4965059196ca948db781e52f7cfebf19e (patch) | |
tree | 6ca352808c8fdc52006a0f33f6ae3c593b23867d /Source/JavaScriptCore/bytecode/PolymorphicAccess.h | |
parent | 41386e9cb918eed93b3f13648cbef387e371e451 (diff) | |
download | WebKitGtk-tarball-a4e969f4965059196ca948db781e52f7cfebf19e.tar.gz |
webkitgtk-2.12.3webkitgtk-2.12.3
Diffstat (limited to 'Source/JavaScriptCore/bytecode/PolymorphicAccess.h')
-rw-r--r-- | Source/JavaScriptCore/bytecode/PolymorphicAccess.h | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/bytecode/PolymorphicAccess.h b/Source/JavaScriptCore/bytecode/PolymorphicAccess.h new file mode 100644 index 000000000..bb1ea0a4e --- /dev/null +++ b/Source/JavaScriptCore/bytecode/PolymorphicAccess.h @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2014, 2015 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. + */ + +#ifndef PolymorphicAccess_h +#define PolymorphicAccess_h + +#if ENABLE(JIT) + +#include "CodeOrigin.h" +#include "JSFunctionInlines.h" +#include "MacroAssembler.h" +#include "ObjectPropertyConditionSet.h" +#include "Opcode.h" +#include "ScratchRegisterAllocator.h" +#include "Structure.h" +#include <wtf/Vector.h> + +namespace JSC { + +class CodeBlock; +class PolymorphicAccess; +class StructureStubInfo; +class WatchpointsOnStructureStubInfo; +class ScratchRegisterAllocator; + +struct AccessGenerationState; + +class AccessCase { + WTF_MAKE_NONCOPYABLE(AccessCase); + WTF_MAKE_FAST_ALLOCATED; +public: + enum AccessType { + Load, + Transition, + Replace, + Miss, + Getter, + Setter, + CustomValueGetter, + CustomAccessorGetter, + CustomValueSetter, + CustomAccessorSetter, + IntrinsicGetter, + InHit, + InMiss, + ArrayLength, + StringLength + }; + + static bool isGet(AccessType type) + { + switch (type) { + case Transition: + case Replace: + case Setter: + case CustomValueSetter: + case CustomAccessorSetter: + case InHit: + case InMiss: + return false; + case Load: + case Miss: + case Getter: + case CustomValueGetter: + case CustomAccessorGetter: + case IntrinsicGetter: + case ArrayLength: + case StringLength: + return true; + } + } + + static bool isPut(AccessType type) + { + switch (type) { + case Load: + case Miss: + case Getter: + case CustomValueGetter: + case CustomAccessorGetter: + case IntrinsicGetter: + case InHit: + case InMiss: + case ArrayLength: + case StringLength: + return false; + case Transition: + case Replace: + case Setter: + case CustomValueSetter: + case CustomAccessorSetter: + return true; + } + } + + static bool isIn(AccessType type) + { + switch (type) { + case Load: + case Miss: + case Getter: + case CustomValueGetter: + case CustomAccessorGetter: + case IntrinsicGetter: + case Transition: + case Replace: + case Setter: + case CustomValueSetter: + case CustomAccessorSetter: + case ArrayLength: + case StringLength: + return false; + case InHit: + case InMiss: + return true; + } + } + + static std::unique_ptr<AccessCase> get( + VM&, JSCell* owner, AccessType, PropertyOffset, Structure*, + const ObjectPropertyConditionSet& = ObjectPropertyConditionSet(), + bool viaProxy = false, + WatchpointSet* additionalSet = nullptr, + PropertySlot::GetValueFunc = nullptr, + JSObject* customSlotBase = nullptr); + + static std::unique_ptr<AccessCase> replace(VM&, JSCell* owner, Structure*, PropertyOffset); + + static std::unique_ptr<AccessCase> transition( + VM&, JSCell* owner, Structure* oldStructure, Structure* newStructure, PropertyOffset, + const ObjectPropertyConditionSet& = ObjectPropertyConditionSet()); + + static std::unique_ptr<AccessCase> setter( + VM&, JSCell* owner, AccessType, Structure*, PropertyOffset, + const ObjectPropertyConditionSet&, PutPropertySlot::PutValueFunc = nullptr, + JSObject* customSlotBase = nullptr); + + static std::unique_ptr<AccessCase> in( + VM&, JSCell* owner, AccessType, Structure*, + const ObjectPropertyConditionSet& = ObjectPropertyConditionSet()); + + static std::unique_ptr<AccessCase> getLength(VM&, JSCell* owner, AccessType); + static std::unique_ptr<AccessCase> getIntrinsic(VM&, JSCell* owner, JSFunction* intrinsic, PropertyOffset, Structure*, const ObjectPropertyConditionSet&); + + static std::unique_ptr<AccessCase> fromStructureStubInfo(VM&, JSCell* owner, StructureStubInfo&); + + ~AccessCase(); + + std::unique_ptr<AccessCase> clone() const; + + AccessType type() const { return m_type; } + PropertyOffset offset() const { return m_offset; } + bool viaProxy() const { return m_rareData ? m_rareData->viaProxy : false; } + + Structure* structure() const + { + if (m_type == Transition) + return m_structure->previousID(); + return m_structure.get(); + } + bool guardedByStructureCheck() const; + + Structure* newStructure() const + { + ASSERT(m_type == Transition); + return m_structure.get(); + } + + ObjectPropertyConditionSet conditionSet() const { return m_conditionSet; } + JSFunction* intrinsicFunction() const + { + ASSERT(type() == IntrinsicGetter && m_rareData); + return m_rareData->intrinsicFunction.get(); + } + Intrinsic intrinsic() const + { + return intrinsicFunction()->intrinsic(); + } + + WatchpointSet* additionalSet() const + { + return m_rareData ? m_rareData->additionalSet.get() : nullptr; + } + + JSObject* customSlotBase() const + { + return m_rareData ? m_rareData->customSlotBase.get() : nullptr; + } + + JSObject* alternateBase() const; + + bool doesCalls() const + { + switch (type()) { + case Getter: + case Setter: + case CustomValueGetter: + case CustomAccessorGetter: + case CustomValueSetter: + case CustomAccessorSetter: + return true; + default: + return false; + } + } + + bool isGetter() const + { + switch (type()) { + case Getter: + case CustomValueGetter: + case CustomAccessorGetter: + return true; + default: + return false; + } + } + + CallLinkInfo* callLinkInfo() const + { + if (!m_rareData) + return nullptr; + return m_rareData->callLinkInfo.get(); + } + + // Is it still possible for this case to ever be taken? + bool couldStillSucceed() const; + + static bool canEmitIntrinsicGetter(JSFunction*, Structure*); + + // If this method returns true, then it's a good idea to remove 'other' from the access once 'this' + // is added. This method assumes that in case of contradictions, 'this' represents a newer, and so + // more useful, truth. This method can be conservative; it will return false when it doubt. + bool canReplace(const AccessCase& other); + + void dump(PrintStream& out) const; + +private: + friend class CodeBlock; + friend class PolymorphicAccess; + + AccessCase(); + + bool visitWeak(VM&) const; + + // Fall through on success. Two kinds of failures are supported: fall-through, which means that we + // should try a different case; and failure, which means that this was the right case but it needs + // help from the slow path. + void generateWithGuard(AccessGenerationState&, MacroAssembler::JumpList& fallThrough); + + // Fall through on success, add a jump to the failure list on failure. + void generate(AccessGenerationState&); + void emitIntrinsicGetter(AccessGenerationState&); + + AccessType m_type { Load }; + PropertyOffset m_offset { invalidOffset }; + + // Usually this is the structure that we expect the base object to have. But, this is the *new* + // structure for a transition and we rely on the fact that it has a strong reference to the old + // structure. For proxies, this is the structure of the object behind the proxy. + WriteBarrier<Structure> m_structure; + + ObjectPropertyConditionSet m_conditionSet; + + class RareData { + WTF_MAKE_FAST_ALLOCATED; + public: + RareData() + : viaProxy(false) + { + customAccessor.opaque = nullptr; + } + + bool viaProxy; + RefPtr<WatchpointSet> additionalSet; + std::unique_ptr<CallLinkInfo> callLinkInfo; + union { + PropertySlot::GetValueFunc getter; + PutPropertySlot::PutValueFunc setter; + void* opaque; + } customAccessor; + WriteBarrier<JSObject> customSlotBase; + WriteBarrier<JSFunction> intrinsicFunction; + }; + + std::unique_ptr<RareData> m_rareData; +}; + +class PolymorphicAccess { + WTF_MAKE_NONCOPYABLE(PolymorphicAccess); + WTF_MAKE_FAST_ALLOCATED; +public: + PolymorphicAccess(); + ~PolymorphicAccess(); + + // This may return null, in which case the old stub routine is left intact. You are required to + // pass a vector of non-null access cases. This will prune the access cases by rejecting any case + // in the list that is subsumed by a later case in the list. + MacroAssemblerCodePtr regenerateWithCases( + VM&, CodeBlock*, StructureStubInfo&, const Identifier&, Vector<std::unique_ptr<AccessCase>>); + + MacroAssemblerCodePtr regenerateWithCase( + VM&, CodeBlock*, StructureStubInfo&, const Identifier&, std::unique_ptr<AccessCase>); + + bool isEmpty() const { return m_list.isEmpty(); } + unsigned size() const { return m_list.size(); } + const AccessCase& at(unsigned i) const { return *m_list[i]; } + const AccessCase& operator[](unsigned i) const { return *m_list[i]; } + + // If this returns false then we are requesting a reset of the owning StructureStubInfo. + bool visitWeak(VM&) const; + + void aboutToDie(); + + void dump(PrintStream& out) const; + bool containsPC(void* pc) const + { + if (!m_stubRoutine) + return false; + + uintptr_t pcAsInt = bitwise_cast<uintptr_t>(pc); + return m_stubRoutine->startAddress() <= pcAsInt && pcAsInt <= m_stubRoutine->endAddress(); + } + +private: + friend class AccessCase; + friend class CodeBlock; + friend struct AccessGenerationState; + + typedef Vector<std::unique_ptr<AccessCase>, 2> ListType; + + MacroAssemblerCodePtr regenerate( + VM&, CodeBlock*, StructureStubInfo&, const Identifier&, ListType& cases); + + ListType m_list; + RefPtr<JITStubRoutine> m_stubRoutine; + std::unique_ptr<WatchpointsOnStructureStubInfo> m_watchpoints; + std::unique_ptr<Vector<WriteBarrier<JSCell>>> m_weakReferences; +}; + +struct AccessGenerationState { + AccessGenerationState() + : m_calculatedRegistersForCallAndExceptionHandling(false) + , m_needsToRestoreRegistersIfException(false) + , m_calculatedCallSiteIndex(false) + { + } + CCallHelpers* jit { nullptr }; + ScratchRegisterAllocator* allocator; + ScratchRegisterAllocator::PreservedState preservedReusedRegisterState; + PolymorphicAccess* access { nullptr }; + StructureStubInfo* stubInfo { nullptr }; + MacroAssembler::JumpList success; + MacroAssembler::JumpList failAndRepatch; + MacroAssembler::JumpList failAndIgnore; + GPRReg baseGPR { InvalidGPRReg }; + JSValueRegs valueRegs; + GPRReg scratchGPR { InvalidGPRReg }; + Vector<std::function<void(LinkBuffer&)>> callbacks; + const Identifier* ident; + std::unique_ptr<WatchpointsOnStructureStubInfo> watchpoints; + Vector<WriteBarrier<JSCell>> weakReferences; + + Watchpoint* addWatchpoint(const ObjectPropertyCondition& = ObjectPropertyCondition()); + + void restoreScratch(); + void succeed(); + + void calculateLiveRegistersForCallAndExceptionHandling(); + + void preserveLiveRegistersToStackForCall(); + + void restoreLiveRegistersFromStackForCall(bool isGetter); + void restoreLiveRegistersFromStackForCallWithThrownException(); + void restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore); + + const RegisterSet& liveRegistersForCall() + { + RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling); + return m_liveRegistersForCall; + } + + CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal(); + CallSiteIndex callSiteIndexForExceptionHandling() + { + RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling); + RELEASE_ASSERT(m_needsToRestoreRegistersIfException); + RELEASE_ASSERT(m_calculatedCallSiteIndex); + return m_callSiteIndex; + } + + const HandlerInfo& originalExceptionHandler() const; + unsigned numberOfStackBytesUsedForRegisterPreservation() const + { + RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling); + return m_numberOfStackBytesUsedForRegisterPreservation; + } + + bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; } + CallSiteIndex originalCallSiteIndex() const; + +private: + const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite() + { + RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling); + return m_liveRegistersToPreserveAtExceptionHandlingCallSite; + } + + RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite; + RegisterSet m_liveRegistersForCall; + CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits<unsigned>::max()) }; + unsigned m_numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() }; + bool m_calculatedRegistersForCallAndExceptionHandling : 1; + bool m_needsToRestoreRegistersIfException : 1; + bool m_calculatedCallSiteIndex : 1; +}; + +} // namespace JSC + +namespace WTF { + +void printInternal(PrintStream&, JSC::AccessCase::AccessType); + +} // namespace WTF + +#endif // ENABLE(JIT) + +#endif // PolymorphicAccess_h + |