Title: [199297] trunk/Source/_javascript_Core
Revision
199297
Author
fpi...@apple.com
Date
2016-04-11 11:20:59 -0700 (Mon, 11 Apr 2016)

Log Message

Clean up how we reason about the states of AccessCases
https://bugs.webkit.org/show_bug.cgi?id=156454

Reviewed by Mark Lam.
        
Currently when we add an AccessCase to a PolymorphicAccess stub, we regenerate the stub.
That means that as we grow a stub to have N cases, we will do O(N^2) generation work. I want
to explore buffering AccessCases so that we can do O(N) generation work instead. But to
before I go there, I want to make sure that the statefulness of AccessCase makes sense. So,
I broke it down into three different states and added assertions about the transitions. I
also broke out a separate operation called AccessCase::commit(), which is the work that
cannot be buffered since there cannot be any JS effects between when the AccessCase was
created and when we do the work in commit().
        
This opens up a fairly obvious path to buffering AccessCases: add them to the list without
regenerating. Then when we do eventually trigger regeneration, those cases will get cloned
and generated automagically. This patch doesn't implement this technique yet, but gives us
an opportunity to independently test the scaffolding necessary to do it.

This is perf-neutral on lots of tests.

* bytecode/PolymorphicAccess.cpp:
(JSC::AccessGenerationResult::dump):
(JSC::AccessCase::clone):
(JSC::AccessCase::commit):
(JSC::AccessCase::guardedByStructureCheck):
(JSC::AccessCase::dump):
(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generate):
(JSC::AccessCase::generateImpl):
(JSC::PolymorphicAccess::regenerateWithCases):
(JSC::PolymorphicAccess::regenerate):
(WTF::printInternal):
* bytecode/PolymorphicAccess.h:
(JSC::AccessCase::type):
(JSC::AccessCase::state):
(JSC::AccessCase::offset):
(JSC::AccessCase::viaProxy):
(JSC::AccessCase::callLinkInfo):
* bytecode/StructureStubInfo.cpp:
(JSC::StructureStubInfo::addAccessCase):
* bytecode/Watchpoint.h:
* dfg/DFGOperations.cpp:
* jit/Repatch.cpp:
(JSC::repatchGetByID):
(JSC::repatchPutByID):
(JSC::repatchIn):
* runtime/VM.cpp:
(JSC::VM::dumpRegExpTrace):
(JSC::VM::ensureWatchpointSetForImpureProperty):
(JSC::VM::registerWatchpointForImpureProperty):
(JSC::VM::addImpureProperty):
* runtime/VM.h:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (199296 => 199297)


--- trunk/Source/_javascript_Core/ChangeLog	2016-04-11 16:50:44 UTC (rev 199296)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-04-11 18:20:59 UTC (rev 199297)
@@ -1,3 +1,59 @@
+2016-04-10  Filip Pizlo  <fpi...@apple.com>
+
+        Clean up how we reason about the states of AccessCases
+        https://bugs.webkit.org/show_bug.cgi?id=156454
+
+        Reviewed by Mark Lam.
+        
+        Currently when we add an AccessCase to a PolymorphicAccess stub, we regenerate the stub.
+        That means that as we grow a stub to have N cases, we will do O(N^2) generation work. I want
+        to explore buffering AccessCases so that we can do O(N) generation work instead. But to
+        before I go there, I want to make sure that the statefulness of AccessCase makes sense. So,
+        I broke it down into three different states and added assertions about the transitions. I
+        also broke out a separate operation called AccessCase::commit(), which is the work that
+        cannot be buffered since there cannot be any JS effects between when the AccessCase was
+        created and when we do the work in commit().
+        
+        This opens up a fairly obvious path to buffering AccessCases: add them to the list without
+        regenerating. Then when we do eventually trigger regeneration, those cases will get cloned
+        and generated automagically. This patch doesn't implement this technique yet, but gives us
+        an opportunity to independently test the scaffolding necessary to do it.
+
+        This is perf-neutral on lots of tests.
+
+        * bytecode/PolymorphicAccess.cpp:
+        (JSC::AccessGenerationResult::dump):
+        (JSC::AccessCase::clone):
+        (JSC::AccessCase::commit):
+        (JSC::AccessCase::guardedByStructureCheck):
+        (JSC::AccessCase::dump):
+        (JSC::AccessCase::generateWithGuard):
+        (JSC::AccessCase::generate):
+        (JSC::AccessCase::generateImpl):
+        (JSC::PolymorphicAccess::regenerateWithCases):
+        (JSC::PolymorphicAccess::regenerate):
+        (WTF::printInternal):
+        * bytecode/PolymorphicAccess.h:
+        (JSC::AccessCase::type):
+        (JSC::AccessCase::state):
+        (JSC::AccessCase::offset):
+        (JSC::AccessCase::viaProxy):
+        (JSC::AccessCase::callLinkInfo):
+        * bytecode/StructureStubInfo.cpp:
+        (JSC::StructureStubInfo::addAccessCase):
+        * bytecode/Watchpoint.h:
+        * dfg/DFGOperations.cpp:
+        * jit/Repatch.cpp:
+        (JSC::repatchGetByID):
+        (JSC::repatchPutByID):
+        (JSC::repatchIn):
+        * runtime/VM.cpp:
+        (JSC::VM::dumpRegExpTrace):
+        (JSC::VM::ensureWatchpointSetForImpureProperty):
+        (JSC::VM::registerWatchpointForImpureProperty):
+        (JSC::VM::addImpureProperty):
+        * runtime/VM.h:
+
 2016-04-11  Fujii Hironori  <hironori.fu...@jp.sony.com>
 
         [CMake] Make FOLDER property INHERITED

