LCOV - code coverage report
Current view: top level - test/cctest/compiler - test-js-context-specialization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 298 298 100.0 %
Date: 2017-10-20 Functions: 19 19 100.0 %

          Line data    Source code
       1             : // Copyright 2014 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler/compiler-source-position-table.h"
       6             : #include "src/compiler/js-context-specialization.h"
       7             : #include "src/compiler/js-graph.h"
       8             : #include "src/compiler/js-operator.h"
       9             : #include "src/compiler/node-matchers.h"
      10             : #include "src/compiler/node-properties.h"
      11             : #include "src/factory.h"
      12             : #include "src/objects-inl.h"
      13             : #include "src/property.h"
      14             : #include "test/cctest/cctest.h"
      15             : #include "test/cctest/compiler/function-tester.h"
      16             : #include "test/cctest/compiler/graph-builder-tester.h"
      17             : 
      18             : namespace v8 {
      19             : namespace internal {
      20             : namespace compiler {
      21             : 
      22          96 : class ContextSpecializationTester : public HandleAndZoneScope {
      23             :  public:
      24         144 :   explicit ContextSpecializationTester(Maybe<OuterContext> context)
      25          48 :       : graph_(new (main_zone()) Graph(main_zone())),
      26             :         common_(main_zone()),
      27             :         javascript_(main_zone()),
      28             :         machine_(main_zone()),
      29             :         simplified_(main_zone()),
      30             :         jsgraph_(main_isolate(), graph(), common(), &javascript_, &simplified_,
      31             :                  &machine_),
      32             :         reducer_(main_zone(), graph()),
      33         432 :         spec_(&reducer_, jsgraph(), context, MaybeHandle<JSFunction>()) {}
      34             : 
      35             :   JSContextSpecialization* spec() { return &spec_; }
      36         132 :   Factory* factory() { return main_isolate()->factory(); }
      37             :   CommonOperatorBuilder* common() { return &common_; }
      38             :   JSOperatorBuilder* javascript() { return &javascript_; }
      39             :   SimplifiedOperatorBuilder* simplified() { return &simplified_; }
      40             :   JSGraph* jsgraph() { return &jsgraph_; }
      41             :   Graph* graph() { return graph_; }
      42             : 
      43             :   void CheckChangesToValue(Node* node, Handle<HeapObject> expected_value);
      44             :   void CheckContextInputAndDepthChanges(
      45             :       Node* node, Handle<Context> expected_new_context_object,
      46             :       size_t expected_new_depth);
      47             :   void CheckContextInputAndDepthChanges(Node* node, Node* expected_new_context,
      48             :                                         size_t expected_new_depth);
      49             : 
      50             :  private:
      51             :   Graph* graph_;
      52             :   CommonOperatorBuilder common_;
      53             :   JSOperatorBuilder javascript_;
      54             :   MachineOperatorBuilder machine_;
      55             :   SimplifiedOperatorBuilder simplified_;
      56             :   JSGraph jsgraph_;
      57             :   GraphReducer reducer_;
      58             :   JSContextSpecialization spec_;
      59             : };
      60             : 
      61          24 : void ContextSpecializationTester::CheckChangesToValue(
      62             :     Node* node, Handle<HeapObject> expected_value) {
      63          24 :   Reduction r = spec()->Reduce(node);
      64          24 :   CHECK(r.Changed());
      65             :   HeapObjectMatcher match(r.replacement());
      66          24 :   CHECK(match.HasValue());
      67          24 :   CHECK_EQ(*match.Value(), *expected_value);
      68          24 : }
      69             : 
      70          36 : void ContextSpecializationTester::CheckContextInputAndDepthChanges(
      71             :     Node* node, Handle<Context> expected_new_context_object,
      72             :     size_t expected_new_depth) {
      73          36 :   ContextAccess access = OpParameter<ContextAccess>(node);
      74          36 :   Reduction r = spec()->Reduce(node);
      75          36 :   CHECK(r.Changed());
      76             : 
      77          36 :   Node* new_context = NodeProperties::GetContextInput(r.replacement());
      78          36 :   CHECK_EQ(IrOpcode::kHeapConstant, new_context->opcode());
      79             :   HeapObjectMatcher match(new_context);
      80          36 :   CHECK_EQ(*match.Value(), *expected_new_context_object);
      81             : 
      82          36 :   ContextAccess new_access = OpParameter<ContextAccess>(r.replacement());
      83          36 :   CHECK_EQ(new_access.depth(), expected_new_depth);
      84          36 :   CHECK_EQ(new_access.index(), access.index());
      85          36 :   CHECK_EQ(new_access.immutable(), access.immutable());
      86          36 : }
      87             : 
      88         102 : void ContextSpecializationTester::CheckContextInputAndDepthChanges(
      89             :     Node* node, Node* expected_new_context, size_t expected_new_depth) {
      90         102 :   ContextAccess access = OpParameter<ContextAccess>(node);
      91         102 :   Reduction r = spec()->Reduce(node);
      92         102 :   CHECK(r.Changed());
      93             : 
      94         102 :   Node* new_context = NodeProperties::GetContextInput(r.replacement());
      95         102 :   CHECK_EQ(new_context, expected_new_context);
      96             : 
      97         102 :   ContextAccess new_access = OpParameter<ContextAccess>(r.replacement());
      98         102 :   CHECK_EQ(new_access.depth(), expected_new_depth);
      99         102 :   CHECK_EQ(new_access.index(), access.index());
     100         102 :   CHECK_EQ(new_access.immutable(), access.immutable());
     101         102 : }
     102             : 
     103             : static const int slot_index = Context::NATIVE_CONTEXT_INDEX;
     104             : 
     105       23724 : TEST(ReduceJSLoadContext0) {
     106           6 :   ContextSpecializationTester t(Nothing<OuterContext>());
     107             : 
     108           6 :   Node* start = t.graph()->NewNode(t.common()->Start(0));
     109           6 :   t.graph()->SetStart(start);
     110             : 
     111             :   // Make a context and initialize it a bit for this test.
     112           6 :   Handle<Context> native = t.factory()->NewNativeContext();
     113           6 :   Handle<Context> subcontext1 = t.factory()->NewNativeContext();
     114           6 :   Handle<Context> subcontext2 = t.factory()->NewNativeContext();
     115             :   subcontext2->set_previous(*subcontext1);
     116             :   subcontext1->set_previous(*native);
     117           6 :   Handle<Object> expected = t.factory()->InternalizeUtf8String("gboy!");
     118             :   const int slot = Context::NATIVE_CONTEXT_INDEX;
     119           6 :   native->set(slot, *expected);
     120             : 
     121           6 :   Node* const_context = t.jsgraph()->Constant(native);
     122           6 :   Node* deep_const_context = t.jsgraph()->Constant(subcontext2);
     123           6 :   Node* param_context = t.graph()->NewNode(t.common()->Parameter(0), start);
     124             : 
     125             :   {
     126             :     // Mutable slot, constant context, depth = 0 => do nothing.
     127             :     Node* load = t.graph()->NewNode(t.javascript()->LoadContext(0, 0, false),
     128           6 :                                     const_context, start);
     129           6 :     Reduction r = t.spec()->Reduce(load);
     130           6 :     CHECK(!r.Changed());
     131             :   }
     132             : 
     133             :   {
     134             :     // Mutable slot, non-constant context, depth = 0 => do nothing.
     135             :     Node* load = t.graph()->NewNode(t.javascript()->LoadContext(0, 0, false),
     136           6 :                                     param_context, start);
     137           6 :     Reduction r = t.spec()->Reduce(load);
     138           6 :     CHECK(!r.Changed());
     139             :   }
     140             : 
     141             :   {
     142             :     // Mutable slot, constant context, depth > 0 => fold-in parent context.
     143             :     Node* load = t.graph()->NewNode(
     144             :         t.javascript()->LoadContext(2, Context::GLOBAL_EVAL_FUN_INDEX, false),
     145           6 :         deep_const_context, start);
     146           6 :     Reduction r = t.spec()->Reduce(load);
     147           6 :     CHECK(r.Changed());
     148           6 :     Node* new_context_input = NodeProperties::GetContextInput(r.replacement());
     149           6 :     CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode());
     150             :     HeapObjectMatcher match(new_context_input);
     151           6 :     CHECK_EQ(*native, *match.Value());
     152           6 :     ContextAccess access = OpParameter<ContextAccess>(r.replacement());
     153          12 :     CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
     154           6 :     CHECK_EQ(0, static_cast<int>(access.depth()));
     155          12 :     CHECK_EQ(false, access.immutable());
     156             :   }
     157             : 
     158             :   {
     159             :     // Immutable slot, constant context, depth = 0 => specialize.
     160             :     Node* load = t.graph()->NewNode(t.javascript()->LoadContext(0, slot, true),
     161           6 :                                     const_context, start);
     162           6 :     Reduction r = t.spec()->Reduce(load);
     163           6 :     CHECK(r.Changed());
     164           6 :     CHECK(r.replacement() != load);
     165             : 
     166             :     HeapObjectMatcher match(r.replacement());
     167           6 :     CHECK(match.HasValue());
     168           6 :     CHECK_EQ(*expected, *match.Value());
     169           6 :   }
     170           6 : }
     171             : 
     172       23724 : TEST(ReduceJSLoadContext1) {
     173             :   // The graph's context chain ends in the incoming context parameter:
     174             :   //
     175             :   //   context2 <-- context1 <-- context0 (= Parameter(0))
     176             : 
     177           6 :   ContextSpecializationTester t(Nothing<OuterContext>());
     178             : 
     179           6 :   Node* start = t.graph()->NewNode(t.common()->Start(0));
     180           6 :   t.graph()->SetStart(start);
     181           6 :   Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
     182             :   const i::compiler::Operator* create_function_context =
     183           6 :       t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
     184             : 
     185           6 :   Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
     186             :   Node* context1 = t.graph()->NewNode(create_function_context, undefined,
     187           6 :                                       context0, start, start);
     188             :   Node* context2 = t.graph()->NewNode(create_function_context, undefined,
     189           6 :                                       context1, start, start);
     190             : 
     191             :   {
     192             :     Node* load = t.graph()->NewNode(
     193           6 :         t.javascript()->LoadContext(0, slot_index, false), context2, start);
     194          12 :     CHECK(!t.spec()->Reduce(load).Changed());
     195             :   }
     196             : 
     197             :   {
     198             :     Node* load = t.graph()->NewNode(
     199           6 :         t.javascript()->LoadContext(0, slot_index, true), context2, start);
     200          12 :     CHECK(!t.spec()->Reduce(load).Changed());
     201             :   }
     202             : 
     203             :   {
     204             :     Node* load = t.graph()->NewNode(
     205           6 :         t.javascript()->LoadContext(1, slot_index, false), context2, start);
     206           6 :     t.CheckContextInputAndDepthChanges(load, context1, 0);
     207             :   }
     208             : 
     209             :   {
     210             :     Node* load = t.graph()->NewNode(
     211           6 :         t.javascript()->LoadContext(1, slot_index, true), context2, start);
     212           6 :     t.CheckContextInputAndDepthChanges(load, context1, 0);
     213             :   }
     214             : 
     215             :   {
     216             :     Node* load = t.graph()->NewNode(
     217           6 :         t.javascript()->LoadContext(2, slot_index, false), context2, start);
     218           6 :     t.CheckContextInputAndDepthChanges(load, context0, 0);
     219             :   }
     220             : 
     221             :   {
     222             :     Node* load = t.graph()->NewNode(
     223           6 :         t.javascript()->LoadContext(2, slot_index, true), context2, start);
     224           6 :     t.CheckContextInputAndDepthChanges(load, context0, 0);
     225             :   }
     226             : 
     227             :   {
     228             :     Node* load = t.graph()->NewNode(
     229           6 :         t.javascript()->LoadContext(3, slot_index, false), context2, start);
     230           6 :     t.CheckContextInputAndDepthChanges(load, context0, 1);
     231             :   }
     232             : 
     233             :   {
     234             :     Node* load = t.graph()->NewNode(
     235           6 :         t.javascript()->LoadContext(3, slot_index, true), context2, start);
     236           6 :     t.CheckContextInputAndDepthChanges(load, context0, 1);
     237           6 :   }
     238           6 : }
     239             : 
     240       23724 : TEST(ReduceJSLoadContext2) {
     241             :   // The graph's context chain ends in a constant context (context_object1),
     242             :   // which has another outer context (context_object0).
     243             :   //
     244             :   //   context2 <-- context1 <-- context0 (= HeapConstant(context_object1))
     245             :   //   context_object1 <~~ context_object0
     246             : 
     247           6 :   ContextSpecializationTester t(Nothing<OuterContext>());
     248             : 
     249           6 :   Node* start = t.graph()->NewNode(t.common()->Start(0));
     250           6 :   t.graph()->SetStart(start);
     251           6 :   Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
     252             :   const i::compiler::Operator* create_function_context =
     253           6 :       t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
     254             : 
     255           6 :   Handle<HeapObject> slot_value0 = t.factory()->InternalizeUtf8String("0");
     256           6 :   Handle<HeapObject> slot_value1 = t.factory()->InternalizeUtf8String("1");
     257             : 
     258           6 :   Handle<Context> context_object0 = t.factory()->NewNativeContext();
     259           6 :   Handle<Context> context_object1 = t.factory()->NewNativeContext();
     260             :   context_object1->set_previous(*context_object0);
     261           6 :   context_object0->set(slot_index, *slot_value0);
     262           6 :   context_object1->set(slot_index, *slot_value1);
     263             : 
     264           6 :   Node* context0 = t.jsgraph()->Constant(context_object1);
     265             :   Node* context1 = t.graph()->NewNode(create_function_context, undefined,
     266           6 :                                       context0, start, start);
     267             :   Node* context2 = t.graph()->NewNode(create_function_context, undefined,
     268           6 :                                       context1, start, start);
     269             : 
     270             :   {
     271             :     Node* load = t.graph()->NewNode(
     272           6 :         t.javascript()->LoadContext(0, slot_index, false), context2, start);
     273          12 :     CHECK(!t.spec()->Reduce(load).Changed());
     274             :   }
     275             : 
     276             :   {
     277             :     Node* load = t.graph()->NewNode(
     278           6 :         t.javascript()->LoadContext(0, slot_index, true), context2, start);
     279          12 :     CHECK(!t.spec()->Reduce(load).Changed());
     280             :   }
     281             : 
     282             :   {
     283             :     Node* load = t.graph()->NewNode(
     284           6 :         t.javascript()->LoadContext(1, slot_index, false), context2, start);
     285           6 :     t.CheckContextInputAndDepthChanges(load, context1, 0);
     286             :   }
     287             : 
     288             :   {
     289             :     Node* load = t.graph()->NewNode(
     290           6 :         t.javascript()->LoadContext(1, slot_index, true), context2, start);
     291           6 :     t.CheckContextInputAndDepthChanges(load, context1, 0);
     292             :   }
     293             : 
     294             :   {
     295             :     Node* load = t.graph()->NewNode(
     296           6 :         t.javascript()->LoadContext(2, slot_index, false), context2, start);
     297           6 :     t.CheckContextInputAndDepthChanges(load, context0, 0);
     298             :   }
     299             : 
     300             :   {
     301             :     Node* load = t.graph()->NewNode(
     302           6 :         t.javascript()->LoadContext(2, slot_index, true), context2, start);
     303           6 :     t.CheckChangesToValue(load, slot_value1);
     304             :   }
     305             : 
     306             :   {
     307             :     Node* load = t.graph()->NewNode(
     308           6 :         t.javascript()->LoadContext(3, slot_index, false), context2, start);
     309           6 :     t.CheckContextInputAndDepthChanges(load, context_object0, 0);
     310             :   }
     311             : 
     312             :   {
     313             :     Node* load = t.graph()->NewNode(
     314           6 :         t.javascript()->LoadContext(3, slot_index, true), context2, start);
     315           6 :     t.CheckChangesToValue(load, slot_value0);
     316           6 :   }
     317           6 : }
     318             : 
     319       23724 : TEST(ReduceJSLoadContext3) {
     320             :   // Like in ReduceJSLoadContext1, the graph's context chain ends in the
     321             :   // incoming context parameter.  However, this time we provide a concrete
     322             :   // context for this parameter as the "specialization context".  We choose
     323             :   // context_object2 from ReduceJSLoadContext2 for this, so almost all test
     324             :   // expectations are the same as in ReduceJSLoadContext2.
     325             : 
     326           6 :   HandleAndZoneScope handle_zone_scope;
     327           6 :   auto factory = handle_zone_scope.main_isolate()->factory();
     328             : 
     329           6 :   Handle<HeapObject> slot_value0 = factory->InternalizeUtf8String("0");
     330           6 :   Handle<HeapObject> slot_value1 = factory->InternalizeUtf8String("1");
     331             : 
     332           6 :   Handle<Context> context_object0 = factory->NewNativeContext();
     333           6 :   Handle<Context> context_object1 = factory->NewNativeContext();
     334             :   context_object1->set_previous(*context_object0);
     335           6 :   context_object0->set(slot_index, *slot_value0);
     336           6 :   context_object1->set(slot_index, *slot_value1);
     337             : 
     338          12 :   ContextSpecializationTester t(Just(OuterContext(context_object1, 0)));
     339             : 
     340           6 :   Node* start = t.graph()->NewNode(t.common()->Start(2));
     341           6 :   t.graph()->SetStart(start);
     342           6 :   Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
     343             :   const i::compiler::Operator* create_function_context =
     344           6 :       t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
     345             : 
     346           6 :   Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
     347             :   Node* context1 = t.graph()->NewNode(create_function_context, undefined,
     348           6 :                                       context0, start, start);
     349             :   Node* context2 = t.graph()->NewNode(create_function_context, undefined,
     350           6 :                                       context1, start, start);
     351             : 
     352             :   {
     353             :     Node* load = t.graph()->NewNode(
     354           6 :         t.javascript()->LoadContext(0, slot_index, false), context2, start);
     355          12 :     CHECK(!t.spec()->Reduce(load).Changed());
     356             :   }
     357             : 
     358             :   {
     359             :     Node* load = t.graph()->NewNode(
     360           6 :         t.javascript()->LoadContext(0, slot_index, true), context2, start);
     361          12 :     CHECK(!t.spec()->Reduce(load).Changed());
     362             :   }
     363             : 
     364             :   {
     365             :     Node* load = t.graph()->NewNode(
     366           6 :         t.javascript()->LoadContext(1, slot_index, false), context2, start);
     367           6 :     t.CheckContextInputAndDepthChanges(load, context1, 0);
     368             :   }
     369             : 
     370             :   {
     371             :     Node* load = t.graph()->NewNode(
     372           6 :         t.javascript()->LoadContext(1, slot_index, true), context2, start);
     373           6 :     t.CheckContextInputAndDepthChanges(load, context1, 0);
     374             :   }
     375             : 
     376             :   {
     377             :     Node* load = t.graph()->NewNode(
     378           6 :         t.javascript()->LoadContext(2, slot_index, false), context2, start);
     379           6 :     t.CheckContextInputAndDepthChanges(load, context_object1, 0);
     380             :   }
     381             : 
     382             :   {
     383             :     Node* load = t.graph()->NewNode(
     384           6 :         t.javascript()->LoadContext(2, slot_index, true), context2, start);
     385           6 :     t.CheckChangesToValue(load, slot_value1);
     386             :   }
     387             : 
     388             :   {
     389             :     Node* load = t.graph()->NewNode(
     390           6 :         t.javascript()->LoadContext(3, slot_index, false), context2, start);
     391           6 :     t.CheckContextInputAndDepthChanges(load, context_object0, 0);
     392             :   }
     393             : 
     394             :   {
     395             :     Node* load = t.graph()->NewNode(
     396           6 :         t.javascript()->LoadContext(3, slot_index, true), context2, start);
     397           6 :     t.CheckChangesToValue(load, slot_value0);
     398           6 :   }
     399           6 : }
     400             : 
     401       23724 : TEST(ReduceJSStoreContext0) {
     402           6 :   ContextSpecializationTester t(Nothing<OuterContext>());
     403             : 
     404           6 :   Node* start = t.graph()->NewNode(t.common()->Start(0));
     405           6 :   t.graph()->SetStart(start);
     406             : 
     407             :   // Make a context and initialize it a bit for this test.
     408           6 :   Handle<Context> native = t.factory()->NewNativeContext();
     409           6 :   Handle<Context> subcontext1 = t.factory()->NewNativeContext();
     410           6 :   Handle<Context> subcontext2 = t.factory()->NewNativeContext();
     411             :   subcontext2->set_previous(*subcontext1);
     412             :   subcontext1->set_previous(*native);
     413           6 :   Handle<Object> expected = t.factory()->InternalizeUtf8String("gboy!");
     414             :   const int slot = Context::NATIVE_CONTEXT_INDEX;
     415           6 :   native->set(slot, *expected);
     416             : 
     417           6 :   Node* const_context = t.jsgraph()->Constant(native);
     418           6 :   Node* deep_const_context = t.jsgraph()->Constant(subcontext2);
     419           6 :   Node* param_context = t.graph()->NewNode(t.common()->Parameter(0), start);
     420             : 
     421             :   {
     422             :     // Mutable slot, constant context, depth = 0 => do nothing.
     423             :     Node* load = t.graph()->NewNode(t.javascript()->StoreContext(0, 0),
     424           6 :                                     const_context, const_context, start, start);
     425           6 :     Reduction r = t.spec()->Reduce(load);
     426           6 :     CHECK(!r.Changed());
     427             :   }
     428             : 
     429             :   {
     430             :     // Mutable slot, non-constant context, depth = 0 => do nothing.
     431             :     Node* load = t.graph()->NewNode(t.javascript()->StoreContext(0, 0),
     432           6 :                                     param_context, param_context, start, start);
     433           6 :     Reduction r = t.spec()->Reduce(load);
     434           6 :     CHECK(!r.Changed());
     435             :   }
     436             : 
     437             :   {
     438             :     // Immutable slot, constant context, depth = 0 => do nothing.
     439             :     Node* load = t.graph()->NewNode(t.javascript()->StoreContext(0, slot),
     440           6 :                                     const_context, const_context, start, start);
     441           6 :     Reduction r = t.spec()->Reduce(load);
     442           6 :     CHECK(!r.Changed());
     443             :   }
     444             : 
     445             :   {
     446             :     // Mutable slot, constant context, depth > 0 => fold-in parent context.
     447             :     Node* load = t.graph()->NewNode(
     448             :         t.javascript()->StoreContext(2, Context::GLOBAL_EVAL_FUN_INDEX),
     449           6 :         deep_const_context, deep_const_context, start, start);
     450           6 :     Reduction r = t.spec()->Reduce(load);
     451           6 :     CHECK(r.Changed());
     452           6 :     Node* new_context_input = NodeProperties::GetContextInput(r.replacement());
     453           6 :     CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode());
     454             :     HeapObjectMatcher match(new_context_input);
     455           6 :     CHECK_EQ(*native, *match.Value());
     456           6 :     ContextAccess access = OpParameter<ContextAccess>(r.replacement());
     457          12 :     CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
     458           6 :     CHECK_EQ(0, static_cast<int>(access.depth()));
     459          12 :     CHECK_EQ(false, access.immutable());
     460           6 :   }
     461           6 : }
     462             : 
     463       23724 : TEST(ReduceJSStoreContext1) {
     464           6 :   ContextSpecializationTester t(Nothing<OuterContext>());
     465             : 
     466           6 :   Node* start = t.graph()->NewNode(t.common()->Start(0));
     467           6 :   t.graph()->SetStart(start);
     468           6 :   Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
     469             :   const i::compiler::Operator* create_function_context =
     470           6 :       t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
     471             : 
     472           6 :   Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
     473             :   Node* context1 = t.graph()->NewNode(create_function_context, undefined,
     474           6 :                                       context0, start, start);
     475             :   Node* context2 = t.graph()->NewNode(create_function_context, undefined,
     476           6 :                                       context1, start, start);
     477             : 
     478             :   {
     479             :     Node* store =
     480             :         t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
     481           6 :                            context2, context2, start, start);
     482          12 :     CHECK(!t.spec()->Reduce(store).Changed());
     483             :   }
     484             : 
     485             :   {
     486             :     Node* store =
     487             :         t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
     488           6 :                            context2, context2, start, start);
     489           6 :     t.CheckContextInputAndDepthChanges(store, context1, 0);
     490             :   }
     491             : 
     492             :   {
     493             :     Node* store =
     494             :         t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
     495           6 :                            context2, context2, start, start);
     496           6 :     t.CheckContextInputAndDepthChanges(store, context0, 0);
     497             :   }
     498             : 
     499             :   {
     500             :     Node* store =
     501             :         t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
     502           6 :                            context2, context2, start, start);
     503           6 :     t.CheckContextInputAndDepthChanges(store, context0, 1);
     504           6 :   }
     505           6 : }
     506             : 
     507       23724 : TEST(ReduceJSStoreContext2) {
     508           6 :   ContextSpecializationTester t(Nothing<OuterContext>());
     509             : 
     510           6 :   Node* start = t.graph()->NewNode(t.common()->Start(0));
     511           6 :   t.graph()->SetStart(start);
     512           6 :   Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
     513             :   const i::compiler::Operator* create_function_context =
     514           6 :       t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
     515             : 
     516           6 :   Handle<HeapObject> slot_value0 = t.factory()->InternalizeUtf8String("0");
     517           6 :   Handle<HeapObject> slot_value1 = t.factory()->InternalizeUtf8String("1");
     518             : 
     519           6 :   Handle<Context> context_object0 = t.factory()->NewNativeContext();
     520           6 :   Handle<Context> context_object1 = t.factory()->NewNativeContext();
     521             :   context_object1->set_previous(*context_object0);
     522           6 :   context_object0->set(slot_index, *slot_value0);
     523           6 :   context_object1->set(slot_index, *slot_value1);
     524             : 
     525           6 :   Node* context0 = t.jsgraph()->Constant(context_object1);
     526             :   Node* context1 = t.graph()->NewNode(create_function_context, undefined,
     527           6 :                                       context0, start, start);
     528             :   Node* context2 = t.graph()->NewNode(create_function_context, undefined,
     529           6 :                                       context1, start, start);
     530             : 
     531             :   {
     532             :     Node* store =
     533             :         t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
     534           6 :                            context2, context2, start, start);
     535          12 :     CHECK(!t.spec()->Reduce(store).Changed());
     536             :   }
     537             : 
     538             :   {
     539             :     Node* store =
     540             :         t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
     541           6 :                            context2, context2, start, start);
     542           6 :     t.CheckContextInputAndDepthChanges(store, context1, 0);
     543             :   }
     544             : 
     545             :   {
     546             :     Node* store =
     547             :         t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
     548           6 :                            context2, context2, start, start);
     549           6 :     t.CheckContextInputAndDepthChanges(store, context0, 0);
     550             :   }
     551             : 
     552             :   {
     553             :     Node* store =
     554             :         t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
     555           6 :                            context2, context2, start, start);
     556           6 :     t.CheckContextInputAndDepthChanges(store, context_object0, 0);
     557           6 :   }
     558           6 : }
     559             : 
     560       23724 : TEST(ReduceJSStoreContext3) {
     561           6 :   HandleAndZoneScope handle_zone_scope;
     562           6 :   auto factory = handle_zone_scope.main_isolate()->factory();
     563             : 
     564           6 :   Handle<HeapObject> slot_value0 = factory->InternalizeUtf8String("0");
     565           6 :   Handle<HeapObject> slot_value1 = factory->InternalizeUtf8String("1");
     566             : 
     567           6 :   Handle<Context> context_object0 = factory->NewNativeContext();
     568           6 :   Handle<Context> context_object1 = factory->NewNativeContext();
     569             :   context_object1->set_previous(*context_object0);
     570           6 :   context_object0->set(slot_index, *slot_value0);
     571           6 :   context_object1->set(slot_index, *slot_value1);
     572             : 
     573          12 :   ContextSpecializationTester t(Just(OuterContext(context_object1, 0)));
     574             : 
     575           6 :   Node* start = t.graph()->NewNode(t.common()->Start(2));
     576           6 :   t.graph()->SetStart(start);
     577           6 :   Node* undefined = t.jsgraph()->Constant(t.factory()->undefined_value());
     578             :   const i::compiler::Operator* create_function_context =
     579           6 :       t.javascript()->CreateFunctionContext(42, FUNCTION_SCOPE);
     580             : 
     581           6 :   Node* context0 = t.graph()->NewNode(t.common()->Parameter(0), start);
     582             :   Node* context1 = t.graph()->NewNode(create_function_context, undefined,
     583           6 :                                       context0, start, start);
     584             :   Node* context2 = t.graph()->NewNode(create_function_context, undefined,
     585           6 :                                       context1, start, start);
     586             : 
     587             :   {
     588             :     Node* store =
     589             :         t.graph()->NewNode(t.javascript()->StoreContext(0, slot_index),
     590           6 :                            context2, context2, start, start);
     591          12 :     CHECK(!t.spec()->Reduce(store).Changed());
     592             :   }
     593             : 
     594             :   {
     595             :     Node* store =
     596             :         t.graph()->NewNode(t.javascript()->StoreContext(1, slot_index),
     597           6 :                            context2, context2, start, start);
     598           6 :     t.CheckContextInputAndDepthChanges(store, context1, 0);
     599             :   }
     600             : 
     601             :   {
     602             :     Node* store =
     603             :         t.graph()->NewNode(t.javascript()->StoreContext(2, slot_index),
     604           6 :                            context2, context2, start, start);
     605           6 :     t.CheckContextInputAndDepthChanges(store, context_object1, 0);
     606             :   }
     607             : 
     608             :   {
     609             :     Node* store =
     610             :         t.graph()->NewNode(t.javascript()->StoreContext(3, slot_index),
     611           6 :                            context2, context2, start, start);
     612           6 :     t.CheckContextInputAndDepthChanges(store, context_object0, 0);
     613           6 :   }
     614           6 : }
     615             : 
     616       23724 : TEST(SpecializeJSFunction_ToConstant1) {
     617             :   FunctionTester T(
     618             :       "(function() { var x = 1; function inc(a)"
     619           6 :       " { return a + x; } return inc; })()");
     620             : 
     621           6 :   T.CheckCall(1.0, 0.0, 0.0);
     622           6 :   T.CheckCall(2.0, 1.0, 0.0);
     623           6 :   T.CheckCall(2.1, 1.1, 0.0);
     624           6 : }
     625             : 
     626             : 
     627       23724 : TEST(SpecializeJSFunction_ToConstant2) {
     628             :   FunctionTester T(
     629             :       "(function() { var x = 1.5; var y = 2.25; var z = 3.75;"
     630           6 :       " function f(a) { return a - x + y - z; } return f; })()");
     631             : 
     632           6 :   T.CheckCall(-3.0, 0.0, 0.0);
     633           6 :   T.CheckCall(-2.0, 1.0, 0.0);
     634           6 :   T.CheckCall(-1.9, 1.1, 0.0);
     635           6 : }
     636             : 
     637             : 
     638       23724 : TEST(SpecializeJSFunction_ToConstant3) {
     639             :   FunctionTester T(
     640             :       "(function() { var x = -11.5; function inc()"
     641             :       " { return (function(a) { return a + x; }); }"
     642           6 :       " return inc(); })()");
     643             : 
     644           6 :   T.CheckCall(-11.5, 0.0, 0.0);
     645           6 :   T.CheckCall(-10.5, 1.0, 0.0);
     646           6 :   T.CheckCall(-10.4, 1.1, 0.0);
     647           6 : }
     648             : 
     649             : 
     650       23724 : TEST(SpecializeJSFunction_ToConstant_uninit) {
     651             :   {
     652             :     FunctionTester T(
     653             :         "(function() { if (false) { var x = 1; } function inc(a)"
     654           6 :         " { return x; } return inc; })()");  // x is undefined!
     655             :     i::Isolate* isolate = CcTest::i_isolate();
     656          12 :     CHECK(
     657             :         T.Call(T.Val(0.0), T.Val(0.0)).ToHandleChecked()->IsUndefined(isolate));
     658          12 :     CHECK(
     659             :         T.Call(T.Val(2.0), T.Val(0.0)).ToHandleChecked()->IsUndefined(isolate));
     660          12 :     CHECK(T.Call(T.Val(-2.1), T.Val(0.0))
     661             :               .ToHandleChecked()
     662             :               ->IsUndefined(isolate));
     663             :   }
     664             : 
     665             :   {
     666             :     FunctionTester T(
     667             :         "(function() { if (false) { var x = 1; } function inc(a)"
     668           6 :         " { return a + x; } return inc; })()");  // x is undefined!
     669             : 
     670          12 :     CHECK(T.Call(T.Val(0.0), T.Val(0.0)).ToHandleChecked()->IsNaN());
     671          12 :     CHECK(T.Call(T.Val(2.0), T.Val(0.0)).ToHandleChecked()->IsNaN());
     672          12 :     CHECK(T.Call(T.Val(-2.1), T.Val(0.0)).ToHandleChecked()->IsNaN());
     673             :   }
     674           6 : }
     675             : 
     676             : }  // namespace compiler
     677             : }  // namespace internal
     678       71154 : }  // namespace v8

Generated by: LCOV version 1.10