LCOV - code coverage report
Current view: top level - test/unittests/compiler - bytecode-analysis-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 219 221 99.1 %
Date: 2017-10-20 Functions: 44 46 95.7 %

          Line data    Source code
       1             : // Copyright 2015 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/v8.h"
       6             : 
       7             : #include "src/compiler/bytecode-analysis.h"
       8             : #include "src/interpreter/bytecode-array-builder.h"
       9             : #include "src/interpreter/bytecode-array-iterator.h"
      10             : #include "src/interpreter/bytecode-decoder.h"
      11             : #include "src/interpreter/bytecode-label.h"
      12             : #include "src/interpreter/control-flow-builders.h"
      13             : #include "src/objects-inl.h"
      14             : #include "test/unittests/test-utils.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : namespace compiler {
      19             : 
      20             : using ToBooleanMode = interpreter::BytecodeArrayBuilder::ToBooleanMode;
      21             : 
      22             : class BytecodeAnalysisTest : public TestWithIsolateAndZone {
      23             :  public:
      24           9 :   BytecodeAnalysisTest() {}
      25           9 :   ~BytecodeAnalysisTest() override {}
      26             : 
      27           9 :   static void SetUpTestCase() {
      28           9 :     CHECK_NULL(save_flags_);
      29           9 :     save_flags_ = new SaveFlags();
      30           9 :     i::FLAG_ignition_elide_noneffectful_bytecodes = false;
      31           9 :     i::FLAG_ignition_reo = false;
      32             : 
      33           9 :     TestWithIsolateAndZone::SetUpTestCase();
      34           9 :   }
      35             : 
      36           9 :   static void TearDownTestCase() {
      37           9 :     TestWithIsolateAndZone::TearDownTestCase();
      38           9 :     delete save_flags_;
      39           9 :     save_flags_ = nullptr;
      40           9 :   }
      41             : 
      42         108 :   std::string ToLivenessString(const BytecodeLivenessState* liveness) const {
      43         648 :     const BitVector& bit_vector = liveness->bit_vector();
      44             : 
      45             :     std::string out;
      46         108 :     out.resize(bit_vector.length());
      47        1080 :     for (int i = 0; i < bit_vector.length(); ++i) {
      48         432 :       if (bit_vector.Contains(i)) {
      49         316 :         out[i] = 'L';
      50             :       } else {
      51         548 :         out[i] = '.';
      52             :       }
      53             :     }
      54         108 :     return out;
      55             :   }
      56             : 
      57           9 :   void EnsureLivenessMatches(
      58             :       Handle<BytecodeArray> bytecode,
      59             :       const std::vector<std::pair<std::string, std::string>>&
      60             :           expected_liveness) {
      61           9 :     BytecodeAnalysis analysis(bytecode, zone(), true);
      62           9 :     analysis.Analyze(BailoutId::None());
      63             : 
      64           9 :     interpreter::BytecodeArrayIterator iterator(bytecode);
      65          72 :     for (auto liveness : expected_liveness) {
      66         108 :       std::stringstream ss;
      67         108 :       ss << std::setw(4) << iterator.current_offset() << " : ";
      68          54 :       iterator.PrintTo(ss);
      69             : 
      70         108 :       EXPECT_EQ(liveness.first, ToLivenessString(analysis.GetInLivenessFor(
      71             :                                     iterator.current_offset())))
      72           0 :           << " at bytecode " << ss.str();
      73             : 
      74         108 :       EXPECT_EQ(liveness.second, ToLivenessString(analysis.GetOutLivenessFor(
      75             :                                      iterator.current_offset())))
      76           0 :           << " at bytecode " << ss.str();
      77             : 
      78          54 :       iterator.Advance();
      79          54 :     }
      80             : 
      81          27 :     EXPECT_TRUE(iterator.done());
      82           9 :   }
      83             : 
      84             :  private:
      85             :   static SaveFlags* save_flags_;
      86             : 
      87             :   DISALLOW_COPY_AND_ASSIGN(BytecodeAnalysisTest);
      88             : };
      89             : 
      90             : SaveFlags* BytecodeAnalysisTest::save_flags_ = nullptr;
      91             : 
      92       13160 : TEST_F(BytecodeAnalysisTest, EmptyBlock) {
      93           2 :   interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 3);
      94           1 :   std::vector<std::pair<std::string, std::string>> expected_liveness;
      95             : 
      96             :   interpreter::Register reg_0(0);
      97             : 
      98           1 :   builder.Return();
      99           1 :   expected_liveness.emplace_back("...L", "....");
     100             : 
     101           1 :   Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate());
     102             : 
     103           1 :   EnsureLivenessMatches(bytecode, expected_liveness);
     104           1 : }
     105             : 
     106       13160 : TEST_F(BytecodeAnalysisTest, SimpleLoad) {
     107           2 :   interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 3);
     108           1 :   std::vector<std::pair<std::string, std::string>> expected_liveness;
     109             : 
     110             :   interpreter::Register reg_0(0);
     111             : 
     112           1 :   builder.LoadAccumulatorWithRegister(reg_0);
     113           1 :   expected_liveness.emplace_back("L...", "...L");
     114             : 
     115           1 :   builder.Return();
     116           1 :   expected_liveness.emplace_back("...L", "....");
     117             : 
     118           1 :   Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate());
     119             : 
     120           1 :   EnsureLivenessMatches(bytecode, expected_liveness);
     121           1 : }
     122             : 
     123       13160 : TEST_F(BytecodeAnalysisTest, StoreThenLoad) {
     124           2 :   interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 3);
     125           1 :   std::vector<std::pair<std::string, std::string>> expected_liveness;
     126             : 
     127             :   interpreter::Register reg_0(0);
     128             : 
     129           1 :   builder.StoreAccumulatorInRegister(reg_0);
     130           1 :   expected_liveness.emplace_back("...L", "L...");
     131             : 
     132           1 :   builder.LoadAccumulatorWithRegister(reg_0);
     133           1 :   expected_liveness.emplace_back("L...", "...L");
     134             : 
     135           1 :   builder.Return();
     136           1 :   expected_liveness.emplace_back("...L", "....");
     137             : 
     138           1 :   Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate());
     139             : 
     140           1 :   EnsureLivenessMatches(bytecode, expected_liveness);
     141           1 : }
     142             : 
     143       13160 : TEST_F(BytecodeAnalysisTest, DiamondLoad) {
     144           2 :   interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 3);
     145           1 :   std::vector<std::pair<std::string, std::string>> expected_liveness;
     146             : 
     147             :   interpreter::Register reg_0(0);
     148             :   interpreter::Register reg_1(1);
     149             :   interpreter::Register reg_2(2);
     150             : 
     151             :   interpreter::BytecodeLabel ld1_label;
     152             :   interpreter::BytecodeLabel end_label;
     153             : 
     154           1 :   builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &ld1_label);
     155           1 :   expected_liveness.emplace_back("LLLL", "LLL.");
     156             : 
     157           1 :   builder.LoadAccumulatorWithRegister(reg_0);
     158           1 :   expected_liveness.emplace_back("L.L.", "..L.");
     159             : 
     160           1 :   builder.Jump(&end_label);
     161           1 :   expected_liveness.emplace_back("..L.", "..L.");
     162             : 
     163           1 :   builder.Bind(&ld1_label);
     164           1 :   builder.LoadAccumulatorWithRegister(reg_1);
     165           1 :   expected_liveness.emplace_back(".LL.", "..L.");
     166             : 
     167           1 :   builder.Bind(&end_label);
     168             : 
     169           1 :   builder.LoadAccumulatorWithRegister(reg_2);
     170           1 :   expected_liveness.emplace_back("..L.", "...L");
     171             : 
     172           1 :   builder.Return();
     173           1 :   expected_liveness.emplace_back("...L", "....");
     174             : 
     175           1 :   Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate());
     176             : 
     177           1 :   EnsureLivenessMatches(bytecode, expected_liveness);
     178           1 : }
     179             : 
     180       13160 : TEST_F(BytecodeAnalysisTest, DiamondLookupsAndBinds) {
     181           2 :   interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 3);
     182           1 :   std::vector<std::pair<std::string, std::string>> expected_liveness;
     183             : 
     184             :   interpreter::Register reg_0(0);
     185             :   interpreter::Register reg_1(1);
     186             :   interpreter::Register reg_2(2);
     187             : 
     188             :   interpreter::BytecodeLabel ld1_label;
     189             :   interpreter::BytecodeLabel end_label;
     190             : 
     191           1 :   builder.StoreAccumulatorInRegister(reg_0);
     192           1 :   expected_liveness.emplace_back(".LLL", "LLLL");
     193             : 
     194           1 :   builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &ld1_label);
     195           1 :   expected_liveness.emplace_back("LLLL", "LLL.");
     196             : 
     197             :   {
     198           1 :     builder.LoadAccumulatorWithRegister(reg_0);
     199           1 :     expected_liveness.emplace_back("L...", "...L");
     200             : 
     201           1 :     builder.StoreAccumulatorInRegister(reg_2);
     202           1 :     expected_liveness.emplace_back("...L", "..L.");
     203             : 
     204           1 :     builder.Jump(&end_label);
     205           1 :     expected_liveness.emplace_back("..L.", "..L.");
     206             :   }
     207             : 
     208           1 :   builder.Bind(&ld1_label);
     209             :   {
     210           1 :     builder.LoadAccumulatorWithRegister(reg_1);
     211           1 :     expected_liveness.emplace_back(".LL.", "..L.");
     212             :   }
     213             : 
     214           1 :   builder.Bind(&end_label);
     215             : 
     216           1 :   builder.LoadAccumulatorWithRegister(reg_2);
     217           1 :   expected_liveness.emplace_back("..L.", "...L");
     218             : 
     219           1 :   builder.Return();
     220           1 :   expected_liveness.emplace_back("...L", "....");
     221             : 
     222           1 :   Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate());
     223             : 
     224           1 :   EnsureLivenessMatches(bytecode, expected_liveness);
     225           1 : }
     226             : 
     227       13160 : TEST_F(BytecodeAnalysisTest, SimpleLoop) {
     228           2 :   interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 3);
     229           1 :   std::vector<std::pair<std::string, std::string>> expected_liveness;
     230             : 
     231             :   interpreter::Register reg_0(0);
     232             :   interpreter::Register reg_1(1);
     233             :   interpreter::Register reg_2(2);
     234             : 
     235             :   // Kill r0.
     236           1 :   builder.StoreAccumulatorInRegister(reg_0);
     237           1 :   expected_liveness.emplace_back("..LL", "L.L.");
     238             : 
     239             :   {
     240           1 :     interpreter::LoopBuilder loop_builder(&builder, nullptr, nullptr);
     241           1 :     loop_builder.LoopHeader();
     242             : 
     243           1 :     builder.LoadUndefined();
     244           1 :     expected_liveness.emplace_back("L.L.", "L.LL");
     245             : 
     246             :     builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean,
     247           1 :                        loop_builder.break_labels()->New());
     248           1 :     expected_liveness.emplace_back("L.LL", "L.L.");
     249             : 
     250             :     // Gen r0.
     251           1 :     builder.LoadAccumulatorWithRegister(reg_0);
     252           1 :     expected_liveness.emplace_back("L...", "L..L");
     253             : 
     254             :     // Kill r2.
     255           1 :     builder.StoreAccumulatorInRegister(reg_2);
     256           1 :     expected_liveness.emplace_back("L..L", "L.L.");
     257             : 
     258           1 :     loop_builder.BindContinueTarget();
     259           1 :     loop_builder.JumpToHeader(0);
     260           1 :     expected_liveness.emplace_back("L.L.", "L.L.");
     261             :   }
     262             : 
     263             :   // Gen r2.
     264           1 :   builder.LoadAccumulatorWithRegister(reg_2);
     265           1 :   expected_liveness.emplace_back("..L.", "...L");
     266             : 
     267           1 :   builder.Return();
     268           1 :   expected_liveness.emplace_back("...L", "....");
     269             : 
     270           1 :   Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate());
     271             : 
     272           1 :   EnsureLivenessMatches(bytecode, expected_liveness);
     273           1 : }
     274             : 
     275       13160 : TEST_F(BytecodeAnalysisTest, TryCatch) {
     276           2 :   interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 3);
     277           1 :   std::vector<std::pair<std::string, std::string>> expected_liveness;
     278             : 
     279             :   interpreter::Register reg_0(0);
     280             :   interpreter::Register reg_1(1);
     281             :   interpreter::Register reg_context(2);
     282             : 
     283             :   // Kill r0.
     284           1 :   builder.StoreAccumulatorInRegister(reg_0);
     285           1 :   expected_liveness.emplace_back(".LLL", "LLL.");
     286             : 
     287             :   interpreter::TryCatchBuilder try_builder(&builder, HandlerTable::CAUGHT);
     288           1 :   try_builder.BeginTry(reg_context);
     289             :   {
     290             :     // Gen r0.
     291           1 :     builder.LoadAccumulatorWithRegister(reg_0);
     292           1 :     expected_liveness.emplace_back("LLL.", ".LLL");
     293             : 
     294             :     // Kill r0.
     295           1 :     builder.StoreAccumulatorInRegister(reg_0);
     296           1 :     expected_liveness.emplace_back(".LLL", ".LL.");
     297             : 
     298           1 :     builder.CallRuntime(Runtime::kThrow);
     299           1 :     expected_liveness.emplace_back(".LL.", ".LLL");
     300             : 
     301           1 :     builder.StoreAccumulatorInRegister(reg_0);
     302             :     // Star can't throw, so doesn't take handler liveness
     303           1 :     expected_liveness.emplace_back("...L", "...L");
     304             :   }
     305           1 :   try_builder.EndTry();
     306           1 :   expected_liveness.emplace_back("...L", "...L");
     307             : 
     308             :   // Catch
     309             :   {
     310           1 :     builder.LoadAccumulatorWithRegister(reg_1);
     311           1 :     expected_liveness.emplace_back(".L..", "...L");
     312             :   }
     313           1 :   try_builder.EndCatch();
     314             : 
     315           1 :   builder.Return();
     316           1 :   expected_liveness.emplace_back("...L", "....");
     317             : 
     318           1 :   Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate());
     319             : 
     320           1 :   EnsureLivenessMatches(bytecode, expected_liveness);
     321           1 : }
     322             : 
     323       13160 : TEST_F(BytecodeAnalysisTest, DiamondInLoop) {
     324             :   // For a logic diamond inside a loop, the liveness down one path of the
     325             :   // diamond should eventually propagate up the other path when the loop is
     326             :   // reprocessed.
     327             : 
     328           2 :   interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 3);
     329           1 :   std::vector<std::pair<std::string, std::string>> expected_liveness;
     330             : 
     331             :   interpreter::Register reg_0(0);
     332             : 
     333             :   {
     334           1 :     interpreter::LoopBuilder loop_builder(&builder, nullptr, nullptr);
     335           1 :     loop_builder.LoopHeader();
     336             : 
     337           1 :     builder.LoadUndefined();
     338           1 :     expected_liveness.emplace_back("L...", "L..L");
     339             :     builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean,
     340           1 :                        loop_builder.break_labels()->New());
     341           1 :     expected_liveness.emplace_back("L..L", "L..L");
     342             : 
     343             :     interpreter::BytecodeLabel ld1_label;
     344             :     interpreter::BytecodeLabel end_label;
     345           1 :     builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &ld1_label);
     346           1 :     expected_liveness.emplace_back("L..L", "L...");
     347             : 
     348             :     {
     349           1 :       builder.Jump(&end_label);
     350           1 :       expected_liveness.emplace_back("L...", "L...");
     351             :     }
     352             : 
     353           1 :     builder.Bind(&ld1_label);
     354             :     {
     355             :       // Gen r0.
     356           1 :       builder.LoadAccumulatorWithRegister(reg_0);
     357           1 :       expected_liveness.emplace_back("L...", "L...");
     358             :     }
     359             : 
     360           1 :     builder.Bind(&end_label);
     361             : 
     362           1 :     loop_builder.BindContinueTarget();
     363           1 :     loop_builder.JumpToHeader(0);
     364           1 :     expected_liveness.emplace_back("L...", "L...");
     365             :   }
     366             : 
     367           1 :   builder.LoadUndefined();
     368           1 :   expected_liveness.emplace_back("....", "...L");
     369           1 :   builder.Return();
     370           1 :   expected_liveness.emplace_back("...L", "....");
     371             : 
     372           1 :   Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate());
     373             : 
     374           1 :   EnsureLivenessMatches(bytecode, expected_liveness);
     375           1 : }
     376             : 
     377       13160 : TEST_F(BytecodeAnalysisTest, KillingLoopInsideLoop) {
     378             :   // For a loop inside a loop, the inner loop has to be processed after the
     379             :   // outer loop has been processed, to ensure that it can propagate the
     380             :   // information in its header. Consider
     381             :   //
     382             :   //     0: do {
     383             :   //     1:   acc = r0;
     384             :   //     2:   acc = r1;
     385             :   //     3:   do {
     386             :   //     4:     r0 = acc;
     387             :   //     5:     break;
     388             :   //     6:   } while(true);
     389             :   //     7: } while(true);
     390             :   //
     391             :   // r0 should should be dead at 3 and 6, while r1 is live throughout. On the
     392             :   // initial pass, r1 is dead from 3-7. On the outer loop pass, it becomes live
     393             :   // in 3 and 7 (but not 4-6 because 6 only reads liveness from 3). Only after
     394             :   // the inner loop pass does it become live in 4-6. It's necessary, however, to
     395             :   // still process the inner loop when processing the outer loop, to ensure that
     396             :   // r1 becomes live in 3 (via 5), but r0 stays dead (because of 4).
     397             : 
     398           2 :   interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 3);
     399           1 :   std::vector<std::pair<std::string, std::string>> expected_liveness;
     400             : 
     401             :   interpreter::Register reg_0(0);
     402             :   interpreter::Register reg_1(1);
     403             : 
     404             :   {
     405           1 :     interpreter::LoopBuilder loop_builder(&builder, nullptr, nullptr);
     406           1 :     loop_builder.LoopHeader();
     407             : 
     408             :     // Gen r0.
     409           1 :     builder.LoadAccumulatorWithRegister(reg_0);
     410           1 :     expected_liveness.emplace_back("LL..", ".L..");
     411             : 
     412             :     // Gen r1.
     413           1 :     builder.LoadAccumulatorWithRegister(reg_1);
     414           1 :     expected_liveness.emplace_back(".L..", ".L.L");
     415             : 
     416             :     builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean,
     417           1 :                        loop_builder.break_labels()->New());
     418           1 :     expected_liveness.emplace_back(".L.L", ".L..");
     419             : 
     420             :     {
     421           1 :       interpreter::LoopBuilder inner_loop_builder(&builder, nullptr, nullptr);
     422           1 :       inner_loop_builder.LoopHeader();
     423             : 
     424             :       // Kill r0.
     425           1 :       builder.LoadUndefined();
     426           1 :       expected_liveness.emplace_back(".L..", ".L.L");
     427           1 :       builder.StoreAccumulatorInRegister(reg_0);
     428           1 :       expected_liveness.emplace_back(".L.L", "LL.L");
     429             : 
     430             :       builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean,
     431           1 :                          inner_loop_builder.break_labels()->New());
     432           1 :       expected_liveness.emplace_back("LL.L", "LL..");
     433             : 
     434           1 :       inner_loop_builder.BindContinueTarget();
     435           1 :       inner_loop_builder.JumpToHeader(1);
     436           1 :       expected_liveness.emplace_back(".L..", ".L..");
     437             :     }
     438             : 
     439           1 :     loop_builder.BindContinueTarget();
     440           1 :     loop_builder.JumpToHeader(0);
     441           1 :     expected_liveness.emplace_back("LL..", "LL..");
     442             :   }
     443             : 
     444           1 :   builder.LoadUndefined();
     445           1 :   expected_liveness.emplace_back("....", "...L");
     446           1 :   builder.Return();
     447           1 :   expected_liveness.emplace_back("...L", "....");
     448             : 
     449           1 :   Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate());
     450             : 
     451           1 :   EnsureLivenessMatches(bytecode, expected_liveness);
     452           1 : }
     453             : 
     454             : }  // namespace compiler
     455             : }  // namespace internal
     456        7893 : }  // namespace v8

Generated by: LCOV version 1.10