OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/interpreter/bytecode-array-builder.h" | 7 #include "src/interpreter/bytecode-array-builder.h" |
8 #include "src/interpreter/bytecode-array-iterator.h" | 8 #include "src/interpreter/bytecode-array-iterator.h" |
9 #include "test/unittests/test-utils.h" | 9 #include "test/unittests/test-utils.h" |
10 | 10 |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 builder.CastAccumulatorToNumber() | 143 builder.CastAccumulatorToNumber() |
144 .CastAccumulatorToBoolean() | 144 .CastAccumulatorToBoolean() |
145 .CastAccumulatorToJSObject() | 145 .CastAccumulatorToJSObject() |
146 .CastAccumulatorToName(); | 146 .CastAccumulatorToName(); |
147 | 147 |
148 // Emit control flow. Return must be the last instruction. | 148 // Emit control flow. Return must be the last instruction. |
149 BytecodeLabel start; | 149 BytecodeLabel start; |
150 builder.Bind(&start); | 150 builder.Bind(&start); |
151 // Short jumps with Imm8 operands | 151 // Short jumps with Imm8 operands |
152 builder.Jump(&start) | 152 builder.Jump(&start) |
153 .JumpIfTrue(&start) | |
154 .JumpIfFalse(&start) | |
155 .JumpIfToBooleanTrue(&start) | |
156 .JumpIfToBooleanFalse(&start) | |
157 .JumpIfNull(&start) | 153 .JumpIfNull(&start) |
158 .JumpIfUndefined(&start); | 154 .JumpIfUndefined(&start); |
159 | 155 // Perform an operation that returns boolean value to |
| 156 // generate JumpIfTrue/False |
| 157 builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
| 158 .JumpIfTrue(&start) |
| 159 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
| 160 .JumpIfFalse(&start); |
| 161 // Perform an operation that returns a non-boolean operation to |
| 162 // generate JumpIfToBooleanTrue/False. |
| 163 builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 164 .JumpIfTrue(&start) |
| 165 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 166 .JumpIfFalse(&start); |
160 // Insert dummy ops to force longer jumps | 167 // Insert dummy ops to force longer jumps |
161 for (int i = 0; i < 128; i++) { | 168 for (int i = 0; i < 128; i++) { |
162 builder.LoadTrue(); | 169 builder.LoadTrue(); |
163 } | 170 } |
164 // Longer jumps requiring Constant operand | 171 // Longer jumps requiring Constant operand |
165 builder.Jump(&start) | 172 builder.Jump(&start) |
166 .JumpIfTrue(&start) | |
167 .JumpIfFalse(&start) | |
168 .JumpIfToBooleanTrue(&start) | |
169 .JumpIfToBooleanFalse(&start) | |
170 .JumpIfNull(&start) | 173 .JumpIfNull(&start) |
171 .JumpIfUndefined(&start); | 174 .JumpIfUndefined(&start); |
| 175 // Perform an operation that returns boolean value to |
| 176 // generate JumpIfTrue/False |
| 177 builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
| 178 .JumpIfTrue(&start) |
| 179 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
| 180 .JumpIfFalse(&start); |
| 181 // Perform an operation that returns a non-boolean operation to |
| 182 // generate JumpIfToBooleanTrue/False. |
| 183 builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 184 .JumpIfTrue(&start) |
| 185 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 186 .JumpIfFalse(&start); |
172 | 187 |
173 builder.EnterBlock() | 188 builder.EnterBlock() |
174 .Throw() | 189 .Throw() |
175 .LeaveBlock(); | 190 .LeaveBlock(); |
176 | 191 |
177 builder.ForInPrepare(reg).ForInDone(reg).ForInNext(reg, reg); | 192 builder.ForInPrepare(reg).ForInDone(reg).ForInNext(reg, reg); |
178 | 193 |
179 // Wide constant pool loads | 194 // Wide constant pool loads |
180 for (int i = 0; i < 256; i++) { | 195 for (int i = 0; i < 256; i++) { |
181 // Emit junk in constant pool to force wide constant pool index. | 196 // Emit junk in constant pool to force wide constant pool index. |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 // Should only have one entry for each identical constant. | 353 // Should only have one entry for each identical constant. |
339 CHECK_EQ(array->constant_pool()->length(), 3); | 354 CHECK_EQ(array->constant_pool()->length(), 3); |
340 } | 355 } |
341 | 356 |
342 | 357 |
343 TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { | 358 TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { |
344 static const int kFarJumpDistance = 256; | 359 static const int kFarJumpDistance = 256; |
345 | 360 |
346 BytecodeArrayBuilder builder(isolate(), zone()); | 361 BytecodeArrayBuilder builder(isolate(), zone()); |
347 builder.set_parameter_count(0); | 362 builder.set_parameter_count(0); |
348 builder.set_locals_count(0); | 363 builder.set_locals_count(1); |
349 builder.set_context_count(0); | 364 builder.set_context_count(0); |
350 | 365 |
351 BytecodeLabel far0, far1, far2; | 366 Register reg(0); |
352 BytecodeLabel near0, near1, near2; | 367 BytecodeLabel far0, far1, far2, far3, far4; |
| 368 BytecodeLabel near0, near1, near2, near3, near4; |
353 | 369 |
354 builder.Jump(&near0) | 370 builder.Jump(&near0) |
| 371 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
355 .JumpIfTrue(&near1) | 372 .JumpIfTrue(&near1) |
| 373 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
356 .JumpIfFalse(&near2) | 374 .JumpIfFalse(&near2) |
| 375 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 376 .JumpIfTrue(&near3) |
| 377 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 378 .JumpIfFalse(&near4) |
357 .Bind(&near0) | 379 .Bind(&near0) |
358 .Bind(&near1) | 380 .Bind(&near1) |
359 .Bind(&near2) | 381 .Bind(&near2) |
| 382 .Bind(&near3) |
| 383 .Bind(&near4) |
360 .Jump(&far0) | 384 .Jump(&far0) |
| 385 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
361 .JumpIfTrue(&far1) | 386 .JumpIfTrue(&far1) |
362 .JumpIfFalse(&far2); | 387 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
363 for (int i = 0; i < kFarJumpDistance - 6; i++) { | 388 .JumpIfFalse(&far2) |
| 389 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 390 .JumpIfTrue(&far3) |
| 391 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 392 .JumpIfFalse(&far4); |
| 393 for (int i = 0; i < kFarJumpDistance - 18; i++) { |
364 builder.LoadUndefined(); | 394 builder.LoadUndefined(); |
365 } | 395 } |
366 builder.Bind(&far0).Bind(&far1).Bind(&far2); | 396 builder.Bind(&far0).Bind(&far1).Bind(&far2).Bind(&far3).Bind(&far4); |
367 builder.Return(); | 397 builder.Return(); |
368 | 398 |
369 Handle<BytecodeArray> array = builder.ToBytecodeArray(); | 399 Handle<BytecodeArray> array = builder.ToBytecodeArray(); |
370 DCHECK_EQ(array->length(), 12 + kFarJumpDistance - 6 + 1); | 400 DCHECK_EQ(array->length(), 36 + kFarJumpDistance - 18 + 1); |
371 | 401 |
372 BytecodeArrayIterator iterator(array); | 402 BytecodeArrayIterator iterator(array); |
373 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); | 403 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); |
| 404 CHECK_EQ(iterator.GetImmediateOperand(0), 18); |
| 405 iterator.Advance(); |
| 406 |
| 407 // Ignore compare operation. |
| 408 iterator.Advance(); |
| 409 |
| 410 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue); |
| 411 CHECK_EQ(iterator.GetImmediateOperand(0), 14); |
| 412 iterator.Advance(); |
| 413 |
| 414 // Ignore compare operation. |
| 415 iterator.Advance(); |
| 416 |
| 417 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse); |
| 418 CHECK_EQ(iterator.GetImmediateOperand(0), 10); |
| 419 iterator.Advance(); |
| 420 |
| 421 // Ignore add operation. |
| 422 iterator.Advance(); |
| 423 |
| 424 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue); |
374 CHECK_EQ(iterator.GetImmediateOperand(0), 6); | 425 CHECK_EQ(iterator.GetImmediateOperand(0), 6); |
375 iterator.Advance(); | 426 iterator.Advance(); |
376 | 427 |
377 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue); | 428 // Ignore add operation. |
378 CHECK_EQ(iterator.GetImmediateOperand(0), 4); | |
379 iterator.Advance(); | 429 iterator.Advance(); |
380 | 430 |
381 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse); | 431 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse); |
382 CHECK_EQ(iterator.GetImmediateOperand(0), 2); | 432 CHECK_EQ(iterator.GetImmediateOperand(0), 2); |
383 iterator.Advance(); | 433 iterator.Advance(); |
384 | 434 |
| 435 |
385 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant); | 436 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant); |
386 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), | 437 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), |
387 Smi::FromInt(kFarJumpDistance)); | 438 Smi::FromInt(kFarJumpDistance)); |
388 CHECK_EQ( | 439 iterator.Advance(); |
389 array->get(iterator.current_offset() + | 440 |
390 Smi::cast(*iterator.GetConstantForIndexOperand(0))->value()), | 441 // Ignore compare operation. |
391 Bytecodes::ToByte(Bytecode::kReturn)); | |
392 iterator.Advance(); | 442 iterator.Advance(); |
393 | 443 |
394 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant); | 444 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant); |
395 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), | 445 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), |
396 Smi::FromInt(kFarJumpDistance - 2)); | 446 Smi::FromInt(kFarJumpDistance - 4)); |
397 CHECK_EQ( | 447 iterator.Advance(); |
398 array->get(iterator.current_offset() + | 448 |
399 Smi::cast(*iterator.GetConstantForIndexOperand(0))->value()), | 449 // Ignore compare operation. |
400 Bytecodes::ToByte(Bytecode::kReturn)); | |
401 iterator.Advance(); | 450 iterator.Advance(); |
402 | 451 |
403 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant); | 452 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant); |
404 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), | 453 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), |
405 Smi::FromInt(kFarJumpDistance - 4)); | 454 Smi::FromInt(kFarJumpDistance - 8)); |
406 CHECK_EQ( | 455 iterator.Advance(); |
407 array->get(iterator.current_offset() + | 456 |
408 Smi::cast(*iterator.GetConstantForIndexOperand(0))->value()), | 457 // Ignore add operation. |
409 Bytecodes::ToByte(Bytecode::kReturn)); | 458 iterator.Advance(); |
| 459 |
| 460 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant); |
| 461 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), |
| 462 Smi::FromInt(kFarJumpDistance - 12)); |
| 463 iterator.Advance(); |
| 464 |
| 465 // Ignore add operation. |
| 466 iterator.Advance(); |
| 467 |
| 468 CHECK_EQ(iterator.current_bytecode(), |
| 469 Bytecode::kJumpIfToBooleanFalseConstant); |
| 470 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), |
| 471 Smi::FromInt(kFarJumpDistance - 16)); |
410 iterator.Advance(); | 472 iterator.Advance(); |
411 } | 473 } |
412 | 474 |
413 | 475 |
414 TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { | 476 TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { |
415 BytecodeArrayBuilder builder(isolate(), zone()); | 477 BytecodeArrayBuilder builder(isolate(), zone()); |
416 builder.set_parameter_count(0); | 478 builder.set_parameter_count(0); |
417 builder.set_locals_count(0); | 479 builder.set_locals_count(1); |
418 builder.set_context_count(0); | 480 builder.set_context_count(0); |
| 481 Register reg(0); |
419 | 482 |
420 BytecodeLabel label0, label1, label2; | 483 BytecodeLabel label0, label1, label2, label3, label4; |
421 builder.Bind(&label0) | 484 builder.Bind(&label0) |
422 .Jump(&label0) | 485 .Jump(&label0) |
| 486 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
423 .Bind(&label1) | 487 .Bind(&label1) |
424 .JumpIfTrue(&label1) | 488 .JumpIfTrue(&label1) |
| 489 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
425 .Bind(&label2) | 490 .Bind(&label2) |
| 491 .JumpIfFalse(&label2) |
| 492 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 493 .Bind(&label3) |
| 494 .JumpIfTrue(&label3) |
| 495 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 496 .Bind(&label4) |
| 497 .JumpIfFalse(&label4); |
| 498 for (int i = 0; i < 64; i++) { |
| 499 builder.Jump(&label4); |
| 500 } |
| 501 builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 502 .JumpIfFalse(&label4); |
| 503 builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| 504 .JumpIfTrue(&label3); |
| 505 builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
426 .JumpIfFalse(&label2); | 506 .JumpIfFalse(&label2); |
427 for (int i = 0; i < 64; i++) { | 507 builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
428 builder.Jump(&label2); | 508 .JumpIfTrue(&label1); |
429 } | |
430 builder.JumpIfFalse(&label2); | |
431 builder.JumpIfTrue(&label1); | |
432 builder.Jump(&label0); | 509 builder.Jump(&label0); |
433 builder.Return(); | 510 builder.Return(); |
434 | 511 |
435 Handle<BytecodeArray> array = builder.ToBytecodeArray(); | 512 Handle<BytecodeArray> array = builder.ToBytecodeArray(); |
436 BytecodeArrayIterator iterator(array); | 513 BytecodeArrayIterator iterator(array); |
437 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); | 514 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); |
438 CHECK_EQ(iterator.GetImmediateOperand(0), 0); | 515 CHECK_EQ(iterator.GetImmediateOperand(0), 0); |
439 iterator.Advance(); | 516 iterator.Advance(); |
| 517 // Ignore compare operation. |
| 518 iterator.Advance(); |
440 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue); | 519 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue); |
441 CHECK_EQ(iterator.GetImmediateOperand(0), 0); | 520 CHECK_EQ(iterator.GetImmediateOperand(0), 0); |
442 iterator.Advance(); | 521 iterator.Advance(); |
| 522 // Ignore compare operation. |
| 523 iterator.Advance(); |
443 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse); | 524 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse); |
444 CHECK_EQ(iterator.GetImmediateOperand(0), 0); | 525 CHECK_EQ(iterator.GetImmediateOperand(0), 0); |
445 iterator.Advance(); | 526 iterator.Advance(); |
| 527 // Ignore binary operation. |
| 528 iterator.Advance(); |
| 529 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue); |
| 530 CHECK_EQ(iterator.GetImmediateOperand(0), 0); |
| 531 iterator.Advance(); |
| 532 // Ignore binary operation. |
| 533 iterator.Advance(); |
| 534 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse); |
| 535 CHECK_EQ(iterator.GetImmediateOperand(0), 0); |
| 536 iterator.Advance(); |
446 for (int i = 0; i < 64; i++) { | 537 for (int i = 0; i < 64; i++) { |
447 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); | 538 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); |
448 CHECK_EQ(iterator.GetImmediateOperand(0), -i * 2 - 2); | 539 CHECK_EQ(iterator.GetImmediateOperand(0), -i * 2 - 2); |
449 iterator.Advance(); | 540 iterator.Advance(); |
450 } | 541 } |
| 542 // Ignore binary operation. |
| 543 iterator.Advance(); |
| 544 CHECK_EQ(iterator.current_bytecode(), |
| 545 Bytecode::kJumpIfToBooleanFalseConstant); |
| 546 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -132); |
| 547 iterator.Advance(); |
| 548 // Ignore binary operation. |
| 549 iterator.Advance(); |
| 550 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant); |
| 551 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -140); |
| 552 iterator.Advance(); |
| 553 // Ignore compare operation. |
| 554 iterator.Advance(); |
451 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant); | 555 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant); |
452 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -130); | 556 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -148); |
| 557 iterator.Advance(); |
| 558 // Ignore compare operation. |
453 iterator.Advance(); | 559 iterator.Advance(); |
454 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant); | 560 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant); |
455 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -134); | 561 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -156); |
456 iterator.Advance(); | 562 iterator.Advance(); |
457 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant); | 563 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant); |
458 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -138); | 564 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -162); |
459 iterator.Advance(); | 565 iterator.Advance(); |
460 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); | 566 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); |
461 iterator.Advance(); | 567 iterator.Advance(); |
462 CHECK(iterator.done()); | 568 CHECK(iterator.done()); |
463 } | 569 } |
464 | 570 |
465 | 571 |
466 TEST_F(BytecodeArrayBuilderTest, LabelReuse) { | 572 TEST_F(BytecodeArrayBuilderTest, LabelReuse) { |
467 BytecodeArrayBuilder builder(isolate(), zone()); | 573 BytecodeArrayBuilder builder(isolate(), zone()); |
468 builder.set_parameter_count(0); | 574 builder.set_parameter_count(0); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
570 | 676 |
571 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); | 677 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); |
572 iterator.Advance(); | 678 iterator.Advance(); |
573 CHECK(iterator.done()); | 679 CHECK(iterator.done()); |
574 } | 680 } |
575 | 681 |
576 | 682 |
577 } // namespace interpreter | 683 } // namespace interpreter |
578 } // namespace internal | 684 } // namespace internal |
579 } // namespace v8 | 685 } // namespace v8 |
OLD | NEW |