bytecode-array-builder-unittest.cc 5.18 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/v8.h"

#include "src/interpreter/bytecode-array-builder.h"
8
#include "test/unittests/test-utils.h"
9

10 11 12
namespace v8 {
namespace internal {
namespace interpreter {
13

14
class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
15 16 17 18 19 20 21
 public:
  BytecodeArrayBuilderTest() {}
  ~BytecodeArrayBuilderTest() override {}
};


TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
22
  BytecodeArrayBuilder builder(isolate(), zone());
23 24

  builder.set_locals_count(1);
25
  builder.set_parameter_count(0);
26 27 28 29 30
  CHECK_EQ(builder.locals_count(), 1);

  // Emit constant loads.
  builder.LoadLiteral(Smi::FromInt(0))
      .LoadLiteral(Smi::FromInt(8))
31
      .LoadLiteral(Smi::FromInt(10000000))
32 33 34 35 36 37 38
      .LoadUndefined()
      .LoadNull()
      .LoadTheHole()
      .LoadTrue()
      .LoadFalse();

  // Emit accumulator transfers.
39 40
  Register reg(0);
  builder.LoadAccumulatorWithRegister(reg).StoreAccumulatorInRegister(reg);
41 42

  // Emit binary operators invocations.
43 44 45
  builder.BinaryOperation(Token::Value::ADD, reg)
      .BinaryOperation(Token::Value::SUB, reg)
      .BinaryOperation(Token::Value::MUL, reg)
46 47
      .BinaryOperation(Token::Value::DIV, reg)
      .BinaryOperation(Token::Value::MOD, reg);
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

  // Emit control flow. Return must be the last instruction.
  builder.Return();

  // Generate BytecodeArray.
  Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
  CHECK_EQ(the_array->frame_size(), builder.locals_count() * kPointerSize);

  // Build scorecard of bytecodes encountered in the BytecodeArray.
  std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
  Bytecode final_bytecode = Bytecode::kLdaZero;
  for (int i = 0; i < the_array->length(); i++) {
    uint8_t code = the_array->get(i);
    scorecard[code] += 1;
    int operands = Bytecodes::NumberOfOperands(Bytecodes::FromByte(code));
    CHECK_LE(operands, Bytecodes::MaximumNumberOfOperands());
    final_bytecode = Bytecodes::FromByte(code);
    i += operands;
  }

  // Check return occurs at the end and only once in the BytecodeArray.
  CHECK_EQ(final_bytecode, Bytecode::kReturn);
  CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1);

#define CHECK_BYTECODE_PRESENT(Name, ...)     \
  /* Check Bytecode is marked in scorecard */ \
  CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1);
  BYTECODE_LIST(CHECK_BYTECODE_PRESENT)
#undef CHECK_BYTECODE_PRESENT
}


80
TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
oth's avatar
oth committed
81
  for (int locals = 0; locals < 5; locals++) {
82
    for (int temps = 0; temps < 3; temps++) {
83
      BytecodeArrayBuilder builder(isolate(), zone());
84
      builder.set_parameter_count(0);
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
      builder.set_locals_count(locals);
      builder.Return();

      TemporaryRegisterScope temporaries(&builder);
      for (int i = 0; i < temps; i++) {
        temporaries.NewRegister();
      }

      Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
      int total_registers = locals + temps;
      CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize);
    }
  }
}


101
TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) {
102
  BytecodeArrayBuilder builder(isolate(), zone());
103
  builder.set_parameter_count(0);
104 105 106 107 108 109
  builder.set_locals_count(0);
  builder.Return();

  int first;
  {
    TemporaryRegisterScope temporaries(&builder);
110
    first = temporaries.NewRegister().index();
111 112 113 114 115 116 117 118
    temporaries.NewRegister();
    temporaries.NewRegister();
    temporaries.NewRegister();
  }

  int second;
  {
    TemporaryRegisterScope temporaries(&builder);
119
    second = temporaries.NewRegister().index();
120 121 122 123
  }

  CHECK_EQ(first, second);
}
124

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
  int index = 1;
  uint8_t operand = static_cast<uint8_t>(-index);

  Register the_register(index);
  CHECK_EQ(the_register.index(), index);

  int actual_operand = the_register.ToOperand();
  CHECK_EQ(actual_operand, operand);

  int actual_index = Register::FromOperand(actual_operand).index();
  CHECK_EQ(actual_index, index);
}

140 141

TEST_F(BytecodeArrayBuilderTest, Parameters) {
142
  BytecodeArrayBuilder builder(isolate(), zone());
143 144 145 146 147 148 149 150
  builder.set_parameter_count(10);
  builder.set_locals_count(0);

  Register param0(builder.Parameter(0));
  Register param9(builder.Parameter(9));
  CHECK_EQ(param9.index() - param0.index(), 9);
}

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173

TEST_F(BytecodeArrayBuilderTest, Constants) {
  BytecodeArrayBuilder builder(isolate(), zone());
  builder.set_parameter_count(0);
  builder.set_locals_count(0);

  Factory* factory = isolate()->factory();
  Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14);
  Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2);
  Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate());
  Handle<HeapObject> heap_num_2_copy(*heap_num_2);
  builder.LoadLiteral(heap_num_1)
      .LoadLiteral(heap_num_2)
      .LoadLiteral(large_smi)
      .LoadLiteral(heap_num_1)
      .LoadLiteral(heap_num_1)
      .LoadLiteral(heap_num_2_copy);

  Handle<BytecodeArray> array = builder.ToBytecodeArray();
  // Should only have one entry for each identical constant.
  CHECK_EQ(array->constant_pool()->length(), 3);
}

174 175 176
}  // namespace interpreter
}  // namespace internal
}  // namespace v8