[turbofan] New operator for loads of DYNAMIC_[GLOBAL,LOCAL].
authormstarzinger <mstarzinger@chromium.org>
Mon, 1 Jun 2015 07:35:06 +0000 (00:35 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 1 Jun 2015 07:35:11 +0000 (07:35 +0000)
This introduces two new operators for loads of variables bound to
Variable::LOOKUP locations. Currently they all still lower to runtime
calls, but will allow optimization during typed lowering.

R=bmeurer@chromium.org

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

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

src/compiler/ast-graph-builder.cc
src/compiler/ast-graph-builder.h
src/compiler/js-generic-lowering.cc
src/compiler/js-operator.cc
src/compiler/js-operator.h
src/compiler/opcodes.h
src/compiler/operator-properties.cc
src/compiler/typer.cc
src/compiler/verifier.cc

index 78a0906780e9a6df95e2a808529a7b60078786b4..b648495fdfd5d13cabefadec159ff16e442e07d2 100644 (file)
@@ -1633,8 +1633,8 @@ void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) {
     DCHECK_NOT_NULL(expr->class_variable_proxy());
     Variable* var = expr->class_variable_proxy()->var();
     FrameStateBeforeAndAfter states(this, BailoutId::None());
-    BuildVariableAssignment(states, var, literal, Token::INIT_CONST,
-                            BailoutId::None());
+    BuildVariableAssignment(var, literal, Token::INIT_CONST, BailoutId::None(),
+                            states);
   }
 
   ast_context()->ProduceValue(literal);
@@ -1663,7 +1663,7 @@ void AstGraphBuilder::VisitConditional(Conditional* expr) {
 void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
   VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot());
   FrameStateBeforeAndAfter states(this, BeforeId(expr));
