Home | History | Annotate | Download | only in compiler
      1 // Copyright 2016 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/js-create-lowering.h"
      6 #include "src/code-factory.h"
      7 #include "src/compiler/access-builder.h"
      8 #include "src/compiler/js-graph.h"
      9 #include "src/compiler/js-operator.h"
     10 #include "src/compiler/machine-operator.h"
     11 #include "src/compiler/node-properties.h"
     12 #include "src/compiler/operator-properties.h"
     13 #include "src/isolate-inl.h"
     14 #include "test/unittests/compiler/compiler-test-utils.h"
     15 #include "test/unittests/compiler/graph-unittest.h"
     16 #include "test/unittests/compiler/node-test-utils.h"
     17 #include "testing/gmock-support.h"
     18 
     19 using testing::_;
     20 using testing::BitEq;
     21 using testing::IsNaN;
     22 
     23 namespace v8 {
     24 namespace internal {
     25 namespace compiler {
     26 
     27 class JSCreateLoweringTest : public TypedGraphTest {
     28  public:
     29   JSCreateLoweringTest()
     30       : TypedGraphTest(3), javascript_(zone()), deps_(isolate(), zone()) {}
     31   ~JSCreateLoweringTest() override {}
     32 
     33  protected:
     34   Reduction Reduce(Node* node) {
     35     MachineOperatorBuilder machine(zone());
     36     SimplifiedOperatorBuilder simplified(zone());
     37     JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
     38                     &machine);
     39     // TODO(titzer): mock the GraphReducer here for better unit testing.
     40     GraphReducer graph_reducer(zone(), graph());
     41     JSCreateLowering reducer(&graph_reducer, &deps_, &jsgraph,
     42                              MaybeHandle<LiteralsArray>(), zone());
     43     return reducer.Reduce(node);
     44   }
     45 
     46   Node* FrameState(Handle<SharedFunctionInfo> shared, Node* outer_frame_state) {
     47     Node* state_values = graph()->NewNode(common()->StateValues(0));
     48     return graph()->NewNode(
     49         common()->FrameState(
     50             BailoutId::None(), OutputFrameStateCombine::Ignore(),
     51             common()->CreateFrameStateFunctionInfo(
     52                 FrameStateType::kJavaScriptFunction, 1, 0, shared)),
     53         state_values, state_values, state_values, NumberConstant(0),
     54         UndefinedConstant(), outer_frame_state);
     55   }
     56 
     57   JSOperatorBuilder* javascript() { return &javascript_; }
     58 
     59  private:
     60   JSOperatorBuilder javascript_;
     61   CompilationDependencies deps_;
     62 };
     63 
     64 TEST_F(JSCreateLoweringTest, JSCreate) {
     65   Handle<JSFunction> function = isolate()->object_function();
     66   Node* const target = Parameter(Type::Constant(function, graph()->zone()));
     67   Node* const context = Parameter(Type::Any());
     68   Node* const effect = graph()->start();
     69   Reduction r = Reduce(graph()->NewNode(javascript()->Create(), target, target,
     70                                         context, EmptyFrameState(), effect));
     71   ASSERT_TRUE(r.Changed());
     72   EXPECT_THAT(
     73       r.replacement(),
     74       IsFinishRegion(
     75           IsAllocate(IsNumberConstant(function->initial_map()->instance_size()),
     76                      IsBeginRegion(effect), _),
     77           _));
     78 }
     79 
     80 // -----------------------------------------------------------------------------
     81 // JSCreateArguments
     82 
     83 TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedMapped) {
     84   Node* const closure = Parameter(Type::Any());
     85   Node* const context = UndefinedConstant();
     86   Node* const effect = graph()->start();
     87   Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
     88   Node* const frame_state_outer = FrameState(shared, graph()->start());
     89   Node* const frame_state_inner = FrameState(shared, frame_state_outer);
     90   Reduction r = Reduce(graph()->NewNode(
     91       javascript()->CreateArguments(CreateArgumentsType::kMappedArguments),
     92       closure, context, frame_state_inner, effect));
     93   ASSERT_TRUE(r.Changed());
     94   EXPECT_THAT(
     95       r.replacement(),
     96       IsFinishRegion(
     97           IsAllocate(IsNumberConstant(JSSloppyArgumentsObject::kSize), _, _),
     98           _));
     99 }
    100 
    101 TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedUnmapped) {
    102   Node* const closure = Parameter(Type::Any());
    103   Node* const context = UndefinedConstant();
    104   Node* const effect = graph()->start();
    105   Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
    106   Node* const frame_state_outer = FrameState(shared, graph()->start());
    107   Node* const frame_state_inner = FrameState(shared, frame_state_outer);
    108   Reduction r = Reduce(graph()->NewNode(
    109       javascript()->CreateArguments(CreateArgumentsType::kUnmappedArguments),
    110       closure, context, frame_state_inner, effect));
    111   ASSERT_TRUE(r.Changed());
    112   EXPECT_THAT(
    113       r.replacement(),
    114       IsFinishRegion(
    115           IsAllocate(IsNumberConstant(JSStrictArgumentsObject::kSize), _, _),
    116           _));
    117 }
    118 
    119 TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedRestArray) {
    120   Node* const closure = Parameter(Type::Any());
    121   Node* const context = UndefinedConstant();
    122   Node* const effect = graph()->start();
    123   Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
    124   Node* const frame_state_outer = FrameState(shared, graph()->start());
    125   Node* const frame_state_inner = FrameState(shared, frame_state_outer);
    126   Reduction r = Reduce(graph()->NewNode(
    127       javascript()->CreateArguments(CreateArgumentsType::kRestParameter),
    128       closure, context, frame_state_inner, effect));
    129   ASSERT_TRUE(r.Changed());
    130   EXPECT_THAT(
    131       r.replacement(),
    132       IsFinishRegion(IsAllocate(IsNumberConstant(JSArray::kSize), _, _), _));
    133 }
    134 
    135 // -----------------------------------------------------------------------------
    136 // JSCreateClosure
    137 
    138 TEST_F(JSCreateLoweringTest, JSCreateClosureViaInlinedAllocation) {
    139   Node* const context = UndefinedConstant();
    140   Node* const effect = graph()->start();
    141   Node* const control = graph()->start();
    142   Handle<SharedFunctionInfo> shared(isolate()->number_function()->shared());
    143   Reduction r =
    144       Reduce(graph()->NewNode(javascript()->CreateClosure(shared, NOT_TENURED),
    145                               context, effect, control));
    146   ASSERT_TRUE(r.Changed());
    147   EXPECT_THAT(r.replacement(),
    148               IsFinishRegion(IsAllocate(IsNumberConstant(JSFunction::kSize),
    149                                         IsBeginRegion(_), control),
    150                              _));
    151 }
    152 
    153 // -----------------------------------------------------------------------------
    154 // JSCreateFunctionContext
    155 
    156 TEST_F(JSCreateLoweringTest, JSCreateFunctionContextViaInlinedAllocation) {
    157   Node* const closure = Parameter(Type::Any());
    158   Node* const context = Parameter(Type::Any());
    159   Node* const effect = graph()->start();
    160   Node* const control = graph()->start();
    161   Reduction const r =
    162       Reduce(graph()->NewNode(javascript()->CreateFunctionContext(8), closure,
    163                               context, effect, control));
    164   ASSERT_TRUE(r.Changed());
    165   EXPECT_THAT(r.replacement(),
    166               IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
    167                                             8 + Context::MIN_CONTEXT_SLOTS)),
    168                                         IsBeginRegion(_), control),
    169                              _));
    170 }
    171 
    172 // -----------------------------------------------------------------------------
    173 // JSCreateWithContext
    174 
    175 TEST_F(JSCreateLoweringTest, JSCreateWithContext) {
    176   Node* const object = Parameter(Type::Receiver());
    177   Node* const closure = Parameter(Type::Function());
    178   Node* const context = Parameter(Type::Any());
    179   Node* const effect = graph()->start();
    180   Node* const control = graph()->start();
    181   Reduction r =
    182       Reduce(graph()->NewNode(javascript()->CreateWithContext(), object,
    183                               closure, context, effect, control));
    184   ASSERT_TRUE(r.Changed());
    185   EXPECT_THAT(r.replacement(),
    186               IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
    187                                             Context::MIN_CONTEXT_SLOTS)),
    188                                         IsBeginRegion(_), control),
    189                              _));
    190 }
    191 
    192 // -----------------------------------------------------------------------------
    193 // JSCreateCatchContext
    194 
    195 TEST_F(JSCreateLoweringTest, JSCreateCatchContext) {
    196   Handle<String> name = factory()->length_string();
    197   Node* const exception = Parameter(Type::Receiver());
    198   Node* const closure = Parameter(Type::Function());
    199   Node* const context = Parameter(Type::Any());
    200   Node* const effect = graph()->start();
    201   Node* const control = graph()->start();
    202   Reduction r =
    203       Reduce(graph()->NewNode(javascript()->CreateCatchContext(name), exception,
    204                               closure, context, effect, control));
    205   ASSERT_TRUE(r.Changed());
    206   EXPECT_THAT(r.replacement(),
    207               IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
    208                                             Context::MIN_CONTEXT_SLOTS + 1)),
    209                                         IsBeginRegion(_), control),
    210                              _));
    211 }
    212 
    213 }  // namespace compiler
    214 }  // namespace internal
    215 }  // namespace v8
    216