[turbofan] Optimized lowering of DYNAMIC_GLOBAL lookup slot loads.
authormstarzinger <mstarzinger@chromium.org>
Tue, 2 Jun 2015 09:37:49 +0000 (02:37 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 2 Jun 2015 09:37:59 +0000 (09:37 +0000)
This adds handling of JSLoadDynamicGlobal nodes to JSTypedLowering to
perform extension checks and an inline fast path. The fast path is a
global variable load from the global object.

R=bmeurer@chromium.org
BUG=v8:4131
LOG=N

Review URL: https://codereview.chromium.org/1150723005

Cr-Commit-Position: refs/heads/master@{#28750}

src/compiler/ast-graph-builder.cc
src/compiler/js-generic-lowering.cc
src/compiler/js-operator.cc
src/compiler/js-operator.h
src/compiler/js-typed-lowering.cc
src/compiler/js-typed-lowering.h
src/compiler/operator-properties.cc
test/unittests/compiler/js-typed-lowering-unittest.cc
test/unittests/compiler/node-test-utils.cc
test/unittests/compiler/node-test-utils.h

index d84cca6..94057f2 100644 (file)
@@ -2748,10 +2748,15 @@ VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
 
 uint32_t AstGraphBuilder::ComputeBitsetForDynamicGlobal(Variable* variable) {
   DCHECK_EQ(DYNAMIC_GLOBAL, variable->mode());
+  bool found_eval_scope = false;
   EnumSet<int, uint32_t> check_depths;
   for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) {
     if (s->num_heap_slots() <= 0) continue;
-    // TODO(mstarzinger): Be smarter about which checks to require!
+    // TODO(mstarzinger): If we have reached an eval scope, we check all
+    // extensions from this point. Replicated from full-codegen, figure out
+    // whether this is still needed. If not, drop {found_eval_scope} below.
+    if (s->is_eval_scope()) found_eval_scope = true;
+    if (!s->calls_sloppy_eval() && !found_eval_scope) continue;
     int depth = current_scope()->ContextChainLength(s);
     if (depth > DynamicGlobalAccess::kMaxCheckDepth) {
       return DynamicGlobalAccess::kFullCheckRequired;
@@ -3021,9 +3026,10 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
       Handle<String> name = variable->name();
       if (mode == DYNAMIC_GLOBAL) {
         uint32_t check_bitset = ComputeBitsetForDynamicGlobal(variable);
-        const Operator* op = javascript()->LoadDynamicGlobal(name, check_bitset,
-                                                             contextual_mode);
+        const Operator* op = javascript()->LoadDynamicGlobal(
+            name, check_bitset, feedback, contextual_mode);
         value = NewNode(op, current_context());
+        states.AddToNode(value, bailout_id, combine);
       } else if (mode == DYNAMIC_LOCAL) {
         Variable* local = variable->local_if_not_shadowed();
         DCHECK(local->location() == Variable::CONTEXT);  // Must be context.
@@ -3032,14 +3038,15 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
         const Operator* op = javascript()->LoadDynamicContext(
             name, check_bitset, depth, local->index());
         value = NewNode(op, current_context());
+        PrepareFrameState(value, bailout_id, combine);
         // TODO(mstarzinger): Hole checks are missing here when optimized.
       } else if (mode == DYNAMIC) {
         uint32_t check_bitset = DynamicGlobalAccess::kFullCheckRequired;
-        const Operator* op = javascript()->LoadDynamicGlobal(name, check_bitset,
-                                                             contextual_mode);
+        const Operator* op = javascript()->LoadDynamicGlobal(
+            name, check_bitset, feedback, contextual_mode);
         value = NewNode(op, current_context());
+        states.AddToNode(value, bailout_id, combine);
       }
-      PrepareFrameState(value, bailout_id, combine);
       return value;
     }
   }
index 876a456..3fc0496 100644 (file)
@@ -454,6 +454,7 @@ void JSGenericLowering::LowerJSLoadDynamicGlobal(Node* node) {
                                     : Runtime::kLoadLookupSlotNoReferenceError;
   Node* projection = graph()->NewNode(common()->Projection(0), node);
   NodeProperties::ReplaceWithValue(node, projection, node, node);
+  node->RemoveInput(NodeProperties::FirstFrameStateIndex(node) + 1);
   node->InsertInput(zone(), 1, jsgraph()->Constant(access.name()));
   ReplaceWithRuntimeCall(node, function_id);
   projection->ReplaceInput(0, node);
index f6009c5..a360a27 100644 (file)
@@ -93,8 +93,12 @@ ContextAccess const& ContextAccessOf(Operator const* op) {
 
 DynamicGlobalAccess::DynamicGlobalAccess(const Handle<String>& name,
                                          uint32_t check_bitset,
+                                         const VectorSlotPair& feedback,
                                          ContextualMode mode)
-    : name_(name), check_bitset_(check_bitset), mode_(mode) {
+    : name_(name),
+      check_bitset_(check_bitset),
+      feedback_(feedback),
+      mode_(mode) {
   DCHECK(check_bitset == kFullCheckRequired || check_bitset < 0x80000000U);
 }
 
@@ -520,10 +524,10 @@ const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) {
 }
 
 
-const Operator* JSOperatorBuilder::LoadDynamicGlobal(const Handle<String>& name,
-                                                     uint32_t check_bitset,
-                                                     ContextualMode mode) {
-  DynamicGlobalAccess access(name, check_bitset, mode);
+const Operator* JSOperatorBuilder::LoadDynamicGlobal(
+    const Handle<String>& name, uint32_t check_bitset,
+    const VectorSlotPair& feedback, ContextualMode mode) {
+  DynamicGlobalAccess access(name, check_bitset, feedback, mode);
   return new (zone()) Operator1<DynamicGlobalAccess>(           // --
       IrOpcode::kJSLoadDynamicGlobal, Operator::kNoProperties,  // opcode
       "JSLoadDynamicGlobal",                                    // name
index 9a8bdd6..1ba0354 100644 (file)
@@ -112,16 +112,36 @@ std::ostream& operator<<(std::ostream&, ContextAccess const&);
 ContextAccess const& ContextAccessOf(Operator const*);
 
 
+class VectorSlotPair {
+ public:
+  VectorSlotPair(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
+      : vector_(vector), slot_(slot) {}
+
+  Handle<TypeFeedbackVector> vector() const { return vector_; }
+  FeedbackVectorICSlot slot() const { return slot_; }
+
+  int index() const { return vector_->GetIndex(slot_); }
+
+ private:
+  const Handle<TypeFeedbackVector> vector_;
+  const FeedbackVectorICSlot slot_;
+};
+
+
+bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs);
+
+
 // Defines the name for a dynamic variable lookup. The {check_bitset} allows to
 // inline checks whether the lookup yields in a global variable. This is used as
 // a parameter by JSLoadDynamicGlobal and JSStoreDynamicGlobal operators.
 class DynamicGlobalAccess final {
  public:
   DynamicGlobalAccess(const Handle<String>& name, uint32_t check_bitset,
-                      ContextualMode mode);
+                      const VectorSlotPair& feedback, ContextualMode mode);
 
   const Handle<String>& name() const { return name_; }
   uint32_t check_bitset() const { return check_bitset_; }
+  const VectorSlotPair& feedback() const { return feedback_; }
   ContextualMode mode() const { return mode_; }
 
   // Indicates that an inline check is disabled.
@@ -138,6 +158,7 @@ class DynamicGlobalAccess final {
  private:
   const Handle<String> name_;
   const uint32_t check_bitset_;
+  const VectorSlotPair feedback_;
   const ContextualMode mode_;
 };
 
@@ -190,25 +211,6 @@ std::ostream& operator<<(std::ostream&, DynamicContextAccess const&);
 DynamicContextAccess const& DynamicContextAccessOf(Operator const*);
 
 
-class VectorSlotPair {
- public:
-  VectorSlotPair(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
-      : vector_(vector), slot_(slot) {}
-
-  Handle<TypeFeedbackVector> vector() const { return vector_; }
-  FeedbackVectorICSlot slot() const { return slot_; }
-
-  int index() const { return vector_->GetIndex(slot_); }
-
- private:
-  const Handle<TypeFeedbackVector> vector_;
-  const FeedbackVectorICSlot slot_;
-};
-
-
-bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs);
-
-
 // Defines the property being loaded from an object by a named load. This is
 // used as a parameter by JSLoadNamed operators.
 class LoadNamedParameters final {
@@ -376,7 +378,9 @@ class JSOperatorBuilder final : public ZoneObject {
   const Operator* StoreContext(size_t depth, size_t index);
 
   const Operator* LoadDynamicGlobal(const Handle<String>& name,
-                                    uint32_t check_bitset, ContextualMode mode);
+                                    uint32_t check_bitset,
+                                    const VectorSlotPair& feedback,
+                                    ContextualMode mode);
   const Operator* LoadDynamicContext(const Handle<String>& name,
                                      uint32_t check_bitset, size_t depth,
                                      size_t index);
index 4a4bcbf..987f73f 100644 (file)
@@ -924,6 +924,64 @@ Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
 }
 
 
+Reduction JSTypedLowering::ReduceJSLoadDynamicGlobal(Node* node) {
+  DCHECK_EQ(IrOpcode::kJSLoadDynamicGlobal, node->opcode());
+  DynamicGlobalAccess const& access = DynamicGlobalAccessOf(node->op());
+  Node* const context = NodeProperties::GetContextInput(node);
+  Node* const state1 = NodeProperties::GetFrameStateInput(node, 0);
+  Node* const state2 = NodeProperties::GetFrameStateInput(node, 1);
+  Node* const effect = NodeProperties::GetEffectInput(node);
+  Node* const control = NodeProperties::GetControlInput(node);
+  if (access.RequiresFullCheck()) return NoChange();
+
+  // Perform checks whether the fast mode applies, by looking for any extension
+  // object which might shadow the optimistic declaration.
+  uint32_t bitset = access.check_bitset();
+  Node* check_true = control;
+  Node* check_false = graph()->NewNode(common()->Merge(0));
+  for (int depth = 0; bitset != 0; bitset >>= 1, depth++) {
+    if ((bitset & 1) == 0) continue;
+    Node* load = graph()->NewNode(
+        javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
+        context, context, effect);
+    Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), load);
+    Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), check,
+                                    check_true);
+    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+    check_false->set_op(common()->Merge(check_false->InputCount() + 1));
+    check_false->AppendInput(graph()->zone(), if_false);
+    check_true = if_true;
+  }
+
+  // Fast case, because variable is not shadowed. Perform global object load.
+  Unique<Name> name = Unique<Name>::CreateUninitialized(access.name());
+  Node* global = graph()->NewNode(
+      javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true), context,
+      context, effect);
+  Node* fast = graph()->NewNode(
+      javascript()->LoadNamed(name, access.feedback(), access.mode()), global,
+      context, state1, state2, global, check_true);
+
+  // Slow case, because variable potentially shadowed. Perform dynamic lookup.
+  uint32_t check_bitset = DynamicGlobalAccess::kFullCheckRequired;
+  Node* slow = graph()->NewNode(
+      javascript()->LoadDynamicGlobal(access.name(), check_bitset,
+                                      access.feedback(), access.mode()),
+      context, context, state1, state2, effect, check_false);
+
+  // Replace value, effect and control uses accordingly.
+  Node* new_control =
+      graph()->NewNode(common()->Merge(2), check_true, check_false);
+  Node* new_effect =
+      graph()->NewNode(common()->EffectPhi(2), fast, slow, new_control);
+  Node* new_value = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), fast,
+                                     slow, new_control);
+  ReplaceWithValue(node, new_value, new_effect, new_control);
+  return Changed(new_value);
+}
+
+
 Reduction JSTypedLowering::ReduceJSCreateClosure(Node* node) {
   DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode());
   CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