-  Node* value = BuildVariableLoad(states, expr->var(), expr->id(), pair,
+  Node* value = BuildVariableLoad(expr->var(), expr->id(), states, pair,
                                   ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
 }
@@ -1975,7 +1975,7 @@ void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value,
     case VARIABLE: {
       Variable* var = expr->AsVariableProxy()->var();
       FrameStateBeforeAndAfter states(this, BailoutId::None());
-      BuildVariableAssignment(states, var, value, Token::ASSIGN, bailout_id);
+      BuildVariableAssignment(var, value, Token::ASSIGN, bailout_id, states);
       break;
     }
     case NAMED_PROPERTY: {
@@ -2047,7 +2047,7 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
             CreateVectorSlotPair(proxy->VariableFeedbackSlot());
         FrameStateBeforeAndAfter states(this, BeforeId(proxy));
         old_value =
-            BuildVariableLoad(states, proxy->var(), expr->target()->id(), pair,
+            BuildVariableLoad(proxy->var(), expr->target()->id(), states, pair,
                               OutputFrameStateCombine::Push());
         break;
       }
@@ -2102,8 +2102,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
   switch (assign_type) {
     case VARIABLE: {
       Variable* variable = expr->target()->AsVariableProxy()->var();
-      BuildVariableAssignment(store_states, variable, value, expr->op(),
-                              expr->id(), ast_context()->GetStateCombine());
+      BuildVariableAssignment(variable, value, expr->op(), expr->id(),
+                              store_states, ast_context()->GetStateCombine());
       break;
     }
     case NAMED_PROPERTY: {
@@ -2184,7 +2184,7 @@ void AstGraphBuilder::VisitCall(Call* expr) {
       VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
       FrameStateBeforeAndAfter states(this, BeforeId(proxy));
       callee_value =
-          BuildVariableLoad(states, proxy->var(), expr->expression()->id(),
+          BuildVariableLoad(proxy->var(), expr->expression()->id(), states,
                             pair, OutputFrameStateCombine::Push());
       receiver_value = jsgraph()->UndefinedConstant();
       break;
@@ -2412,7 +2412,7 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
       VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
       FrameStateBeforeAndAfter states(this, BeforeId(proxy));
       old_value =
-          BuildVariableLoad(states, proxy->var(), expr->expression()->id(),
+          BuildVariableLoad(proxy->var(), expr->expression()->id(), states,
                             pair, OutputFrameStateCombine::Push());
       stack_depth = 0;
       break;
@@ -2476,8 +2476,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
     case VARIABLE: {
       Variable* variable = expr->expression()->AsVariableProxy()->var();
       environment()->Push(value);
-      BuildVariableAssignment(store_states, variable, value, expr->op(),
-                              expr->AssignmentId());
+      BuildVariableAssignment(variable, value, expr->op(), expr->AssignmentId(),
+                              store_states);
       environment()->Pop();
       break;
     }
@@ -2680,7 +2680,7 @@ void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) {
     VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
     FrameStateBeforeAndAfter states(this, BeforeId(proxy));
     operand =
-        BuildVariableLoad(states, proxy->var(), expr->expression()->id(), pair,
+        BuildVariableLoad(proxy->var(), expr->expression()->id(), states, pair,
                           OutputFrameStateCombine::Push(), NOT_CONTEXTUAL);
   } else {
     VisitForValue(expr->expression());
@@ -2747,6 +2747,39 @@ VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
 }
 
 
+uint32_t AstGraphBuilder::ComputeBitsetForDynamicGlobal(Variable* variable) {
+  DCHECK_EQ(DYNAMIC_GLOBAL, variable->mode());
+  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!
+    int depth = current_scope()->ContextChainLength(s);
+    if (depth > DynamicGlobalAccess::kMaxCheckDepth) {
+      return DynamicGlobalAccess::kFullCheckRequired;
+    }
+    check_depths.Add(depth);
+  }
+  return check_depths.ToIntegral();
+}
+
+
+uint32_t AstGraphBuilder::ComputeBitsetForDynamicContext(Variable* variable) {
+  DCHECK_EQ(DYNAMIC_LOCAL, variable->mode());
+  EnumSet<int, uint32_t> check_depths;
+  for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) {
+    if (s->num_heap_slots() <= 0) continue;
+    if (!s->calls_sloppy_eval()) continue;
+    int depth = current_scope()->ContextChainLength(s);
+    if (depth > DynamicContextAccess::kMaxCheckDepth) {
+      return DynamicContextAccess::kFullCheckRequired;
+    }
+    check_depths.Add(depth);
+    if (s == variable->scope()) break;
+  }
+  return check_depths.ToIntegral();
+}
+
+
 Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
   DCHECK(environment()->stack_height() >= arity);
   Node** all = info()->zone()->NewArray<Node*>(arity);
@@ -2856,8 +2889,8 @@ Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
   DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
   // This should never lazy deopt, so it is fine to send invalid bailout id.
   FrameStateBeforeAndAfter states(this, BailoutId::None());
-  BuildVariableAssignment(states, arguments, object, Token::ASSIGN,
-                          BailoutId::None());
+  BuildVariableAssignment(arguments, object, Token::ASSIGN, BailoutId::None(),
+                          states);
 
   return object;
 }
@@ -2874,8 +2907,8 @@ Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest, int index) {
   DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
   // This should never lazy deopt, so it is fine to send invalid bailout id.
   FrameStateBeforeAndAfter states(this, BailoutId::None());
-  BuildVariableAssignment(states, rest, object, Token::ASSIGN,
-                          BailoutId::None());
+  BuildVariableAssignment(rest, object, Token::ASSIGN, BailoutId::None(),
+                          states);
 
   return object;
 }
@@ -2924,9 +2957,9 @@ Node* AstGraphBuilder::BuildThrowIfStaticPrototype(Node* name,
 }
 
 
-Node* AstGraphBuilder::BuildVariableLoad(FrameStateBeforeAndAfter& states,
-                                         Variable* variable,
+Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
                                          BailoutId bailout_id,
+                                         FrameStateBeforeAndAfter& states,
                                          const VectorSlotPair& feedback,
                                          OutputFrameStateCombine combine,
                                          ContextualMode contextual_mode) {
@@ -2937,9 +2970,9 @@ Node* AstGraphBuilder::BuildVariableLoad(FrameStateBeforeAndAfter& states,
       // Global var, const, or let variable.
       Node* global = BuildLoadGlobalObject();
       Handle<Name> name = variable->name();
-      Node* node = BuildNamedLoad(global, name, feedback, contextual_mode);
-      states.AddToNode(node, bailout_id, combine);
-      return node;
+      Node* value = BuildNamedLoad(global, name, feedback, contextual_mode);
+      states.AddToNode(value, bailout_id, combine);
+      return value;
     }
     case Variable::PARAMETER:
     case Variable::LOCAL: {
@@ -2985,15 +3018,30 @@ Node* AstGraphBuilder::BuildVariableLoad(FrameStateBeforeAndAfter& states,
     }
     case Variable::LOOKUP: {
       // Dynamic lookup of context variable (anywhere in the chain).
-      Node* name = jsgraph()->Constant(variable->name());
-      Runtime::FunctionId function_id =
-          (contextual_mode == CONTEXTUAL)
-              ? Runtime::kLoadLookupSlot
-              : Runtime::kLoadLookupSlotNoReferenceError;
-      const Operator* op = javascript()->CallRuntime(function_id, 2);
-      Node* pair = NewNode(op, current_context(), name);
-      PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1));
-      return NewNode(common()->Projection(0), pair);
+      Node* value = jsgraph()->TheHoleConstant();
+      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);
+        value = NewNode(op, current_context());
+      } else if (mode == DYNAMIC_LOCAL) {
+        Variable* local = variable->local_if_not_shadowed();
+        DCHECK(local->location() == Variable::CONTEXT);  // Must be context.
+        int depth = current_scope()->ContextChainLength(local->scope());
+        uint32_t check_bitset = ComputeBitsetForDynamicContext(variable);
+        const Operator* op = javascript()->LoadDynamicContext(
+            name, check_bitset, depth, local->index());
+        value = NewNode(op, current_context());
+        // 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);
+        value = NewNode(op, current_context());
+      }
+      PrepareFrameState(value, bailout_id, combine);
+      return value;
     }
   }
   UNREACHABLE();
