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/v8.h" 6 7 #include "src/interpreter/bytecode-array-builder.h" 8 #include "src/interpreter/bytecode-array-iterator.h" 9 #include "src/interpreter/bytecode-register-allocator.h" 10 #include "test/unittests/test-utils.h" 11 12 namespace v8 { 13 namespace internal { 14 namespace interpreter { 15 16 class BytecodeArrayBuilderTest : public TestWithIsolateAndZone { 17 public: 18 BytecodeArrayBuilderTest() {} 19 ~BytecodeArrayBuilderTest() override {} 20 }; 21 22 23 TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { 24 BytecodeArrayBuilder builder(isolate(), zone()); 25 26 builder.set_locals_count(200); 27 builder.set_context_count(1); 28 builder.set_parameter_count(0); 29 CHECK_EQ(builder.locals_count(), 200); 30 CHECK_EQ(builder.context_count(), 1); 31 CHECK_EQ(builder.fixed_register_count(), 201); 32 33 // Emit constant loads. 34 builder.LoadLiteral(Smi::FromInt(0)) 35 .LoadLiteral(Smi::FromInt(8)) 36 .LoadLiteral(Smi::FromInt(10000000)) 37 .LoadUndefined() 38 .LoadNull() 39 .LoadTheHole() 40 .LoadTrue() 41 .LoadFalse(); 42 43 // Emit accumulator transfers. Stores followed by loads to the same register 44 // are not generated. Hence, a dummy instruction in between. 45 Register reg(0); 46 builder.LoadAccumulatorWithRegister(reg) 47 .LoadNull() 48 .StoreAccumulatorInRegister(reg); 49 50 // Emit register-register transfer. 51 Register other(1); 52 builder.MoveRegister(reg, other); 53 54 // Emit register-register exchanges. 55 Register wide(150); 56 builder.ExchangeRegisters(reg, wide); 57 builder.ExchangeRegisters(wide, reg); 58 Register wider(151); 59 builder.ExchangeRegisters(wide, wider); 60 61 // Emit global load / store operations. 62 Factory* factory = isolate()->factory(); 63 Handle<String> name = factory->NewStringFromStaticChars("var_name"); 64 builder.LoadGlobal(name, 1, LanguageMode::SLOPPY, 65 TypeofMode::NOT_INSIDE_TYPEOF) 66 .LoadGlobal(name, 1, LanguageMode::STRICT, TypeofMode::NOT_INSIDE_TYPEOF) 67 .LoadGlobal(name, 1, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF) 68 .LoadGlobal(name, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF) 69 .StoreGlobal(name, 1, LanguageMode::SLOPPY) 70 .StoreGlobal(name, 1, LanguageMode::STRICT); 71 72 // Emit context operations. 73 builder.PushContext(reg) 74 .PopContext(reg) 75 .LoadContextSlot(reg, 1) 76 .StoreContextSlot(reg, 1); 77 78 // Emit load / store property operations. 79 builder.LoadNamedProperty(reg, name, 0, LanguageMode::SLOPPY) 80 .LoadKeyedProperty(reg, 0, LanguageMode::SLOPPY) 81 .StoreNamedProperty(reg, name, 0, LanguageMode::SLOPPY) 82 .StoreKeyedProperty(reg, reg, 0, LanguageMode::SLOPPY) 83 .LoadNamedProperty(reg, name, 0, LanguageMode::STRICT) 84 .LoadKeyedProperty(reg, 0, LanguageMode::STRICT) 85 .StoreNamedProperty(reg, name, 0, LanguageMode::STRICT) 86 .StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT); 87 88 // Emit load / store lookup slots. 89 builder.LoadLookupSlot(name, TypeofMode::NOT_INSIDE_TYPEOF) 90 .LoadLookupSlot(name, TypeofMode::INSIDE_TYPEOF) 91 .StoreLookupSlot(name, LanguageMode::SLOPPY) 92 .StoreLookupSlot(name, LanguageMode::STRICT); 93 94 // Emit closure operations. 95 Handle<SharedFunctionInfo> shared_info = factory->NewSharedFunctionInfo( 96 factory->NewStringFromStaticChars("function_a"), MaybeHandle<Code>(), 97 false); 98 builder.CreateClosure(shared_info, NOT_TENURED); 99 100 // Emit argument creation operations. 101 builder.CreateArguments(CreateArgumentsType::kMappedArguments) 102 .CreateArguments(CreateArgumentsType::kUnmappedArguments); 103 104 // Emit literal creation operations. 105 builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("a"), 0, 0) 106 .CreateArrayLiteral(factory->NewFixedArray(1), 0, 0) 107 .CreateObjectLiteral(factory->NewFixedArray(1), 0, 0); 108 109 // Call operations. 110 builder.Call(reg, reg, 0, 0) 111 .Call(reg, reg, 0, 1024) 112 .CallRuntime(Runtime::kIsArray, reg, 1) 113 .CallRuntimeForPair(Runtime::kLoadLookupSlot, reg, 1, reg) 114 .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1); 115 116 // Emit binary operator invocations. 117 builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 118 .BinaryOperation(Token::Value::SUB, reg, Strength::WEAK) 119 .BinaryOperation(Token::Value::MUL, reg, Strength::WEAK) 120 .BinaryOperation(Token::Value::DIV, reg, Strength::WEAK) 121 .BinaryOperation(Token::Value::MOD, reg, Strength::WEAK); 122 123 // Emit bitwise operator invocations 124 builder.BinaryOperation(Token::Value::BIT_OR, reg, Strength::WEAK) 125 .BinaryOperation(Token::Value::BIT_XOR, reg, Strength::WEAK) 126 .BinaryOperation(Token::Value::BIT_AND, reg, Strength::WEAK); 127 128 // Emit shift operator invocations 129 builder.BinaryOperation(Token::Value::SHL, reg, Strength::WEAK) 130 .BinaryOperation(Token::Value::SAR, reg, Strength::WEAK) 131 .BinaryOperation(Token::Value::SHR, reg, Strength::WEAK); 132 133 // Emit count operatior invocations 134 builder.CountOperation(Token::Value::ADD, Strength::WEAK) 135 .CountOperation(Token::Value::SUB, Strength::WEAK); 136 137 // Emit unary operator invocations. 138 builder.LogicalNot().TypeOf(); 139 140 // Emit delete 141 builder.Delete(reg, LanguageMode::SLOPPY) 142 .Delete(reg, LanguageMode::STRICT) 143 .DeleteLookupSlot(); 144 145 // Emit new. 146 builder.New(reg, reg, 0); 147 148 // Emit test operator invocations. 149 builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 150 .CompareOperation(Token::Value::NE, reg, Strength::WEAK) 151 .CompareOperation(Token::Value::EQ_STRICT, reg, Strength::WEAK) 152 .CompareOperation(Token::Value::NE_STRICT, reg, Strength::WEAK) 153 .CompareOperation(Token::Value::LT, reg, Strength::WEAK) 154 .CompareOperation(Token::Value::GT, reg, Strength::WEAK) 155 .CompareOperation(Token::Value::LTE, reg, Strength::WEAK) 156 .CompareOperation(Token::Value::GTE, reg, Strength::WEAK) 157 .CompareOperation(Token::Value::INSTANCEOF, reg, Strength::WEAK) 158 .CompareOperation(Token::Value::IN, reg, Strength::WEAK); 159 160 // Emit cast operator invocations. 161 builder.CastAccumulatorToNumber() 162 .CastAccumulatorToJSObject() 163 .CastAccumulatorToName(); 164 165 // Emit control flow. Return must be the last instruction. 166 BytecodeLabel start; 167 builder.Bind(&start); 168 // Short jumps with Imm8 operands 169 builder.Jump(&start) 170 .JumpIfNull(&start) 171 .JumpIfUndefined(&start); 172 // Perform an operation that returns boolean value to 173 // generate JumpIfTrue/False 174 builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 175 .JumpIfTrue(&start) 176 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 177 .JumpIfFalse(&start); 178 // Perform an operation that returns a non-boolean operation to 179 // generate JumpIfToBooleanTrue/False. 180 builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 181 .JumpIfTrue(&start) 182 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 183 .JumpIfFalse(&start); 184 // Insert dummy ops to force longer jumps 185 for (int i = 0; i < 128; i++) { 186 builder.LoadTrue(); 187 } 188 // Longer jumps requiring Constant operand 189 builder.Jump(&start) 190 .JumpIfNull(&start) 191 .JumpIfUndefined(&start); 192 // Perform an operation that returns boolean value to 193 // generate JumpIfTrue/False 194 builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 195 .JumpIfTrue(&start) 196 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 197 .JumpIfFalse(&start); 198 // Perform an operation that returns a non-boolean operation to 199 // generate JumpIfToBooleanTrue/False. 200 builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 201 .JumpIfTrue(&start) 202 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 203 .JumpIfFalse(&start); 204 205 // Emit throw in it's own basic block so that the rest of the code isn't 206 // omitted due to being dead. 207 BytecodeLabel after_throw; 208 builder.Jump(&after_throw) 209 .Throw() 210 .Bind(&after_throw); 211 212 builder.ForInPrepare(reg, reg, reg) 213 .ForInDone(reg, reg) 214 .ForInNext(reg, reg, reg, reg) 215 .ForInStep(reg); 216 217 // Wide constant pool loads 218 for (int i = 0; i < 256; i++) { 219 // Emit junk in constant pool to force wide constant pool index. 220 builder.LoadLiteral(factory->NewNumber(2.5321 + i)); 221 } 222 builder.LoadLiteral(Smi::FromInt(20000000)); 223 Handle<String> wide_name = factory->NewStringFromStaticChars("var_wide_name"); 224 225 // Emit wide global load / store operations. 226 builder.LoadGlobal(name, 1024, LanguageMode::SLOPPY, 227 TypeofMode::NOT_INSIDE_TYPEOF) 228 .LoadGlobal(wide_name, 1, LanguageMode::STRICT, 229 TypeofMode::NOT_INSIDE_TYPEOF) 230 .LoadGlobal(name, 1024, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF) 231 .LoadGlobal(wide_name, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF) 232 .StoreGlobal(name, 1024, LanguageMode::SLOPPY) 233 .StoreGlobal(wide_name, 1, LanguageMode::STRICT); 234 235 // Emit wide load / store property operations. 236 builder.LoadNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY) 237 .LoadKeyedProperty(reg, 2056, LanguageMode::SLOPPY) 238 .StoreNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY) 239 .StoreKeyedProperty(reg, reg, 2056, LanguageMode::SLOPPY) 240 .LoadNamedProperty(reg, wide_name, 0, LanguageMode::STRICT) 241 .LoadKeyedProperty(reg, 2056, LanguageMode::STRICT) 242 .StoreNamedProperty(reg, wide_name, 0, LanguageMode::STRICT) 243 .StoreKeyedProperty(reg, reg, 2056, LanguageMode::STRICT); 244 245 // Emit wide context operations. 246 builder.LoadContextSlot(reg, 1024) 247 .StoreContextSlot(reg, 1024); 248 249 // Emit wide load / store lookup slots. 250 builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF) 251 .LoadLookupSlot(wide_name, TypeofMode::INSIDE_TYPEOF) 252 .StoreLookupSlot(wide_name, LanguageMode::SLOPPY) 253 .StoreLookupSlot(wide_name, LanguageMode::STRICT); 254 255 // CreateClosureWide 256 Handle<SharedFunctionInfo> shared_info2 = factory->NewSharedFunctionInfo( 257 factory->NewStringFromStaticChars("function_b"), MaybeHandle<Code>(), 258 false); 259 builder.CreateClosure(shared_info2, NOT_TENURED); 260 261 // Emit wide variant of literal creation operations. 262 builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("wide_literal"), 263 0, 0) 264 .CreateArrayLiteral(factory->NewFixedArray(2), 0, 0) 265 .CreateObjectLiteral(factory->NewFixedArray(2), 0, 0); 266 267 // Longer jumps requiring ConstantWide operand 268 builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start); 269 // Perform an operation that returns boolean value to 270 // generate JumpIfTrue/False 271 builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 272 .JumpIfTrue(&start) 273 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 274 .JumpIfFalse(&start); 275 // Perform an operation that returns a non-boolean operation to 276 // generate JumpIfToBooleanTrue/False. 277 builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 278 .JumpIfTrue(&start) 279 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 280 .JumpIfFalse(&start); 281 282 builder.Return(); 283 284 // Generate BytecodeArray. 285 Handle<BytecodeArray> the_array = builder.ToBytecodeArray(); 286 CHECK_EQ(the_array->frame_size(), 287 builder.fixed_register_count() * kPointerSize); 288 289 // Build scorecard of bytecodes encountered in the BytecodeArray. 290 std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1); 291 Bytecode final_bytecode = Bytecode::kLdaZero; 292 int i = 0; 293 while (i < the_array->length()) { 294 uint8_t code = the_array->get(i); 295 scorecard[code] += 1; 296 final_bytecode = Bytecodes::FromByte(code); 297 i += Bytecodes::Size(Bytecodes::FromByte(code)); 298 } 299 300 // Check return occurs at the end and only once in the BytecodeArray. 301 CHECK_EQ(final_bytecode, Bytecode::kReturn); 302 CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1); 303 304 #define CHECK_BYTECODE_PRESENT(Name, ...) \ 305 /* Check Bytecode is marked in scorecard */ \ 306 CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); 307 BYTECODE_LIST(CHECK_BYTECODE_PRESENT) 308 #undef CHECK_BYTECODE_PRESENT 309 } 310 311 312 TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { 313 for (int locals = 0; locals < 5; locals++) { 314 for (int contexts = 0; contexts < 4; contexts++) { 315 for (int temps = 0; temps < 3; temps++) { 316 BytecodeArrayBuilder builder(isolate(), zone()); 317 builder.set_parameter_count(0); 318 builder.set_locals_count(locals); 319 builder.set_context_count(contexts); 320 321 BytecodeRegisterAllocator temporaries(&builder); 322 for (int i = 0; i < temps; i++) { 323 builder.StoreAccumulatorInRegister(temporaries.NewRegister()); 324 } 325 builder.Return(); 326 327 Handle<BytecodeArray> the_array = builder.ToBytecodeArray(); 328 int total_registers = locals + contexts + temps; 329 CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize); 330 } 331 } 332 } 333 } 334 335 336 TEST_F(BytecodeArrayBuilderTest, RegisterValues) { 337 int index = 1; 338 uint8_t operand = static_cast<uint8_t>(-index); 339 340 Register the_register(index); 341 CHECK_EQ(the_register.index(), index); 342 343 int actual_operand = the_register.ToOperand(); 344 CHECK_EQ(actual_operand, operand); 345 346 int actual_index = Register::FromOperand(actual_operand).index(); 347 CHECK_EQ(actual_index, index); 348 } 349 350 351 TEST_F(BytecodeArrayBuilderTest, Parameters) { 352 BytecodeArrayBuilder builder(isolate(), zone()); 353 builder.set_parameter_count(10); 354 builder.set_locals_count(0); 355 builder.set_context_count(0); 356 357 Register param0(builder.Parameter(0)); 358 Register param9(builder.Parameter(9)); 359 CHECK_EQ(param9.index() - param0.index(), 9); 360 } 361 362 363 TEST_F(BytecodeArrayBuilderTest, RegisterType) { 364 BytecodeArrayBuilder builder(isolate(), zone()); 365 builder.set_parameter_count(10); 366 builder.set_locals_count(3); 367 builder.set_context_count(0); 368 369 BytecodeRegisterAllocator register_allocator(&builder); 370 Register temp0 = register_allocator.NewRegister(); 371 Register param0(builder.Parameter(0)); 372 Register param9(builder.Parameter(9)); 373 Register temp1 = register_allocator.NewRegister(); 374 Register reg0(0); 375 Register reg1(1); 376 Register reg2(2); 377 Register temp2 = register_allocator.NewRegister(); 378 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp0), false); 379 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp1), false); 380 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp2), false); 381 CHECK_EQ(builder.RegisterIsParameterOrLocal(param0), true); 382 CHECK_EQ(builder.RegisterIsParameterOrLocal(param9), true); 383 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg0), true); 384 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg1), true); 385 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg2), true); 386 } 387 388 389 TEST_F(BytecodeArrayBuilderTest, Constants) { 390 BytecodeArrayBuilder builder(isolate(), zone()); 391 builder.set_parameter_count(0); 392 builder.set_locals_count(0); 393 builder.set_context_count(0); 394 395 Factory* factory = isolate()->factory(); 396 Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14); 397 Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2); 398 Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate()); 399 Handle<HeapObject> heap_num_2_copy(*heap_num_2); 400 builder.LoadLiteral(heap_num_1) 401 .LoadLiteral(heap_num_2) 402 .LoadLiteral(large_smi) 403 .LoadLiteral(heap_num_1) 404 .LoadLiteral(heap_num_1) 405 .LoadLiteral(heap_num_2_copy); 406 407 Handle<BytecodeArray> array = builder.ToBytecodeArray(); 408 // Should only have one entry for each identical constant. 409 CHECK_EQ(array->constant_pool()->length(), 3); 410 } 411 412 413 TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { 414 static const int kFarJumpDistance = 256; 415 416 BytecodeArrayBuilder builder(isolate(), zone()); 417 builder.set_parameter_count(0); 418 builder.set_locals_count(1); 419 builder.set_context_count(0); 420 421 Register reg(0); 422 BytecodeLabel far0, far1, far2, far3, far4; 423 BytecodeLabel near0, near1, near2, near3, near4; 424 425 builder.Jump(&near0) 426 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 427 .JumpIfTrue(&near1) 428 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 429 .JumpIfFalse(&near2) 430 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 431 .JumpIfTrue(&near3) 432 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 433 .JumpIfFalse(&near4) 434 .Bind(&near0) 435 .Bind(&near1) 436 .Bind(&near2) 437 .Bind(&near3) 438 .Bind(&near4) 439 .Jump(&far0) 440 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 441 .JumpIfTrue(&far1) 442 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 443 .JumpIfFalse(&far2) 444 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 445 .JumpIfTrue(&far3) 446 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 447 .JumpIfFalse(&far4); 448 for (int i = 0; i < kFarJumpDistance - 18; i++) { 449 builder.LoadUndefined(); 450 } 451 builder.Bind(&far0).Bind(&far1).Bind(&far2).Bind(&far3).Bind(&far4); 452 builder.Return(); 453 454 Handle<BytecodeArray> array = builder.ToBytecodeArray(); 455 DCHECK_EQ(array->length(), 36 + kFarJumpDistance - 18 + 1); 456 457 BytecodeArrayIterator iterator(array); 458 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); 459 CHECK_EQ(iterator.GetImmediateOperand(0), 18); 460 iterator.Advance(); 461 462 // Ignore compare operation. 463 iterator.Advance(); 464 465 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue); 466 CHECK_EQ(iterator.GetImmediateOperand(0), 14); 467 iterator.Advance(); 468 469 // Ignore compare operation. 470 iterator.Advance(); 471 472 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse); 473 CHECK_EQ(iterator.GetImmediateOperand(0), 10); 474 iterator.Advance(); 475 476 // Ignore add operation. 477 iterator.Advance(); 478 479 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue); 480 CHECK_EQ(iterator.GetImmediateOperand(0), 6); 481 iterator.Advance(); 482 483 // Ignore add operation. 484 iterator.Advance(); 485 486 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse); 487 CHECK_EQ(iterator.GetImmediateOperand(0), 2); 488 iterator.Advance(); 489 490 491 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant); 492 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), 493 Smi::FromInt(kFarJumpDistance)); 494 iterator.Advance(); 495 496 // Ignore compare operation. 497 iterator.Advance(); 498 499 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant); 500 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), 501 Smi::FromInt(kFarJumpDistance - 4)); 502 iterator.Advance(); 503 504 // Ignore compare operation. 505 iterator.Advance(); 506 507 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant); 508 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), 509 Smi::FromInt(kFarJumpDistance - 8)); 510 iterator.Advance(); 511 512 // Ignore add operation. 513 iterator.Advance(); 514 515 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant); 516 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), 517 Smi::FromInt(kFarJumpDistance - 12)); 518 iterator.Advance(); 519 520 // Ignore add operation. 521 iterator.Advance(); 522 523 CHECK_EQ(iterator.current_bytecode(), 524 Bytecode::kJumpIfToBooleanFalseConstant); 525 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), 526 Smi::FromInt(kFarJumpDistance - 16)); 527 iterator.Advance(); 528 } 529 530 531 TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { 532 BytecodeArrayBuilder builder(isolate(), zone()); 533 builder.set_parameter_count(0); 534 builder.set_locals_count(1); 535 builder.set_context_count(0); 536 Register reg(0); 537 538 BytecodeLabel label0, label1, label2, label3, label4; 539 builder.Bind(&label0) 540 .Jump(&label0) 541 .Bind(&label1) 542 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 543 .JumpIfTrue(&label1) 544 .Bind(&label2) 545 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 546 .JumpIfFalse(&label2) 547 .Bind(&label3) 548 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 549 .JumpIfTrue(&label3) 550 .Bind(&label4) 551 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 552 .JumpIfFalse(&label4); 553 for (int i = 0; i < 63; i++) { 554 builder.Jump(&label4); 555 } 556 builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 557 .JumpIfFalse(&label4); 558 builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) 559 .JumpIfTrue(&label3); 560 builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 561 .JumpIfFalse(&label2); 562 builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) 563 .JumpIfTrue(&label1); 564 builder.Jump(&label0); 565 builder.Return(); 566 567 Handle<BytecodeArray> array = builder.ToBytecodeArray(); 568 BytecodeArrayIterator iterator(array); 569 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); 570 CHECK_EQ(iterator.GetImmediateOperand(0), 0); 571 iterator.Advance(); 572 // Ignore compare operation. 573 iterator.Advance(); 574 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue); 575 CHECK_EQ(iterator.GetImmediateOperand(0), -2); 576 iterator.Advance(); 577 // Ignore compare operation. 578 iterator.Advance(); 579 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse); 580 CHECK_EQ(iterator.GetImmediateOperand(0), -2); 581 iterator.Advance(); 582 // Ignore binary operation. 583 iterator.Advance(); 584 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue); 585 CHECK_EQ(iterator.GetImmediateOperand(0), -2); 586 iterator.Advance(); 587 // Ignore binary operation. 588 iterator.Advance(); 589 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse); 590 CHECK_EQ(iterator.GetImmediateOperand(0), -2); 591 iterator.Advance(); 592 for (int i = 0; i < 63; i++) { 593 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); 594 CHECK_EQ(iterator.GetImmediateOperand(0), -i * 2 - 4); 595 iterator.Advance(); 596 } 597 // Ignore binary operation. 598 iterator.Advance(); 599 CHECK_EQ(iterator.current_bytecode(), 600 Bytecode::kJumpIfToBooleanFalseConstant); 601 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -132); 602 iterator.Advance(); 603 // Ignore binary operation. 604 iterator.Advance(); 605 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant); 606 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -140); 607 iterator.Advance(); 608 // Ignore compare operation. 609 iterator.Advance(); 610 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant); 611 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -148); 612 iterator.Advance(); 613 // Ignore compare operation. 614 iterator.Advance(); 615 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant); 616 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -156); 617 iterator.Advance(); 618 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant); 619 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -160); 620 iterator.Advance(); 621 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); 622 iterator.Advance(); 623 CHECK(iterator.done()); 624 } 625 626 627 TEST_F(BytecodeArrayBuilderTest, LabelReuse) { 628 BytecodeArrayBuilder builder(isolate(), zone()); 629 builder.set_parameter_count(0); 630 builder.set_locals_count(0); 631 builder.set_context_count(0); 632 633 // Labels can only have 1 forward reference, but 634 // can be referred to mulitple times once bound. 635 BytecodeLabel label; 636 637 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label).Return(); 638 639 Handle<BytecodeArray> array = builder.ToBytecodeArray(); 640 BytecodeArrayIterator iterator(array); 641 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); 642 CHECK_EQ(iterator.GetImmediateOperand(0), 2); 643 iterator.Advance(); 644 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); 645 CHECK_EQ(iterator.GetImmediateOperand(0), 0); 646 iterator.Advance(); 647 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); 648 CHECK_EQ(iterator.GetImmediateOperand(0), -2); 649 iterator.Advance(); 650 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); 651 iterator.Advance(); 652 CHECK(iterator.done()); 653 } 654 655 656 TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { 657 static const int kRepeats = 3; 658 659 BytecodeArrayBuilder builder(isolate(), zone()); 660 builder.set_parameter_count(0); 661 builder.set_locals_count(0); 662 builder.set_context_count(0); 663 664 for (int i = 0; i < kRepeats; i++) { 665 BytecodeLabel label; 666 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label); 667 } 668 669 builder.Return(); 670 671 Handle<BytecodeArray> array = builder.ToBytecodeArray(); 672 BytecodeArrayIterator iterator(array); 673 for (int i = 0; i < kRepeats; i++) { 674 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); 675 CHECK_EQ(iterator.GetImmediateOperand(0), 2); 676 iterator.Advance(); 677 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); 678 CHECK_EQ(iterator.GetImmediateOperand(0), 0); 679 iterator.Advance(); 680 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); 681 CHECK_EQ(iterator.GetImmediateOperand(0), -2); 682 iterator.Advance(); 683 } 684 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); 685 iterator.Advance(); 686 CHECK(iterator.done()); 687 } 688 689 690 } // namespace interpreter 691 } // namespace internal 692 } // namespace v8 693