@@ -1429,6 +1487,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
       return ReduceJSLoadContext(node);
     case IrOpcode::kJSStoreContext:
       return ReduceJSStoreContext(node);
+    case IrOpcode::kJSLoadDynamicGlobal:
+      return ReduceJSLoadDynamicGlobal(node);
     case IrOpcode::kJSCreateClosure:
       return ReduceJSCreateClosure(node);
     case IrOpcode::kJSCreateLiteralArray:
index add45ce..fbd5c21 100644 (file)
@@ -45,6 +45,7 @@ class JSTypedLowering final : public AdvancedReducer {
   Reduction ReduceJSStoreProperty(Node* node);
   Reduction ReduceJSLoadContext(Node* node);
   Reduction ReduceJSStoreContext(Node* node);
+  Reduction ReduceJSLoadDynamicGlobal(Node* node);
   Reduction ReduceJSEqual(Node* node, bool invert);
   Reduction ReduceJSStrictEqual(Node* node, bool invert);
   Reduction ReduceJSUnaryNot(Node* node);
index 01acf0f..4a7f1d9 100644 (file)
@@ -49,7 +49,6 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
     case IrOpcode::kJSCreateLiteralObject:
 
     // Context operations
-    case IrOpcode::kJSLoadDynamicGlobal:
     case IrOpcode::kJSLoadDynamicContext:
     case IrOpcode::kJSCreateScriptContext:
     case IrOpcode::kJSCreateWithContext:
@@ -67,11 +66,12 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
       return 1;
 
     // We record the frame state immediately before and immediately after
-    // every property access.
+    // every property or global variable access.
     case IrOpcode::kJSLoadNamed:
     case IrOpcode::kJSStoreNamed:
     case IrOpcode::kJSLoadProperty:
     case IrOpcode::kJSStoreProperty:
+    case IrOpcode::kJSLoadDynamicGlobal:
       return 2;
 
     // Binary operators that can deopt in the middle the operation (e.g.,
index 8a0cb17..2cc48e7 100644 (file)
@@ -896,6 +896,37 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) {
   }
 }
 