Modified: trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.cpp (199296 => 199297)


--- trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.cpp	2016-04-11 16:50:44 UTC (rev 199296)
+++ trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.cpp	2016-04-11 18:20:59 UTC (rev 199297)
@@ -48,6 +48,14 @@
 
 static const bool verbose = false;
 
+// EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned on an even-numbered register (r0, r2 or [sp]).
+// To prevent the assembler from using wrong registers, let's occupy r1 or r3 with a dummy argument when necessary.
+#if (COMPILER_SUPPORTS(EABI) && CPU(ARM)) || CPU(MIPS)
+#define EABI_32BIT_DUMMY_ARG      CCallHelpers::TrustedImm32(0),
+#else
+#define EABI_32BIT_DUMMY_ARG
+#endif
+
 void AccessGenerationResult::dump(PrintStream& out) const
 {
     out.print(m_kind);
@@ -389,6 +397,24 @@
     return result;
 }
 
+Vector<WatchpointSet*, 2> AccessCase::commit(VM& vm, const Identifier& ident)
+{
+    RELEASE_ASSERT(m_state == Primordial);
+    
+    Vector<WatchpointSet*, 2> result;
+    
+    if ((structure() && structure()->needImpurePropertyWatchpoint())
+        || m_conditionSet.needImpurePropertyWatchpoint())
+        result.append(vm.ensureWatchpointSetForImpureProperty(ident));
+
+    if (additionalSet())
+        result.append(additionalSet());
+    
+    m_state = Committed;
+    
+    return result;
+}
+
 bool AccessCase::guardedByStructureCheck() const
 {
     if (viaProxy())
@@ -470,6 +496,8 @@
     out.print(m_type, ":(");
 
     CommaPrinter comma;
+    
+    out.print(comma, m_state);
 
     if (m_type == Transition)
         out.print(comma, "structure = ", pointerDump(structure()), " -> ", pointerDump(newStructure()));
@@ -517,6 +545,11 @@
 void AccessCase::generateWithGuard(
     AccessGenerationState& state, CCallHelpers::JumpList& fallThrough)
 {
+    SuperSamplerScope superSamplerScope(false);
+
+    RELEASE_ASSERT(m_state == Committed);
+    m_state = Generated;
+    
     CCallHelpers& jit = *state.jit;
     VM& vm = *jit.vm();
     const Identifier& ident = *state.ident;
@@ -730,22 +763,25 @@
         break;
     } };
 
-    generate(state);
+    generateImpl(state);
 }
 
-// EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned on an even-numbered register (r0, r2 or [sp]).
-// To prevent the assembler from using wrong registers, let's occupy r1 or r3 with a dummy argument when necessary.
-#if (COMPILER_SUPPORTS(EABI) && CPU(ARM)) || CPU(MIPS)
-#define EABI_32BIT_DUMMY_ARG      CCallHelpers::TrustedImm32(0),
-#else
-#define EABI_32BIT_DUMMY_ARG
-#endif
-
 void AccessCase::generate(AccessGenerationState& state)
 {
+    RELEASE_ASSERT(m_state == Committed);
+    m_state = Generated;
+    
+    generateImpl(state);
+}
+
+void AccessCase::generateImpl(AccessGenerationState& state)
+{
+    SuperSamplerScope superSamplerScope(false);
     if (verbose)
         dataLog("Generating code for: ", *this, "\n");
     
+    ASSERT(m_state == Generated); // We rely on the callers setting this for us.
+    
     CCallHelpers& jit = *state.jit;
     VM& vm = *jit.vm();
     CodeBlock* codeBlock = jit.codeBlock();
@@ -757,13 +793,6 @@
 
     ASSERT(m_conditionSet.structuresEnsureValidityAssumingImpurePropertyWatchpoint());
 
-    if ((structure() && structure()->needImpurePropertyWatchpoint())
-        || m_conditionSet.needImpurePropertyWatchpoint())
-        vm.registerWatchpointForImpureProperty(ident, state.addWatchpoint());
-
-    if (additionalSet())
-        additionalSet()->add(state.addWatchpoint());
-
     for (const ObjectPropertyCondition& condition : m_conditionSet) {
         Structure* structure = condition.object()->structure();
 
@@ -773,6 +802,10 @@
         }
 
         if (!condition.structureEnsuresValidityAssumingImpurePropertyWatchpoint(structure)) {
+            // The reason why this cannot happen is that we require that PolymorphicAccess calls
+            // AccessCase::generate() only after it has verified that
+            // AccessCase::couldStillSucceed() returned true.
+            
             dataLog("This condition is no longer met: ", condition, "\n");
             RELEASE_ASSERT_NOT_REACHED();
         }
@@ -1363,6 +1396,8 @@
     VM& vm, CodeBlock* codeBlock, StructureStubInfo& stubInfo, const Identifier& ident,
     Vector<std::unique_ptr<AccessCase>> originalCasesToAdd)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     // This method will add the originalCasesToAdd to the list one at a time while preserving the
     // invariants:
     // - If a newly added case canReplace() any existing case, then the existing case is removed before
