summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/bytecode/AccessCase.h
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/bytecode/AccessCase.h
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/bytecode/AccessCase.h')
-rw-r--r--Source/JavaScriptCore/bytecode/AccessCase.h233
1 files changed, 233 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/bytecode/AccessCase.h b/Source/JavaScriptCore/bytecode/AccessCase.h
new file mode 100644
index 000000000..9f8a20063
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/AccessCase.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 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
+ * 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
+
+#if ENABLE(JIT)
+
+#include "JSFunctionInlines.h"
+#include "ObjectPropertyConditionSet.h"
+
+namespace JSC {
+
+struct AccessGenerationState;
+
+// An AccessCase describes one of the cases of a PolymorphicAccess. A PolymorphicAccess represents a
+// planned (to generate in future) or generated stub for some inline cache. That stub contains fast
+// path code for some finite number of fast cases, each described by an AccessCase object.
+//
+// An AccessCase object has a lifecycle that proceeds through several states. Note that the states
+// of AccessCase have a lot to do with the global effect epoch (we'll say epoch for short). This is
+// a simple way of reasoning about the state of the system outside this AccessCase. Any observable
+// effect - like storing to a property, changing an object's structure, etc. - increments the epoch.
+// The states are:
+//
+// Primordial: This is an AccessCase that was just allocated. It does not correspond to any actual
+// code and it is not owned by any PolymorphicAccess. In this state, the AccessCase
+// assumes that it is in the same epoch as when it was created. This is important
+// because it may make claims about itself ("I represent a valid case so long as you
+// register a watchpoint on this set") that could be contradicted by some outside
+// effects (like firing and deleting the watchpoint set in question). This is also the
+// state that an AccessCase is in when it is cloned (AccessCase::clone()).
+//
+// Committed: This happens as soon as some PolymorphicAccess takes ownership of this AccessCase.
+// In this state, the AccessCase no longer assumes anything about the epoch. To
+// accomplish this, PolymorphicAccess calls AccessCase::commit(). This must be done
+// during the same epoch when the AccessCase was created, either by the client or by
+// clone(). When created by the client, committing during the same epoch works because
+// we can be sure that whatever watchpoint sets they spoke of are still valid. When
+// created by clone(), we can be sure that the set is still valid because the original
+// of the clone still has watchpoints on it.
+//
+// Generated: This is the state when the PolymorphicAccess generates code for this case by
+// calling AccessCase::generate() or AccessCase::generateWithGuard(). At this point
+// the case object will have some extra stuff in it, like possibly the CallLinkInfo
+// object associated with the inline cache.
+// FIXME: Moving into the Generated state should not mutate the AccessCase object or
+// put more stuff into it. If we fix this, then we can get rid of AccessCase::clone().
+// https://bugs.webkit.org/show_bug.cgi?id=156456
+//
+// An AccessCase may be destroyed while in any of these states.
+//
+// We will sometimes buffer committed AccessCases in the PolymorphicAccess object before generating
+// code. This allows us to only regenerate once we've accumulated (hopefully) more than one new
+// AccessCase.
+class AccessCase {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ enum AccessType : uint8_t {
+ Load,
+ Transition,
+ Replace,
+ Miss,
+ GetGetter,
+ Getter,
+ Setter,
+ CustomValueGetter,
+ CustomAccessorGetter,
+ CustomValueSetter,
+ CustomAccessorSetter,
+ IntrinsicGetter,
+ InHit,
+ InMiss,
+ ArrayLength,
+ StringLength,
+ DirectArgumentsLength,
+ ScopedArgumentsLength,
+ ModuleNamespaceLoad,
+ };
+
+ enum State : uint8_t {
+ Primordial,
+ Committed,
+ Generated
+ };
+
+ template<typename T>
+ T& as() { return *static_cast<T*>(this); }
+
+ template<typename T>
+ const T& as() const { return *static_cast<const T*>(this); }
+
+
+ template<typename AccessCaseType, typename... Arguments>
+ static std::unique_ptr<AccessCaseType> create(Arguments... arguments)
+ {
+ return std::unique_ptr<AccessCaseType>(new AccessCaseType(arguments...));
+ }
+
+ static std::unique_ptr<AccessCase> create(VM&, JSCell* owner, AccessType, PropertyOffset = invalidOffset,
+ Structure* = nullptr, const ObjectPropertyConditionSet& = ObjectPropertyConditionSet());
+
+ // This create method should be used for transitions.
+ static std::unique_ptr<AccessCase> create(VM&, JSCell* owner, PropertyOffset, Structure* oldStructure,
+ Structure* newStructure, const ObjectPropertyConditionSet& = ObjectPropertyConditionSet());
+
+ static std::unique_ptr<AccessCase> fromStructureStubInfo(VM&, JSCell* owner, StructureStubInfo&);
+
+ AccessType type() const { return m_type; }
+ State state() const { return m_state; }
+ PropertyOffset offset() const { return m_offset; }
+
+ 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; }
+
+ virtual JSObject* alternateBase() const { return conditionSet().slotBaseCondition().object(); }
+ virtual WatchpointSet* additionalSet() const { return nullptr; }
+ virtual bool viaProxy() const { return false; }
+
+ // If you supply the optional vector, this will append the set of cells that this will need to keep alive
+ // past the call.
+ bool doesCalls(Vector<JSCell*>* cellsToMark = nullptr) const;
+
+ bool isGetter() const
+ {
+ switch (type()) {
+ case Getter:
+ case CustomValueGetter:
+ case CustomAccessorGetter:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isAccessor() const { return isGetter() || type() == Setter; }
+
+ // Is it still possible for this case to ever be taken? Must call this as a prerequisite for
+ // calling generate() and friends. If this returns true, then you can call generate(). If
+ // this returns false, then generate() will crash. You must call generate() in the same epoch
+ // as when you called couldStillSucceed().
+ bool couldStillSucceed() const;
+
+ // 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) const;
+
+ void dump(PrintStream& out) const;
+ virtual void dumpImpl(PrintStream&, CommaPrinter&) const { }
+
+ virtual ~AccessCase();
+
+protected:
+ AccessCase(VM&, JSCell* owner, AccessType, PropertyOffset, Structure*, const ObjectPropertyConditionSet&);
+ AccessCase(const AccessCase&) = default;
+ AccessCase& operator=(const AccessCase&) = delete;
+ void resetState() { m_state = Primordial; }
+
+private:
+ friend class CodeBlock;
+ friend class PolymorphicAccess;
+
+ bool visitWeak(VM&) const;
+ bool propagateTransitions(SlotVisitor&) const;
+
+ // FIXME: This only exists because of how AccessCase puts post-generation things into itself.
+ // https://bugs.webkit.org/show_bug.cgi?id=156456
+ virtual std::unique_ptr<AccessCase> clone() const;
+
+ // Perform any action that must be performed before the end of the epoch in which the case
+ // was created. Returns a set of watchpoint sets that will need to be watched.
+ Vector<WatchpointSet*, 2> commit(VM&, const Identifier&);
+
+ // 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 generateImpl(AccessGenerationState&);
+
+ AccessType m_type;
+ State m_state { Primordial };
+ PropertyOffset m_offset;
+
+ // 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;
+};
+
+} // namespace JSC
+
+#endif