+
+// -----------------------------------------------------------------------------
+// JSLoadDynamicGlobal
+
+
+TEST_F(JSTypedLoweringTest, JSLoadDynamicGlobal) {
+  Node* const context = Parameter(Type::Any());
+  Node* const frame_state = EmptyFrameState();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Handle<String> name = factory()->object_string();
+  VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
+                          FeedbackVectorICSlot::Invalid());
+  for (int i = 0; i < DynamicGlobalAccess::kMaxCheckDepth; ++i) {
+    uint32_t bitset = 1 << i;  // Only single check.
+    Reduction r = Reduce(graph()->NewNode(
+        javascript()->LoadDynamicGlobal(name, bitset, feedback, NOT_CONTEXTUAL),
+        context, context, frame_state, frame_state, effect, control));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsPhi(kMachAnyTagged, _, _,
+              IsMerge(IsIfTrue(IsBranch(
+                          IsObjectIsSmi(IsLoadContext(
+                              ContextAccess(i, Context::EXTENSION_INDEX, false),
+                              context)),
+                          control)),
+                      _)));
+  }
+}
+
 #if V8_TURBOFAN_TARGET
 
 // -----------------------------------------------------------------------------
index 522eecf..d5d4e1a 100644 (file)
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "src/assembler.h"
+#include "src/compiler/js-operator.h"
 #include "src/compiler/node-properties.h"
 #include "src/compiler/simplified-operator.h"
 #include "src/unique.h"