@@ -1503,6 +1538,8 @@
     VM& vm, CodeBlock* codeBlock, StructureStubInfo& stubInfo, const Identifier& ident,
     PolymorphicAccess::ListType& cases)
 {
+    SuperSamplerScope superSamplerScope(false);
+    
     if (verbose)
         dataLog("Generating code for cases: ", listDump(cases), "\n");
     
@@ -1538,6 +1575,9 @@
     bool allGuardedByStructureCheck = true;
     bool hasJSGetterSetterCall = false;
     for (auto& entry : cases) {
+        for (WatchpointSet* set : entry->commit(vm, ident))
+            set->add(state.addWatchpoint());
+        
         allGuardedByStructureCheck &= entry->guardedByStructureCheck();
         if (entry->type() == AccessCase::Getter || entry->type() == AccessCase::Setter)
             hasJSGetterSetterCall = true;
@@ -1763,6 +1803,23 @@
     RELEASE_ASSERT_NOT_REACHED();
 }
 
+void printInternal(PrintStream& out, AccessCase::State state)
+{
+    switch (state) {
+    case AccessCase::Primordial:
+        out.print("Primordial");
+        return;
+    case AccessCase::Committed:
+        out.print("Committed");
+        return;
+    case AccessCase::Generated:
+        out.print("Generated");
+        return;
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
 } // namespace WTF
 
 #endif // ENABLE(JIT)

Modified: trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.h (199296 => 199297)


--- trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.h	2016-04-11 16:50:44 UTC (rev 199296)
+++ trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.h	2016-04-11 18:20:59 UTC (rev 199297)
@@ -47,11 +47,52 @@
 
 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.
+//
+// Note that right now, an AccessCase goes from Primordial to Generated quite quickly.
+// FIXME: Make it possible for PolymorphicAccess to hold onto AccessCases that haven't been
+// generated. That would allow us to significantly reduce the number of regeneration events.
+// https://bugs.webkit.org/show_bug.cgi?id=156457
 class AccessCase {
     WTF_MAKE_NONCOPYABLE(AccessCase);
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    enum AccessType {
+    enum AccessType : uint8_t {
         Load,
         MegamorphicLoad,
         Transition,
@@ -72,6 +113,12 @@
         DirectArgumentsLength,
         ScopedArgumentsLength
     };
+    
+    enum State : uint8_t {
+        Primordial,
+        Committed,
+        Generated
+    };
 
     static std::unique_ptr<AccessCase> tryGet(
         VM&, JSCell* owner, AccessType, PropertyOffset, Structure*,
@@ -111,9 +158,8 @@
 
     ~AccessCase();
     
-    std::unique_ptr<AccessCase> clone() const;
-    
     AccessType type() const { return m_type; }
+    State state() const { return m_state; }
     PropertyOffset offset() const { return m_offset; }
     bool viaProxy() const { return m_rareData ? m_rareData->viaProxy : false; }
     
@@ -176,8 +222,11 @@
             return nullptr;
         return m_rareData->callLinkInfo.get();
     }
-
-    // Is it still possible for this case to ever be taken?
+    
+    // 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;
     
     static bool canEmitIntrinsicGetter(JSFunction*, Structure*);
@@ -198,6 +247,14 @@
     AccessCase();
 
     bool visitWeak(VM&) const;
+    
+    // FIXME: This only exists because of how AccessCase puts post-generation things into itself.
+    // https://bugs.webkit.org/show_bug.cgi?id=156456
+    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
@@ -206,9 +263,12 @@
 
     // Fall through on success, add a jump to the failure list on failure.
     void generate(AccessGenerationState&);
+    
+    void generateImpl(AccessGenerationState&);
     void emitIntrinsicGetter(AccessGenerationState&);
     
     AccessType m_type { Load };
+    State m_state { Primordial };
     PropertyOffset m_offset { invalidOffset };
 
     // Usually this is the structure that we expect the base object to have. But, this is the *new*
@@ -229,6 +289,8 @@
         
         bool viaProxy;
         RefPtr<WatchpointSet> additionalSet;
+        // FIXME: This should probably live in the stub routine object.
+        // https://bugs.webkit.org/show_bug.cgi?id=156456
         std::unique_ptr<CallLinkInfo> callLinkInfo;
         union {
             PropertySlot::GetValueFunc getter;
@@ -433,6 +495,7 @@
 
 void printInternal(PrintStream&, JSC::AccessGenerationResult::Kind);
 void printInternal(PrintStream&, JSC::AccessCase::AccessType);
+void printInternal(PrintStream&, JSC::AccessCase::State);
 
 } // namespace WTF
 

Modified: trunk/Source/_javascript_Core/bytecode/StructureStubInfo.cpp (199296 => 199297)


--- trunk/Source/_javascript_Core/bytecode/StructureStubInfo.cpp	2016-04-11 16:50:44 UTC (rev 199296)
+++ trunk/Source/_javascript_Core/bytecode/StructureStubInfo.cpp	2016-04-11 18:20:59 UTC (rev 199297)
@@ -112,9 +112,12 @@
     if (!accessCase)
         return AccessGenerationResult::GaveUp;
     
-    if (cacheType == CacheType::Stub)
+    if (cacheType == CacheType::Stub) {
+        SuperSamplerScope superSamplerScope(true);
+    
         return u.stub->regenerateWithCase(vm, codeBlock, *this, ident, WTFMove(accessCase));
-
+    }
+    
     std::unique_ptr<PolymorphicAccess> access = std::make_unique<PolymorphicAccess>();
     
     Vector<std::unique_ptr<AccessCase>> accessCases;

Modified: trunk/Source/_javascript_Core/bytecode/Watchpoint.h (199296 => 199297)


--- trunk/Source/_javascript_Core/bytecode/Watchpoint.h	2016-04-11 16:50:44 UTC (rev 199296)
+++ trunk/Source/_javascript_Core/bytecode/Watchpoint.h	2016-04-11 18:20:59 UTC (rev 199297)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -95,6 +95,9 @@
     friend class LLIntOffsetsExtractor;
 public:
     JS_EXPORT_PRIVATE WatchpointSet(WatchpointState);
+    
+    // FIXME: In many cases, it would be amazing if this *did* fire the watchpoints. I suspect that
+    // this might be hard to get right, but still, it might be awesome.
     JS_EXPORT_PRIVATE ~WatchpointSet(); // Note that this will not fire any of the watchpoints; if you need to know when a WatchpointSet dies then you need a separate mechanism for this.
     
     // Fast way of getting the state, which only works from the main thread.

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (199296 => 199297)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2016-04-11 16:50:44 UTC (rev 199296)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2016-04-11 18:20:59 UTC (rev 199297)
@@ -691,7 +691,7 @@
 
 size_t JIT_OPERATION operationRegExpTestGeneric(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
 {
-    SuperSamplerScope superSamplerScope;
+    SuperSamplerScope superSamplerScope(false);
     
     VM& vm = globalObject->vm();
     NativeCallFrameTracer tracer(&vm, exec);

Modified: trunk/Source/_javascript_Core/jit/Repatch.cpp (199296 => 199297)


--- trunk/Source/_javascript_Core/jit/Repatch.cpp	2016-04-11 16:50:44 UTC (rev 199296)
+++ trunk/Source/_javascript_Core/jit/Repatch.cpp	2016-04-11 18:20:59 UTC (rev 199297)
@@ -379,6 +379,7 @@
 
 void repatchGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo, GetByIDKind kind)
 {
+    SuperSamplerScope superSamplerScope(false);
     GCSafeConcurrentJITLocker locker(exec->codeBlock()->m_lock, exec->vm().heap);
     
     if (tryCacheGetByID(exec, baseValue, propertyName, slot, stubInfo, kind) == GiveUpOnCache)
@@ -533,6 +534,7 @@
 
 void repatchPutByID(ExecState* exec, JSValue baseValue, Structure* structure, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
+    SuperSamplerScope superSamplerScope(false);
     GCSafeConcurrentJITLocker locker(exec->codeBlock()->m_lock, exec->vm().heap);
     
     if (tryCachePutByID(exec, baseValue, structure, propertyName, slot, stubInfo, putKind) == GiveUpOnCache)
@@ -596,6 +598,7 @@
     ExecState* exec, JSCell* base, const Identifier& ident, bool wasFound,
     const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
+    SuperSamplerScope superSamplerScope(false);
     if (tryRepatchIn(exec, base, ident, wasFound, slot, stubInfo) == GiveUpOnCache)
         repatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationIn);
 }

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (199296 => 199297)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2016-04-11 16:50:44 UTC (rev 199296)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2016-04-11 18:20:59 UTC (rev 199297)
@@ -755,14 +755,19 @@
 }
 #endif
 
-void VM::registerWatchpointForImpureProperty(const Identifier& propertyName, Watchpoint* watchpoint)
+WatchpointSet* VM::ensureWatchpointSetForImpureProperty(const Identifier& propertyName)
 {
     auto result = m_impurePropertyWatchpointSets.add(propertyName.string(), nullptr);
     if (result.isNewEntry)
         result.iterator->value = adoptRef(new WatchpointSet(IsWatched));
-    result.iterator->value->add(watchpoint);
+    return result.iterator->value.get();
 }
 
+void VM::registerWatchpointForImpureProperty(const Identifier& propertyName, Watchpoint* watchpoint)
+{
+    ensureWatchpointSetForImpureProperty(propertyName)->add(watchpoint);
+}
+
 void VM::addImpureProperty(const String& propertyName)
 {
     if (RefPtr<WatchpointSet> watchpointSet = m_impurePropertyWatchpointSets.take(propertyName))

Modified: trunk/Source/_javascript_Core/runtime/VM.h (199296 => 199297)


--- trunk/Source/_javascript_Core/runtime/VM.h	2016-04-11 16:50:44 UTC (rev 199296)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2016-04-11 18:20:59 UTC (rev 199297)
@@ -580,6 +580,7 @@
     JS_EXPORT_PRIVATE void deleteAllLinkedCode();
     JS_EXPORT_PRIVATE void deleteAllRegExpCode();
 
+    WatchpointSet* ensureWatchpointSetForImpureProperty(const Identifier&);
     void registerWatchpointForImpureProperty(const Identifier&, Watchpoint*);
     
     // FIXME: Use AtomicString once it got merged with Identifier.
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to