@@ -3035,8 +3083,8 @@ Node* AstGraphBuilder::BuildVariableDelete(Variable* variable,
 
 
 Node* AstGraphBuilder::BuildVariableAssignment(
-    FrameStateBeforeAndAfter& states, Variable* variable, Node* value,
-    Token::Value op, BailoutId bailout_id, OutputFrameStateCombine combine) {
+    Variable* variable, Node* value, Token::Value op, BailoutId bailout_id,
+    FrameStateBeforeAndAfter& states, OutputFrameStateCombine combine) {
   Node* the_hole = jsgraph()->TheHoleConstant();
   VariableMode mode = variable->mode();
   switch (variable->location()) {
index b9ce500f775897f26a56226f19b1a67f23476d81..b3fbe7107e70a10900e5a9d8cd29d2cc8d052d3b 100644 (file)
@@ -209,9 +209,9 @@ class AstGraphBuilder : public AstVisitor {
   void UpdateControlDependencyToLeaveFunction(Node* exit);
 
   // Builds deoptimization for a given node.
-  void PrepareFrameState(
-      Node* node, BailoutId ast_id,
-      OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore());
+  void PrepareFrameState(Node* node, BailoutId ast_id,
+                         OutputFrameStateCombine framestate_combine =
+                             OutputFrameStateCombine::Ignore());
 
   BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt);
 
@@ -234,6 +234,11 @@ class AstGraphBuilder : public AstVisitor {
   // Named and keyed loads require a VectorSlotPair for successful lowering.
   VectorSlotPair CreateVectorSlotPair(FeedbackVectorICSlot slot) const;
 
+  // Determine which contexts need to be checked for extension objects that
+  // might shadow the optimistic declaration of dynamic lookup variables.
+  uint32_t ComputeBitsetForDynamicGlobal(Variable* variable);
+  uint32_t ComputeBitsetForDynamicContext(Variable* variable);
+
   // ===========================================================================
   // The following build methods all generate graph fragments and return one
   // resulting node. The operand stack height remains the same, variables and
@@ -254,15 +259,17 @@ class AstGraphBuilder : public AstVisitor {
   Node* BuildRestArgumentsArray(Variable* rest, int index);
 
   // Builders for variable load and assignment.
-  Node* BuildVariableAssignment(
-      FrameStateBeforeAndAfter& states, Variable* var, Node* value,
-      Token::Value op, BailoutId bailout_id,
-      OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore());
-  Node* BuildVariableDelete(Variable* var, BailoutId bailout_id,
-                            OutputFrameStateCombine combine);
-  Node* BuildVariableLoad(FrameStateBeforeAndAfter& states, Variable* var,
-                          BailoutId bailout_id, const VectorSlotPair& feedback,
-                          OutputFrameStateCombine combine,
+  Node* BuildVariableAssignment(Variable* variable, Node* value,
+                                Token::Value op, BailoutId bailout_id,
+                                FrameStateBeforeAndAfter& states,
+                                OutputFrameStateCombine framestate_combine =
+                                    OutputFrameStateCombine::Ignore());
+  Node* BuildVariableDelete(Variable* variable, BailoutId bailout_id,
+                            OutputFrameStateCombine framestate_combine);
+  Node* BuildVariableLoad(Variable* variable, BailoutId bailout_id,
+                          FrameStateBeforeAndAfter& states,
+                          const VectorSlotPair& feedback,
+                          OutputFrameStateCombine framestate_combine,
                           ContextualMode mode = CONTEXTUAL);
 
   // Builders for property loads and stores.
index feb3d03789ded22f9ce5d22fa072f33f2466dfa1..a97a00062cb222e7b34021942b497b3b838bbe64 100644 (file)
@@ -447,6 +447,29 @@ void JSGenericLowering::LowerJSStoreContext(Node* node) {
 }
 
 
+void JSGenericLowering::LowerJSLoadDynamicGlobal(Node* node) {
+  const DynamicGlobalAccess& access = DynamicGlobalAccessOf(node->op());
+  Runtime::FunctionId function_id =
+      (access.mode() == CONTEXTUAL) ? Runtime::kLoadLookupSlot
+                                    : Runtime::kLoadLookupSlotNoReferenceError;
+  Node* projection = graph()->NewNode(common()->Projection(0), node);
+  NodeProperties::ReplaceWithValue(node, projection, node, node);
+  node->InsertInput(zone(), 1, jsgraph()->Constant(access.name()));
+  ReplaceWithRuntimeCall(node, function_id);
+  projection->ReplaceInput(0, node);
+}
+
+
+void JSGenericLowering::LowerJSLoadDynamicContext(Node* node) {
+  const DynamicContextAccess& access = DynamicContextAccessOf(node->op());
+  Node* projection = graph()->NewNode(common()->Projection(0), node);
+  NodeProperties::ReplaceWithValue(node, projection, node, node);
+  node->InsertInput(zone(), 1, jsgraph()->Constant(access.name()));
+  ReplaceWithRuntimeCall(node, Runtime::kLoadLookupSlot);
+  projection->ReplaceInput(0, node);
+}
+
+
 void JSGenericLowering::LowerJSCreateClosure(Node* node) {
   CreateClosureParameters p = CreateClosureParametersOf(node->op());
   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.shared_info()));
index 87df6a0c923d8ee4428f8bfe45521ac6d59e7d90..f6009c5b4e974ce49a9b4554004a19521959a4c5 100644 (file)
@@ -91,6 +91,86 @@ ContextAccess const& ContextAccessOf(Operator const* op) {
 }
 
 
+DynamicGlobalAccess::DynamicGlobalAccess(const Handle<String>& name,
+                                         uint32_t check_bitset,
+                                         ContextualMode mode)
+    : name_(name), check_bitset_(check_bitset), mode_(mode) {
+  DCHECK(check_bitset == kFullCheckRequired || check_bitset < 0x80000000U);
+}
+
+
+bool operator==(DynamicGlobalAccess const& lhs,
+                DynamicGlobalAccess const& rhs) {
+  UNIMPLEMENTED();
+  return true;
+}
+
+
+bool operator!=(DynamicGlobalAccess const& lhs,
+                DynamicGlobalAccess const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(DynamicGlobalAccess const& access) {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+std::ostream& operator<<(std::ostream& os, DynamicGlobalAccess const& access) {
+  return os << Brief(*access.name()) << ", " << access.check_bitset() << ", "
+            << access.mode();
+}
+
+
+DynamicGlobalAccess const& DynamicGlobalAccessOf(Operator const* op) {
+  DCHECK_EQ(IrOpcode::kJSLoadDynamicGlobal, op->opcode());
+  return OpParameter<DynamicGlobalAccess>(op);
+}
+
+
+DynamicContextAccess::DynamicContextAccess(const Handle<String>& name,
+                                           uint32_t check_bitset,
+                                           const ContextAccess& context_access)
+    : name_(name),
+      check_bitset_(check_bitset),
+      context_access_(context_access) {
+  DCHECK(check_bitset == kFullCheckRequired || check_bitset < 0x80000000U);
+}
+
+
+bool operator==(DynamicContextAccess const& lhs,
+                DynamicContextAccess const& rhs) {
+  UNIMPLEMENTED();
+  return true;
+}
+
+
+bool operator!=(DynamicContextAccess const& lhs,
+                DynamicContextAccess const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(DynamicContextAccess const& access) {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+std::ostream& operator<<(std::ostream& os, DynamicContextAccess const& access) {
+  return os << Brief(*access.name()) << ", " << access.check_bitset() << ", "
+            << access.context_access();
+}
+
+
+DynamicContextAccess const& DynamicContextAccessOf(Operator const* op) {
+  DCHECK_EQ(IrOpcode::kJSLoadDynamicContext, op->opcode());
+  return OpParameter<DynamicContextAccess>(op);
+}
+
+
 bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs) {
   return lhs.slot().ToInt() == rhs.slot().ToInt() &&
          lhs.vector().is_identical_to(rhs.vector());
@@ -440,6 +520,31 @@ 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);
+  return new (zone()) Operator1<DynamicGlobalAccess>(           // --
+      IrOpcode::kJSLoadDynamicGlobal, Operator::kNoProperties,  // opcode
+      "JSLoadDynamicGlobal",                                    // name
+      1, 1, 1, 1, 1, 2,                                         // counts
+      access);                                                  // parameter
+}
+
+
+const Operator* JSOperatorBuilder::LoadDynamicContext(
+    const Handle<String>& name, uint32_t check_bitset, size_t depth,
+    size_t index) {
+  ContextAccess context_access(depth, index, false);
+  DynamicContextAccess access(name, check_bitset, context_access);
+  return new (zone()) Operator1<DynamicContextAccess>(           // --
+      IrOpcode::kJSLoadDynamicContext, Operator::kNoProperties,  // opcode
+      "JSLoadDynamicContext",                                    // name
+      1, 1, 1, 1, 1, 2,                                          // counts
+      access);                                                   // parameter
+}
+
+
 const Operator* JSOperatorBuilder::CreateClosure(
     Handle<SharedFunctionInfo> shared_info, PretenureFlag pretenure) {
   CreateClosureParameters parameters(shared_info, pretenure);
index ae26665b2eb45344ca38d36ba0cf5e2e02e62a3b..9a8bdd690afbf7cbe3952a32b2dfa88d191d5b43 100644 (file)
@@ -112,6 +112,84 @@ std::ostream& operator<<(std::ostream&, ContextAccess const&);
 ContextAccess const& ContextAccessOf(Operator const*);
 
 
+// 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 Handle<String>& name() const { return name_; }
+  uint32_t check_bitset() const { return check_bitset_; }
+  ContextualMode mode() const { return mode_; }
+
+  // Indicates that an inline check is disabled.
+  bool RequiresFullCheck() const {
+    return check_bitset() == kFullCheckRequired;
+  }
+
+  // Limit of context chain length to which inline check is possible.
+  static const int kMaxCheckDepth = 30;
+
+  // Sentinel for {check_bitset} disabling inline checks.
+  static const uint32_t kFullCheckRequired = -1;
+
+ private:
+  const Handle<String> name_;
+  const uint32_t check_bitset_;
+  const ContextualMode mode_;
+};
+
+size_t hash_value(DynamicGlobalAccess const&);
+
+bool operator==(DynamicGlobalAccess const&, DynamicGlobalAccess const&);
+bool operator!=(DynamicGlobalAccess const&, DynamicGlobalAccess const&);
+
+std::ostream& operator<<(std::ostream&, DynamicGlobalAccess const&);
+
+DynamicGlobalAccess const& DynamicGlobalAccessOf(Operator const*);
+
+
+// Defines the name for a dynamic variable lookup. The {check_bitset} allows to
+// inline checks whether the lookup yields in a context variable. This is used
+// as a parameter by JSLoadDynamicContext and JSStoreDynamicContext operators.
+class DynamicContextAccess final {
+ public:
+  DynamicContextAccess(const Handle<String>& name, uint32_t check_bitset,
+                       const ContextAccess& context_access);
+
+  const Handle<String>& name() const { return name_; }
+  uint32_t check_bitset() const { return check_bitset_; }
+  const ContextAccess& context_access() const { return context_access_; }
+
+  // Indicates that an inline check is disabled.
+  bool RequiresFullCheck() const {
+    return check_bitset() == kFullCheckRequired;
+  }
+
+  // Limit of context chain length to which inline check is possible.
+  static const int kMaxCheckDepth = 30;
+
+  // Sentinel for {check_bitset} disabling inline checks.
+  static const uint32_t kFullCheckRequired = -1;
+
+ private:
+  const Handle<String> name_;
+  const uint32_t check_bitset_;
+  const ContextAccess context_access_;
+};
+
+size_t hash_value(DynamicContextAccess const&);
+
+bool operator==(DynamicContextAccess const&, DynamicContextAccess const&);
+bool operator!=(DynamicContextAccess const&, DynamicContextAccess const&);
+
+std::ostream& operator<<(std::ostream&, DynamicContextAccess const&);
+
+DynamicContextAccess const& DynamicContextAccessOf(Operator const*);
+
+
 class VectorSlotPair {
  public:
   VectorSlotPair(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
@@ -297,6 +375,12 @@ class JSOperatorBuilder final : public ZoneObject {
   const Operator* LoadContext(size_t depth, size_t index, bool immutable);
   const Operator* StoreContext(size_t depth, size_t index);
 
+  const Operator* LoadDynamicGlobal(const Handle<String>& name,
+                                    uint32_t check_bitset, ContextualMode mode);
+  const Operator* LoadDynamicContext(const Handle<String>& name,
+                                     uint32_t check_bitset, size_t depth,
+                                     size_t index);
+
   const Operator* TypeOf();
   const Operator* InstanceOf();
 
index bcc199409f67def301aed0cb782e5ec4a495ac30..4a1e85f2acb792d45eb46229b9013bc42942d048 100644 (file)
 #define JS_CONTEXT_OP_LIST(V) \
   V(JSLoadContext)            \
   V(JSStoreContext)           \
+  V(JSLoadDynamicGlobal)      \
+  V(JSLoadDynamicContext)     \
   V(JSCreateFunctionContext)  \
   V(JSCreateCatchContext)     \
   V(JSCreateWithContext)      \
index ed926a7812bd9862f92ec81a5e0c82dc54834c46..01acf0f7182152dba66c4980ec3ce44171174ac7 100644 (file)
@@ -49,6 +49,8 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
     case IrOpcode::kJSCreateLiteralObject:
 
     // Context operations
+    case IrOpcode::kJSLoadDynamicGlobal:
+    case IrOpcode::kJSLoadDynamicContext:
     case IrOpcode::kJSCreateScriptContext:
     case IrOpcode::kJSCreateWithContext:
 
index 782c8e3352a2c09b43936b573d6826656b70ad07..83d444ccfdf8c22af9f4fe17554bbf50e7eab7a2 100644 (file)
@@ -1506,6 +1506,16 @@ Bounds Typer::Visitor::TypeJSStoreContext(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeJSLoadDynamicGlobal(Node* node) {
+  return Bounds::Unbounded(zone());
+}
+
+
+Bounds Typer::Visitor::TypeJSLoadDynamicContext(Node* node) {
+  return Bounds::Unbounded(zone());
+}
+
+
 Bounds Typer::Visitor::WrapContextBoundsForInput(Node* node) {
   Bounds outer = BoundsOrNone(NodeProperties::GetContextInput(node));
   if (outer.upper->Is(Type::None())) {
index 6ea52b00bc1d6c5caf59f5d0d977bab95537fba9..4e8c23a2873a788666d87b118e53216458636a10 100644 (file)
@@ -531,6 +531,8 @@ void Verifier::Visitor::Check(Node* node) {
       break;
 
     case IrOpcode::kJSLoadContext:
+    case IrOpcode::kJSLoadDynamicGlobal:
+    case IrOpcode::kJSLoadDynamicContext:
       // Type can be anything.
       CheckUpperIs(node, Type::Any());
       break;