@@ -1186,24 +1187,32 @@ class IsLoadMatcher final : public NodeMatcher {
 };
 
 
-class IsToNumberMatcher final : public NodeMatcher {
+class IsStoreMatcher final : public NodeMatcher {
  public:
-  IsToNumberMatcher(const Matcher<Node*>& base_matcher,
-                    const Matcher<Node*>& context_matcher,
-                    const Matcher<Node*>& effect_matcher,
-                    const Matcher<Node*>& control_matcher)
-      : NodeMatcher(IrOpcode::kJSToNumber),
+  IsStoreMatcher(const Matcher<StoreRepresentation>& rep_matcher,
+                 const Matcher<Node*>& base_matcher,
+                 const Matcher<Node*>& index_matcher,
+                 const Matcher<Node*>& value_matcher,
+                 const Matcher<Node*>& effect_matcher,
+                 const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kStore),
+        rep_matcher_(rep_matcher),
         base_matcher_(base_matcher),
-        context_matcher_(context_matcher),
+        index_matcher_(index_matcher),
+        value_matcher_(value_matcher),
         effect_matcher_(effect_matcher),
         control_matcher_(control_matcher) {}
 
   void DescribeTo(std::ostream* os) const final {
     NodeMatcher::DescribeTo(os);
-    *os << " whose base (";
+    *os << " whose rep (";
+    rep_matcher_.DescribeTo(os);
+    *os << "), base (";
     base_matcher_.DescribeTo(os);
-    *os << "), context (";
-    context_matcher_.DescribeTo(os);
+    *os << "), index (";
+    index_matcher_.DescribeTo(os);
+    *os << "), value (";
+    value_matcher_.DescribeTo(os);
     *os << "), effect (";
     effect_matcher_.DescribeTo(os);
     *os << ") and control (";
@@ -1213,10 +1222,14 @@ class IsToNumberMatcher final : public NodeMatcher {
 
   bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
     return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<StoreRepresentation>(node), "rep",
+                                 rep_matcher_, listener) &&
             PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
                                  base_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetContextInput(node),
-                                 "context", context_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "index", index_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "value", value_matcher_, listener) &&
             PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
                                  effect_matcher_, listener) &&
             PrintMatchAndExplain(NodeProperties::GetControlInput(node),
@@ -1224,39 +1237,33 @@ class IsToNumberMatcher final : public NodeMatcher {
   }
 
  private:
+  const Matcher<StoreRepresentation> rep_matcher_;
   const Matcher<Node*> base_matcher_;
-  const Matcher<Node*> context_matcher_;
+  const Matcher<Node*> index_matcher_;
+  const Matcher<Node*> value_matcher_;
   const Matcher<Node*> effect_matcher_;
   const Matcher<Node*> control_matcher_;
 };
 
 
-class IsStoreMatcher final : public NodeMatcher {
+class IsToNumberMatcher final : public NodeMatcher {
  public:
-  IsStoreMatcher(const Matcher<StoreRepresentation>& rep_matcher,
-                 const Matcher<Node*>& base_matcher,
-                 const Matcher<Node*>& index_matcher,
-                 const Matcher<Node*>& value_matcher,
-                 const Matcher<Node*>& effect_matcher,
-                 const Matcher<Node*>& control_matcher)
-      : NodeMatcher(IrOpcode::kStore),
-        rep_matcher_(rep_matcher),
+  IsToNumberMatcher(const Matcher<Node*>& base_matcher,
+                    const Matcher<Node*>& context_matcher,
+                    const Matcher<Node*>& effect_matcher,
+                    const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kJSToNumber),
         base_matcher_(base_matcher),
-        index_matcher_(index_matcher),
-        value_matcher_(value_matcher),
+        context_matcher_(context_matcher),
         effect_matcher_(effect_matcher),
         control_matcher_(control_matcher) {}
 
   void DescribeTo(std::ostream* os) const final {
     NodeMatcher::DescribeTo(os);
-    *os << " whose rep (";
-    rep_matcher_.DescribeTo(os);
-    *os << "), base (";
+    *os << " whose base (";
     base_matcher_.DescribeTo(os);
-    *os << "), index (";
-    index_matcher_.DescribeTo(os);
-    *os << "), value (";
-    value_matcher_.DescribeTo(os);
+    *os << "), context (";
+    context_matcher_.DescribeTo(os);
     *os << "), effect (";
     effect_matcher_.DescribeTo(os);
     *os << ") and control (";
@@ -1266,14 +1273,10 @@ class IsStoreMatcher final : public NodeMatcher {
 
   bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
     return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(OpParameter<StoreRepresentation>(node), "rep",
-                                 rep_matcher_, listener) &&
             PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
                                  base_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
-                                 "index", index_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
-                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetContextInput(node),
+                                 "context", context_matcher_, listener) &&
             PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
                                  effect_matcher_, listener) &&
             PrintMatchAndExplain(NodeProperties::GetControlInput(node),
@@ -1281,15 +1284,35 @@ class IsStoreMatcher final : public NodeMatcher {
   }
 
  private:
-  const Matcher<StoreRepresentation> rep_matcher_;
   const Matcher<Node*> base_matcher_;
-  const Matcher<Node*> index_matcher_;
-  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> context_matcher_;
   const Matcher<Node*> effect_matcher_;
   const Matcher<Node*> control_matcher_;
 };
 
 
+class IsLoadContextMatcher final : public NodeMatcher {
+ public:
+  IsLoadContextMatcher(const Matcher<ContextAccess>& access_matcher,
+                       const Matcher<Node*>& context_matcher)
+      : NodeMatcher(IrOpcode::kJSLoadContext),
+        access_matcher_(access_matcher),
+        context_matcher_(context_matcher) {}
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<ContextAccess>(node), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetContextInput(node),
+                                 "context", context_matcher_, listener));
+  }
+
+ private:
+  const Matcher<ContextAccess> access_matcher_;
+  const Matcher<Node*> context_matcher_;
+};
+
+
 class IsBinopMatcher final : public NodeMatcher {
  public:
   IsBinopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& lhs_matcher,
@@ -1727,15 +1750,6 @@ Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
 }
 
 
-Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher,
-                          const Matcher<Node*>& context_matcher,
-                          const Matcher<Node*>& effect_matcher,
-                          const Matcher<Node*>& control_matcher) {
-  return MakeMatcher(new IsToNumberMatcher(base_matcher, context_matcher,
-                                           effect_matcher, control_matcher));
-}
-
-
 Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
                        const Matcher<Node*>& base_matcher,
                        const Matcher<Node*>& index_matcher,
@@ -1748,6 +1762,21 @@ Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
 }
 
 
+Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher,
+                          const Matcher<Node*>& context_matcher,
+                          const Matcher<Node*>& effect_matcher,
+                          const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsToNumberMatcher(base_matcher, context_matcher,
+                                           effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsLoadContext(const Matcher<ContextAccess>& access_matcher,
+                             const Matcher<Node*>& context_matcher) {
+  return MakeMatcher(new IsLoadContextMatcher(access_matcher, context_matcher));
+}
+
+
 #define IS_BINOP_MATCHER(Name)                                            \
   Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher,              \
                           const Matcher<Node*>& rhs_matcher) {            \
index d7b17ab..05893e8 100644 (file)
@@ -27,6 +27,7 @@ namespace compiler {
 // Forward declarations.
 class BufferAccess;
 class CallDescriptor;
+class ContextAccess;
 struct ElementAccess;
 struct FieldAccess;
 class Node;
@@ -264,6 +265,8 @@ Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher,
                           const Matcher<Node*>& context_matcher,
                           const Matcher<Node*>& effect_matcher,
                           const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsLoadContext(const Matcher<ContextAccess>& access_matcher,
+                             const Matcher<Node*>& context_matcher);
 Matcher<Node*> IsNumberToInt32(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsNumberToUint32(const Matcher<Node*>& input_matcher);