Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: src/codegen-ia32.cc

Issue 21077: Experimental: improve the code generated for possibly boolean-valued... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: '' Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/codegen-ia32.h ('k') | src/disassembler.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 27 matching lines...) Expand all
38 #define __ masm_-> 38 #define __ masm_->
39 39
40 // ------------------------------------------------------------------------- 40 // -------------------------------------------------------------------------
41 // CodeGenState implementation. 41 // CodeGenState implementation.
42 42
43 CodeGenState::CodeGenState(CodeGenerator* owner) 43 CodeGenState::CodeGenState(CodeGenerator* owner)
44 : owner_(owner), 44 : owner_(owner),
45 typeof_state_(NOT_INSIDE_TYPEOF), 45 typeof_state_(NOT_INSIDE_TYPEOF),
46 true_target_(NULL), 46 true_target_(NULL),
47 false_target_(NULL), 47 false_target_(NULL),
48 fall_through_(NULL),
48 previous_(NULL) { 49 previous_(NULL) {
49 owner_->set_state(this); 50 owner_->set_state(this);
50 } 51 }
51 52
52 53
53 CodeGenState::CodeGenState(CodeGenerator* owner, 54 CodeGenState::CodeGenState(CodeGenerator* owner,
54 TypeofState typeof_state, 55 TypeofState typeof_state,
55 JumpTarget* true_target, 56 JumpTarget* true_target,
56 JumpTarget* false_target) 57 JumpTarget* false_target,
58 JumpTarget* fall_through)
57 : owner_(owner), 59 : owner_(owner),
58 typeof_state_(typeof_state), 60 typeof_state_(typeof_state),
59 true_target_(true_target), 61 true_target_(true_target),
60 false_target_(false_target), 62 false_target_(false_target),
63 fall_through_(fall_through),
61 previous_(owner->state()) { 64 previous_(owner->state()) {
62 owner_->set_state(this); 65 owner_->set_state(this);
63 } 66 }
64 67
65 68
66 CodeGenState::~CodeGenState() { 69 CodeGenState::~CodeGenState() {
67 ASSERT(owner_->state() == this); 70 ASSERT(owner_->state() == this);
68 owner_->set_state(previous_); 71 owner_->set_state(previous_);
69 } 72 }
70 73
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 394
392 395
393 // Loads a value on TOS. If the result is a boolean value it may have 396 // Loads a value on TOS. If the result is a boolean value it may have
394 // been translated into control flow to the true and/or false targets. 397 // been translated into control flow to the true and/or false targets.
395 // If force_control is true, control flow is forced and the function 398 // If force_control is true, control flow is forced and the function
396 // exits without a valid frame. 399 // exits without a valid frame.
397 void CodeGenerator::LoadCondition(Expression* x, 400 void CodeGenerator::LoadCondition(Expression* x,
398 TypeofState typeof_state, 401 TypeofState typeof_state,
399 JumpTarget* true_target, 402 JumpTarget* true_target,
400 JumpTarget* false_target, 403 JumpTarget* false_target,
404 JumpTarget* fall_through,
401 bool force_control) { 405 bool force_control) {
402 ASSERT(!in_spilled_code()); 406 ASSERT(!in_spilled_code());
407 ASSERT(!fall_through->is_bound());
403 #ifdef DEBUG 408 #ifdef DEBUG
404 int original_height = frame_->height(); 409 int original_height = frame_->height();
405 #endif 410 #endif
406 { CodeGenState new_state(this, typeof_state, true_target, false_target); 411 JumpTarget* non_fall_through =
412 (false_target == fall_through) ? true_target : false_target;
413 bool backward = non_fall_through->is_bound();
414 { CodeGenState new_state(this, typeof_state, true_target, false_target,
415 fall_through);
407 Visit(x); 416 Visit(x);
408 } 417 }
418 // There are four possibilities for the code generated by a call to
419 // Visit on an expression:
420 //
421 // 1. Conditional control flow to both control destinations by
422 // branching to the non-fall-through destination and binding the
423 // fall-through destination for the very next instruction to be
424 // generated.
425 //
426 // 2. Unconditional control flow to the fall-through destination by
427 // binding it (and not generating a branch or jump to the
428 // non-fall-through destination).
429 //
430 // 3. Unconditional control flow to the non-fall-through destination
431 // by jumping backward to it (if it was already bound) or binding
432 // it.
433 //
434 // 4. No control flow and a result on top of the virtual frame. In
435 // this case there can still be dangling jumps to the true and
436 // false labels (eg, from subexpressions of the short-circuited
437 // boolean operators).
438 bool got_control = fall_through->is_bound() ||
439 (backward && !has_valid_frame()) ||
440 (!backward && non_fall_through->is_bound());
409 441
410 if (force_control && has_valid_frame()) { 442 if (force_control && !got_control) {
411 // Convert the TOS value to a boolean in the condition code register. 443 // Convert the TOS value to a boolean in the condition code register.
412 ToBoolean(true_target, false_target); 444 ToBoolean(true_target, false_target, fall_through);
413 } 445 }
414 446
415 ASSERT(!(force_control && has_valid_frame())); 447 #ifdef DEBUG
416 ASSERT(!has_valid_frame() || frame_->height() == original_height + 1); 448 // ToBoolean will always bind the fall-through destination.
449 got_control = got_control || fall_through->is_bound();
450 #endif
451 ASSERT(!force_control || got_control);
452 ASSERT(got_control || frame_->height() == original_height + 1);
453 ASSERT(!got_control ||
454 fall_through->is_bound() ||
455 (!fall_through->is_bound() && backward && !has_valid_frame()) ||
456 (!fall_through->is_bound() && !backward &&
457 non_fall_through->is_bound()));
417 } 458 }
418 459
419 460
420 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { 461 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
421 #ifdef DEBUG 462 #ifdef DEBUG
422 int original_height = frame_->height(); 463 int original_height = frame_->height();
423 #endif 464 #endif
424 ASSERT(!in_spilled_code()); 465 ASSERT(!in_spilled_code());
425 JumpTarget true_target(this); 466 JumpTarget true_target(this);
426 JumpTarget false_target(this); 467 JumpTarget false_target(this);
427 LoadCondition(x, typeof_state, &true_target, &false_target, false); 468 LoadCondition(x, typeof_state, &true_target, &false_target,
469 &true_target, false);
428 470
429 if (true_target.is_linked() || false_target.is_linked()) { 471 if (true_target.is_bound()) {
430 // We have at least one condition value that has been "translated" into 472 // We have control flow to the fall-through destination and
431 // a branch, thus it needs to be loaded explicitly. 473 // possibly the non-fall-through.
432 JumpTarget loaded(this); 474 frame_->Push(Factory::true_value());
433 if (has_valid_frame()) { 475 if (false_target.is_linked()) {
476 JumpTarget loaded(this);
477 loaded.Jump();
478 false_target.Bind();
479 frame_->Push(Factory::false_value());
480 loaded.Bind();
481 }
482 } else if (false_target.is_bound()) {
483 // We fell through to the label that was not our preferred fall
484 // through (ie, the expression was unconditionally false.
485 frame_->Push(Factory::false_value());
486 } else {
487 // We have a valid value on top of the frame, but we still may
488 // have dangling jumps to the true and false target from nested
489 // subexpressions (eg, the left subexpressions of the
490 // short-circuited boolean operators).
491 ASSERT(has_valid_frame());
492 if (true_target.is_linked() || false_target.is_linked()) {
493 JumpTarget loaded(this);
434 loaded.Jump(); // Don't lose the current TOS. 494 loaded.Jump(); // Don't lose the current TOS.
495 if (true_target.is_linked()) {
496 true_target.Bind();
497 frame_->Push(Factory::true_value());
498 if (false_target.is_linked()) {
499 loaded.Jump();
500 }
501 }
502 if (false_target.is_linked()) {
503 false_target.Bind();
504 frame_->Push(Factory::false_value());
505 }
506 loaded.Bind();
435 } 507 }
436 bool both = true_target.is_linked() && false_target.is_linked();
437 // Load "true" if necessary.
438 if (true_target.is_linked()) {
439 true_target.Bind();
440 VirtualFrame::SpilledScope spilled_scope(this);
441 frame_->EmitPush(Immediate(Factory::true_value()));
442 }
443 // If both "true" and "false" need to be reincarnated jump across the
444 // code for "false".
445 if (both) {
446 loaded.Jump();
447 }
448 // Load "false" if necessary.
449 if (false_target.is_linked()) {
450 false_target.Bind();
451 VirtualFrame::SpilledScope spilled_scope(this);
452 frame_->EmitPush(Immediate(Factory::false_value()));
453 }
454 // A value is loaded on all paths reaching this point.
455 loaded.Bind();
456 } 508 }
457 ASSERT(has_valid_frame()); 509 ASSERT(has_valid_frame());
458 ASSERT(frame_->height() == original_height + 1); 510 ASSERT(frame_->height() == original_height + 1);
459 } 511 }
460 512
461 513
462 void CodeGenerator::LoadGlobal() { 514 void CodeGenerator::LoadGlobal() {
463 if (in_spilled_code()) { 515 if (in_spilled_code()) {
464 frame_->EmitPush(GlobalObject()); 516 frame_->EmitPush(GlobalObject());
465 } else { 517 } else {
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
562 } 614 }
563 615
564 616
565 void CodeGenerator::UnloadReference(Reference* ref) { 617 void CodeGenerator::UnloadReference(Reference* ref) {
566 // Pop a reference from the stack while preserving TOS. 618 // Pop a reference from the stack while preserving TOS.
567 Comment cmnt(masm_, "[ UnloadReference"); 619 Comment cmnt(masm_, "[ UnloadReference");
568 frame_->Nip(ref->size()); 620 frame_->Nip(ref->size());
569 } 621 }
570 622
571 623
624 void CodeGenerator::Branch(Condition cc,
625 JumpTarget* true_target,
626 JumpTarget* false_target,
627 JumpTarget* fall_through) {
628 ASSERT(!fall_through->is_bound());
629 if (fall_through == false_target) {
630 true_target->Branch(cc);
631 false_target->Bind();
632 } else {
633 ASSERT(fall_through == true_target);
634 false_target->Branch(NegateCondition(cc));
635 true_target->Bind();
636 }
637 }
638
639
572 class ToBooleanStub: public CodeStub { 640 class ToBooleanStub: public CodeStub {
573 public: 641 public:
574 ToBooleanStub() { } 642 ToBooleanStub() { }
575 643
576 void Generate(MacroAssembler* masm); 644 void Generate(MacroAssembler* masm);
577 645
578 private: 646 private:
579 Major MajorKey() { return ToBoolean; } 647 Major MajorKey() { return ToBoolean; }
580 int MinorKey() { return 0; } 648 int MinorKey() { return 0; }
581 }; 649 };
582 650
583 651
584 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and 652 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and
585 // convert it to a boolean in the condition code register or jump to 653 // convert it to a boolean in the condition code register or jump to
586 // 'false_target'/'true_target' as appropriate. 654 // 'false_target'/'true_target' as appropriate.
587 void CodeGenerator::ToBoolean(JumpTarget* true_target, 655 void CodeGenerator::ToBoolean(JumpTarget* true_target,
588 JumpTarget* false_target) { 656 JumpTarget* false_target,
657 JumpTarget* fall_through) {
589 Comment cmnt(masm_, "[ ToBoolean"); 658 Comment cmnt(masm_, "[ ToBoolean");
590 659
591 // The value to convert should be popped from the stack. 660 // The value to convert should be popped from the stack.
592 Result value = frame_->Pop(); 661 Result value = frame_->Pop();
593 value.ToRegister(); 662 value.ToRegister();
594 // Fast case checks. 663 // Fast case checks.
595 664
596 // 'false' => false. 665 // 'false' => false.
597 __ cmp(value.reg(), Factory::false_value()); 666 __ cmp(value.reg(), Factory::false_value());
598 false_target->Branch(equal); 667 false_target->Branch(equal);
(...skipping 13 matching lines...) Expand all
612 __ test(value.reg(), Immediate(kSmiTagMask)); 681 __ test(value.reg(), Immediate(kSmiTagMask));
613 true_target->Branch(zero); 682 true_target->Branch(zero);
614 683
615 // Call the stub for all other cases. 684 // Call the stub for all other cases.
616 frame_->Push(&value); // Undo the Pop() from above. 685 frame_->Push(&value); // Undo the Pop() from above.
617 ToBooleanStub stub; 686 ToBooleanStub stub;
618 Result temp = frame_->CallStub(&stub, 1); 687 Result temp = frame_->CallStub(&stub, 1);
619 // Convert the result to a condition code. 688 // Convert the result to a condition code.
620 __ test(temp.reg(), Operand(temp.reg())); 689 __ test(temp.reg(), Operand(temp.reg()));
621 temp.Unuse(); 690 temp.Unuse();
622 true_target->Branch(not_equal); 691 Branch(not_equal, true_target, false_target, fall_through);
623 false_target->Jump();
624 } 692 }
625 693
626 694
627 class FloatingPointHelper : public AllStatic { 695 class FloatingPointHelper : public AllStatic {
628 public: 696 public:
629 // Code pattern for loading floating point values. Input values must 697 // Code pattern for loading floating point values. Input values must
630 // be either smi or heap number objects (fp values). Requirements: 698 // be either smi or heap number objects (fp values). Requirements:
631 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as 699 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as
632 // floating point numbers on FPU stack. 700 // floating point numbers on FPU stack.
633 static void LoadFloatOperands(MacroAssembler* masm, Register scratch); 701 static void LoadFloatOperands(MacroAssembler* masm, Register scratch);
(...skipping 608 matching lines...) Expand 10 before | Expand all | Expand 10 after
1242 static_cast<int>(cc_), 1310 static_cast<int>(cc_),
1243 strict_ ? "true" : "false"); 1311 strict_ ? "true" : "false");
1244 } 1312 }
1245 #endif 1313 #endif
1246 }; 1314 };
1247 1315
1248 1316
1249 void CodeGenerator::Comparison(Condition cc, 1317 void CodeGenerator::Comparison(Condition cc,
1250 bool strict, 1318 bool strict,
1251 JumpTarget* true_target, 1319 JumpTarget* true_target,
1252 JumpTarget* false_target) { 1320 JumpTarget* false_target,
1321 JumpTarget* fall_through) {
1253 // Strict only makes sense for equality comparisons. 1322 // Strict only makes sense for equality comparisons.
1254 ASSERT(!strict || cc == equal); 1323 ASSERT(!strict || cc == equal);
1255 1324
1256 Result left_side(this); 1325 Result left_side(this);
1257 Result right_side(this); 1326 Result right_side(this);
1258 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. 1327 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
1259 if (cc == greater || cc == less_equal) { 1328 if (cc == greater || cc == less_equal) {
1260 cc = ReverseCondition(cc); 1329 cc = ReverseCondition(cc);
1261 left_side = frame_->Pop(); 1330 left_side = frame_->Pop();
1262 right_side = frame_->Pop(); 1331 right_side = frame_->Pop();
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1303 answer.Unuse(); 1372 answer.Unuse();
1304 true_target->Branch(cc); 1373 true_target->Branch(cc);
1305 false_target->Jump(); 1374 false_target->Jump();
1306 1375
1307 is_smi.Bind(&left_side, &right_side); 1376 is_smi.Bind(&left_side, &right_side);
1308 left_side.ToRegister(); 1377 left_side.ToRegister();
1309 right_side.ToRegister(); 1378 right_side.ToRegister();
1310 __ cmp(left_side.reg(), Operand(right_side.reg())); 1379 __ cmp(left_side.reg(), Operand(right_side.reg()));
1311 right_side.Unuse(); 1380 right_side.Unuse();
1312 left_side.Unuse(); 1381 left_side.Unuse();
1313 true_target->Branch(cc); 1382 Branch(cc, true_target, false_target, fall_through);
1314 false_target->Jump();
1315 } 1383 }
1316 1384
1317 1385
1318 void CodeGenerator::SmiComparison(Condition cc, 1386 void CodeGenerator::SmiComparison(Condition cc,
1319 Handle<Object> smi_value, 1387 Handle<Object> smi_value,
1320 bool strict) { 1388 bool strict) {
1321 // Strict only makes sense for equality comparisons. 1389 // Strict only makes sense for equality comparisons.
1322 ASSERT(!strict || cc == equal); 1390 ASSERT(!strict || cc == equal);
1323 ASSERT(is_intn(Smi::cast(*smi_value)->value(), kMaxSmiInlinedBits)); 1391 ASSERT(is_intn(Smi::cast(*smi_value)->value(), kMaxSmiInlinedBits));
1324 1392
(...skipping 15 matching lines...) Expand all
1340 __ cmp(result.reg(), 0); 1408 __ cmp(result.reg(), 0);
1341 result.Unuse(); 1409 result.Unuse();
1342 true_target()->Branch(cc); 1410 true_target()->Branch(cc);
1343 false_target()->Jump(); 1411 false_target()->Jump();
1344 1412
1345 is_smi.Bind(&comparee); 1413 is_smi.Bind(&comparee);
1346 comparee.ToRegister(); 1414 comparee.ToRegister();
1347 // Test smi equality and comparison by signed int comparison. 1415 // Test smi equality and comparison by signed int comparison.
1348 __ cmp(Operand(comparee.reg()), Immediate(smi_value)); 1416 __ cmp(Operand(comparee.reg()), Immediate(smi_value));
1349 comparee.Unuse(); 1417 comparee.Unuse();
1350 true_target()->Branch(cc); 1418 Branch(cc);
1351 false_target()->Jump();
1352 } 1419 }
1353 1420
1354 1421
1355 class CallFunctionStub: public CodeStub { 1422 class CallFunctionStub: public CodeStub {
1356 public: 1423 public:
1357 explicit CallFunctionStub(int argc) : argc_(argc) { } 1424 explicit CallFunctionStub(int argc) : argc_(argc) { }
1358 1425
1359 void Generate(MacroAssembler* masm); 1426 void Generate(MacroAssembler* masm);
1360 1427
1361 private: 1428 private:
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
1547 // Generate different code depending on which parts of the if statement 1614 // Generate different code depending on which parts of the if statement
1548 // are present or not. 1615 // are present or not.
1549 bool has_then_stm = node->HasThenStatement(); 1616 bool has_then_stm = node->HasThenStatement();
1550 bool has_else_stm = node->HasElseStatement(); 1617 bool has_else_stm = node->HasElseStatement();
1551 1618
1552 CodeForStatementPosition(node); 1619 CodeForStatementPosition(node);
1553 JumpTarget exit(this); 1620 JumpTarget exit(this);
1554 if (has_then_stm && has_else_stm) { 1621 if (has_then_stm && has_else_stm) {
1555 JumpTarget then(this); 1622 JumpTarget then(this);
1556 JumpTarget else_(this); 1623 JumpTarget else_(this);
1557 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); 1624 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF,
1558 if (then.is_linked()) { 1625 &then, &else_, &then, true);
1559 then.Bind(); 1626 if (then.is_bound()) {
1560 Visit(node->then_statement()); 1627 Visit(node->then_statement());
1561 if (has_valid_frame() && else_.is_linked()) { 1628 if (else_.is_linked()) {
1562 // We have fallen through from the then block and we need to compile 1629 if (has_valid_frame()) {
1563 // the else block. Emit an unconditional jump around it. 1630 exit.Jump();
1564 exit.Jump(); 1631 }
1632 else_.Bind();
1565 } 1633 }
1566 } 1634 }
1567 if (else_.is_linked()) { 1635 if (else_.is_bound()) {
1568 else_.Bind();
1569 Visit(node->else_statement()); 1636 Visit(node->else_statement());
1570 } 1637 }
1571 1638
1572 } else if (has_then_stm) { 1639 } else if (has_then_stm) {
1573 ASSERT(!has_else_stm); 1640 ASSERT(!has_else_stm);
1574 JumpTarget then(this); 1641 JumpTarget then(this);
1575 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); 1642 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF,
1576 if (then.is_linked()) { 1643 &then, &exit, &then, true);
1577 then.Bind(); 1644 if (then.is_bound()) {
1578 Visit(node->then_statement()); 1645 Visit(node->then_statement());
1579 } 1646 }
1580 1647
1581 } else if (has_else_stm) { 1648 } else if (has_else_stm) {
1582 ASSERT(!has_then_stm); 1649 ASSERT(!has_then_stm);
1583 JumpTarget else_(this); 1650 JumpTarget else_(this);
1584 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); 1651 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF,
1585 if (else_.is_linked()) { 1652 &exit, &else_, &else_, true);
1586 else_.Bind(); 1653 if (else_.is_bound()) {
1587 Visit(node->else_statement()); 1654 Visit(node->else_statement());
1588 } 1655 }
1589 1656
1590 } else { 1657 } else {
1591 ASSERT(!has_then_stm && !has_else_stm); 1658 ASSERT(!has_then_stm && !has_else_stm);
1592 // We only care about the condition's side effects (not its value 1659 // We only care about the condition's side effects (not its value
1593 // or control flow effect). LoadCondition is called without 1660 // or control flow effect). LoadCondition is called without
1594 // forcing control flow. 1661 // forcing control flow.
1595 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); 1662 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF,
1596 if (has_valid_frame()) { 1663 &exit, &exit, &exit, false);
1597 // Control flow can fall off the end of the condition with a 1664 if (!exit.is_bound()) {
1598 // value on the frame.
1599 frame_->Drop(); 1665 frame_->Drop();
1600 } 1666 }
1601 } 1667 }
1602 1668
1603 exit.Bind(); 1669 exit.Bind();
1604 } 1670 }
1605 1671
1606 1672
1607 void CodeGenerator::CleanStack(int num_bytes) { 1673 void CodeGenerator::CleanStack(int num_bytes) {
1608 ASSERT(num_bytes % kPointerSize == 0); 1674 ASSERT(num_bytes % kPointerSize == 0);
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
1891 // Label and compile the test. 1957 // Label and compile the test.
1892 if (next_test.is_linked()) { 1958 if (next_test.is_linked()) {
1893 // Recycle the same label for each test. 1959 // Recycle the same label for each test.
1894 next_test.Bind(); 1960 next_test.Bind();
1895 next_test.Unuse(); 1961 next_test.Unuse();
1896 } 1962 }
1897 // Duplicate the switch value. 1963 // Duplicate the switch value.
1898 frame_->Dup(); 1964 frame_->Dup();
1899 Load(clause->label()); 1965 Load(clause->label());
1900 JumpTarget enter_body(this); 1966 JumpTarget enter_body(this);
1901 Comparison(equal, true, &enter_body, &next_test); 1967 Comparison(equal, true, &enter_body, &next_test, &enter_body);
1902 1968
1903 // Before entering the body from the test remove the switch value from 1969 // Before entering the body from the test remove the switch value from
1904 // the frame. 1970 // the frame.
1905 enter_body.Bind();
1906 frame_->Drop(); 1971 frame_->Drop();
1907 1972
1908 // Label the body so that fall through is enabled. 1973 // Label the body so that fall through is enabled.
1909 if (i > 0 && cases->at(i - 1)->is_default()) { 1974 if (i > 0 && cases->at(i - 1)->is_default()) {
1910 // The previous case was the default. This will be the target of a 1975 // The previous case was the default. This will be the target of a
1911 // possible backward edge. 1976 // possible backward edge.
1912 default_exit.Bind(); 1977 default_exit.Bind();
1913 } else if (fall_through.is_linked()) { 1978 } else if (fall_through.is_linked()) {
1914 // Recycle the same label for each fall through except for the default 1979 // Recycle the same label for each fall through except for the default
1915 // case. 1980 // case.
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
2008 } else if (info == ALWAYS_FALSE) { 2073 } else if (info == ALWAYS_FALSE) {
2009 // If we had a continue in the body we have to bind its jump target. 2074 // If we had a continue in the body we have to bind its jump target.
2010 node->continue_target()->Bind(); 2075 node->continue_target()->Bind();
2011 } else { 2076 } else {
2012 ASSERT(info == DONT_KNOW); 2077 ASSERT(info == DONT_KNOW);
2013 // We have to compile the test expression if it can be reached by 2078 // We have to compile the test expression if it can be reached by
2014 // control flow falling out of the body or via continue. 2079 // control flow falling out of the body or via continue.
2015 node->continue_target()->Bind(); 2080 node->continue_target()->Bind();
2016 if (has_valid_frame()) { 2081 if (has_valid_frame()) {
2017 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, 2082 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
2018 &body, node->break_target(), true); 2083 &body, node->break_target(), node->break_target(),
2084 true);
2019 } 2085 }
2020 } 2086 }
2021 break; 2087 break;
2022 } 2088 }
2023 2089
2024 case LoopStatement::WHILE_LOOP: { 2090 case LoopStatement::WHILE_LOOP: {
2025 IncrementLoopNesting(); 2091 IncrementLoopNesting();
2026 2092
2027 // If the test is never true and has no side effects there is no need 2093 // If the test is never true and has no side effects there is no need
2028 // to compile the test or body. 2094 // to compile the test or body.
2029 if (info == ALWAYS_FALSE) break; 2095 if (info == ALWAYS_FALSE) break;
2030 2096
2031 // Label the top of the loop with the continue target for the backward 2097 // Label the top of the loop with the continue target for the backward
2032 // CFG edge. 2098 // CFG edge.
2033 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); 2099 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
2034 node->continue_target()->Bind(); 2100 node->continue_target()->Bind();
2035 2101
2036 // If the test is always true and has no side effects there is no need 2102 // If the test is always true and has no side effects there is no need
2037 // to compile it. We only compile the test when we do not know its 2103 // to compile it. We only compile the test when we do not know its
2038 // outcome or it may have side effects. 2104 // outcome or it may have side effects.
2039 if (info == DONT_KNOW) { 2105 if (info == DONT_KNOW) {
2040 JumpTarget body(this); 2106 JumpTarget body(this);
2041 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, 2107 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
2042 &body, node->break_target(), true); 2108 &body, node->break_target(), &body, true);
2043 body.Bind();
2044 } 2109 }
2045 2110
2046 if (has_valid_frame()) { 2111 if (!node->break_target()->is_bound()) {
2047 CheckStack(); // TODO(1222600): ignore if body contains calls. 2112 CheckStack(); // TODO(1222600): ignore if body contains calls.
2048 Visit(node->body()); 2113 Visit(node->body());
2049 2114
2050 // If control flow can fall out of the body, jump back to the top. 2115 // If control flow can fall out of the body, jump back to the top.
2051 if (has_valid_frame()) { 2116 if (has_valid_frame()) {
2052 node->continue_target()->Jump(); 2117 node->continue_target()->Jump();
2053 } 2118 }
2054 } 2119 }
2055 break; 2120 break;
2056 } 2121 }
(...skipping 18 matching lines...) Expand all
2075 node->continue_target()->Initialize(this); 2140 node->continue_target()->Initialize(this);
2076 loop.Bind(); 2141 loop.Bind();
2077 } 2142 }
2078 2143
2079 // If the test is always true and has no side effects there is no need 2144 // If the test is always true and has no side effects there is no need
2080 // to compile it. We only compile the test when we do not know its 2145 // to compile it. We only compile the test when we do not know its
2081 // outcome or it has side effects. 2146 // outcome or it has side effects.
2082 if (info == DONT_KNOW) { 2147 if (info == DONT_KNOW) {
2083 JumpTarget body(this); 2148 JumpTarget body(this);
2084 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, 2149 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
2085 &body, node->break_target(), true); 2150 &body, node->break_target(), &body, true);
2086 body.Bind();
2087 } 2151 }
2088 2152
2089 if (has_valid_frame()) { 2153 if (!node->break_target()->is_bound()) {
2090 CheckStack(); // TODO(1222600): ignore if body contains calls. 2154 CheckStack(); // TODO(1222600): ignore if body contains calls.
2091 Visit(node->body()); 2155 Visit(node->body());
2092 2156
2093 if (node->next() == NULL) { 2157 if (node->next() == NULL) {
2094 // If there is no update statement and control flow can fall out 2158 // If there is no update statement and control flow can fall out
2095 // of the loop, jump to the continue label. 2159 // of the loop, jump to the continue label.
2096 if (has_valid_frame()) { 2160 if (has_valid_frame()) {
2097 node->continue_target()->Jump(); 2161 node->continue_target()->Jump();
2098 } 2162 }
2099 } else { 2163 } else {
(...skipping 10 matching lines...) Expand all
2110 Visit(node->next()); 2174 Visit(node->next());
2111 loop.Jump(); 2175 loop.Jump();
2112 } 2176 }
2113 } 2177 }
2114 } 2178 }
2115 break; 2179 break;
2116 } 2180 }
2117 } 2181 }
2118 2182
2119 DecrementLoopNesting(); 2183 DecrementLoopNesting();
2120 node->break_target()->Bind(); 2184 // The break target may have been bound in the condition of a do
2185 // loop, or in the conditions of the other loops if they are
2186 // unconditionally false. Avoid rebinding it.
2187 if (node->break_target()->is_linked()) {
2188 node->break_target()->Bind();
2189 }
2121 } 2190 }
2122 2191
2123 2192
2124 void CodeGenerator::VisitForInStatement(ForInStatement* node) { 2193 void CodeGenerator::VisitForInStatement(ForInStatement* node) {
2125 ASSERT(!in_spilled_code()); 2194 ASSERT(!in_spilled_code());
2126 VirtualFrame::SpilledScope spilled_scope(this); 2195 VirtualFrame::SpilledScope spilled_scope(this);
2127 Comment cmnt(masm_, "[ ForInStatement"); 2196 Comment cmnt(masm_, "[ ForInStatement");
2128 CodeForStatementPosition(node); 2197 CodeForStatementPosition(node);
2129 2198
2130 // We keep stuff on the stack while the body is executing. 2199 // We keep stuff on the stack while the body is executing.
(...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after
2649 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); 2718 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
2650 InstantiateBoilerplate(node->boilerplate()); 2719 InstantiateBoilerplate(node->boilerplate());
2651 } 2720 }
2652 2721
2653 2722
2654 void CodeGenerator::VisitConditional(Conditional* node) { 2723 void CodeGenerator::VisitConditional(Conditional* node) {
2655 Comment cmnt(masm_, "[ Conditional"); 2724 Comment cmnt(masm_, "[ Conditional");
2656 JumpTarget then(this); 2725 JumpTarget then(this);
2657 JumpTarget else_(this); 2726 JumpTarget else_(this);
2658 JumpTarget exit(this); 2727 JumpTarget exit(this);
2659 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); 2728 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF,
2660 if (then.is_linked()) { 2729 &then, &else_, &then, true);
2661 then.Bind(); 2730 if (then.is_bound()) {
2662 Load(node->then_expression(), typeof_state()); 2731 Load(node->then_expression(), typeof_state());
2663 if (else_.is_linked()) { 2732 if (else_.is_linked()) {
2664 exit.Jump(); 2733 exit.Jump();
2734 else_.Bind();
2665 } 2735 }
2666 } 2736 }
2667 2737 if (else_.is_bound()) {
2668 if (else_.is_linked()) {
2669 else_.Bind();
2670 Load(node->else_expression(), typeof_state()); 2738 Load(node->else_expression(), typeof_state());
2671 } 2739 }
2672
2673 exit.Bind(); 2740 exit.Bind();
2674 } 2741 }
2675 2742
2676 2743
2677 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { 2744 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
2678 if (slot->type() == Slot::LOOKUP) { 2745 if (slot->type() == Slot::LOOKUP) {
2679 ASSERT(slot->var()->mode() == Variable::DYNAMIC); 2746 ASSERT(slot->var()->mode() == Variable::DYNAMIC);
2680 2747
2681 // For now, just do a runtime call. 2748 // For now, just do a runtime call.
2682 frame_->Push(esi); 2749 frame_->Push(esi);
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
2817 Comment cmnt(masm_, "[ Slot"); 2884 Comment cmnt(masm_, "[ Slot");
2818 LoadFromSlot(node, typeof_state()); 2885 LoadFromSlot(node, typeof_state());
2819 } 2886 }
2820 2887
2821 2888
2822 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { 2889 void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
2823 Comment cmnt(masm_, "[ VariableProxy"); 2890 Comment cmnt(masm_, "[ VariableProxy");
2824 Variable* var = node->var(); 2891 Variable* var = node->var();
2825 Expression* expr = var->rewrite(); 2892 Expression* expr = var->rewrite();
2826 if (expr != NULL) { 2893 if (expr != NULL) {
2827 // We have to be wary of calling Visit directly on expressions. Because
2828 // of special casing comparisons of the form typeof<expr> === "string",
2829 // we can return from a call from Visit (to a comparison or a unary
2830 // operation) without a virtual frame; which will probably crash if we
2831 // try to emit frame code before reestablishing a frame. Here we're
2832 // safe as long as variable proxies can't rewrite into typeof
2833 // comparisons or unary logical not expressions.
2834 Visit(expr); 2894 Visit(expr);
2835 ASSERT(has_valid_frame());
2836 } else { 2895 } else {
2837 ASSERT(var->is_global()); 2896 ASSERT(var->is_global());
2838 Reference ref(this, node); 2897 Reference ref(this, node);
2839 ref.GetValue(typeof_state()); 2898 ref.GetValue(typeof_state());
2840 } 2899 }
2841 } 2900 }
2842 2901
2843 2902
2844 void CodeGenerator::VisitLiteral(Literal* node) { 2903 void CodeGenerator::VisitLiteral(Literal* node) {
2845 Comment cmnt(masm_, "[ Literal"); 2904 Comment cmnt(masm_, "[ Literal");
(...skipping 599 matching lines...) Expand 10 before | Expand all | Expand 10 after
3445 3504
3446 3505
3447 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { 3506 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
3448 ASSERT(args->length() == 1); 3507 ASSERT(args->length() == 1);
3449 Load(args->at(0)); 3508 Load(args->at(0));
3450 Result value = frame_->Pop(); 3509 Result value = frame_->Pop();
3451 value.ToRegister(); 3510 value.ToRegister();
3452 ASSERT(value.is_valid()); 3511 ASSERT(value.is_valid());
3453 __ test(value.reg(), Immediate(kSmiTagMask)); 3512 __ test(value.reg(), Immediate(kSmiTagMask));
3454 value.Unuse(); 3513 value.Unuse();
3455 true_target()->Branch(zero); 3514 Branch(zero);
3456 false_target()->Jump();
3457 } 3515 }
3458 3516
3459 3517
3460 void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) { 3518 void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) {
3461 // Conditionally generate a log call. 3519 // Conditionally generate a log call.
3462 // Args: 3520 // Args:
3463 // 0 (literal string): The type of logging (corresponds to the flags). 3521 // 0 (literal string): The type of logging (corresponds to the flags).
3464 // This is used to determine whether or not to generate the log call. 3522 // This is used to determine whether or not to generate the log call.
3465 // 1 (string): Format string. Access the string at argument index 2 3523 // 1 (string): Format string. Access the string at argument index 2
3466 // with '%2s' (see Logger::LogRuntime for all the formats). 3524 // with '%2s' (see Logger::LogRuntime for all the formats).
(...skipping 12 matching lines...) Expand all
3479 3537
3480 3538
3481 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { 3539 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
3482 ASSERT(args->length() == 1); 3540 ASSERT(args->length() == 1);
3483 Load(args->at(0)); 3541 Load(args->at(0));
3484 Result value = frame_->Pop(); 3542 Result value = frame_->Pop();
3485 value.ToRegister(); 3543 value.ToRegister();
3486 ASSERT(value.is_valid()); 3544 ASSERT(value.is_valid());
3487 __ test(value.reg(), Immediate(kSmiTagMask | 0x80000000)); 3545 __ test(value.reg(), Immediate(kSmiTagMask | 0x80000000));
3488 value.Unuse(); 3546 value.Unuse();
3489 true_target()->Branch(zero); 3547 Branch(zero);
3490 false_target()->Jump();
3491 } 3548 }
3492 3549
3493 3550
3494 // This generates code that performs a charCodeAt() call or returns 3551 // This generates code that performs a charCodeAt() call or returns
3495 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. 3552 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
3496 // It can handle flat and sliced strings, 8 and 16 bit characters and 3553 // It can handle flat and sliced strings, 8 and 16 bit characters and
3497 // cons strings where the answer is found in the left hand branch of the 3554 // cons strings where the answer is found in the left hand branch of the
3498 // cons. The slow case will flatten the string, which will ensure that 3555 // cons. The slow case will flatten the string, which will ensure that
3499 // the answer is in the left hand side the next time around. 3556 // the answer is in the left hand side the next time around.
3500 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { 3557 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
3641 false_target()->Branch(equal); 3698 false_target()->Branch(equal);
3642 // It is a heap object - get map. 3699 // It is a heap object - get map.
3643 Result temp = allocator()->Allocate(); 3700 Result temp = allocator()->Allocate();
3644 ASSERT(temp.is_valid()); 3701 ASSERT(temp.is_valid());
3645 __ mov(temp.reg(), FieldOperand(value.reg(), HeapObject::kMapOffset)); 3702 __ mov(temp.reg(), FieldOperand(value.reg(), HeapObject::kMapOffset));
3646 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); 3703 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
3647 // Check if the object is a JS array or not. 3704 // Check if the object is a JS array or not.
3648 __ cmp(temp.reg(), JS_ARRAY_TYPE); 3705 __ cmp(temp.reg(), JS_ARRAY_TYPE);
3649 value.Unuse(); 3706 value.Unuse();
3650 temp.Unuse(); 3707 temp.Unuse();
3651 true_target()->Branch(equal); 3708 Branch(equal);
3652 false_target()->Jump();
3653 } 3709 }
3654 3710
3655 3711
3656 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { 3712 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
3657 ASSERT(args->length() == 0); 3713 ASSERT(args->length() == 0);
3658 Result initial_value = allocator()->Allocate(eax); 3714 Result initial_value = allocator()->Allocate(eax);
3659 ASSERT(initial_value.is_valid()); 3715 ASSERT(initial_value.is_valid());
3660 __ Set(initial_value.reg(), 3716 __ Set(initial_value.reg(),
3661 Immediate(Smi::FromInt(scope_->num_parameters()))); 3717 Immediate(Smi::FromInt(scope_->num_parameters())));
3662 // ArgumentsAccessStub takes the parameter count as an input argument 3718 // ArgumentsAccessStub takes the parameter count as an input argument
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
3747 // Load the two objects into registers and perform the comparison. 3803 // Load the two objects into registers and perform the comparison.
3748 Load(args->at(0)); 3804 Load(args->at(0));
3749 Load(args->at(1)); 3805 Load(args->at(1));
3750 Result right = frame_->Pop(); 3806 Result right = frame_->Pop();
3751 Result left = frame_->Pop(); 3807 Result left = frame_->Pop();
3752 right.ToRegister(); 3808 right.ToRegister();
3753 left.ToRegister(); 3809 left.ToRegister();
3754 __ cmp(right.reg(), Operand(left.reg())); 3810 __ cmp(right.reg(), Operand(left.reg()));
3755 right.Unuse(); 3811 right.Unuse();
3756 left.Unuse(); 3812 left.Unuse();
3757 true_target()->Branch(equal); 3813 Branch(equal);
3758 false_target()->Jump();
3759 } 3814 }
3760 3815
3761 3816
3762 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { 3817 void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
3763 if (CheckForInlineRuntimeCall(node)) { 3818 if (CheckForInlineRuntimeCall(node)) {
3764 return; 3819 return;
3765 } 3820 }
3766 3821
3767 ZoneList<Expression*>* args = node->arguments(); 3822 ZoneList<Expression*>* args = node->arguments();
3768 Comment cmnt(masm_, "[ CallRuntime"); 3823 Comment cmnt(masm_, "[ CallRuntime");
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
3807 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { 3862 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
3808 // Note that because of NOT and an optimization in comparison of a typeof 3863 // Note that because of NOT and an optimization in comparison of a typeof
3809 // expression to a literal string, this function can fail to leave a value 3864 // expression to a literal string, this function can fail to leave a value
3810 // on top of the frame or in the cc register. 3865 // on top of the frame or in the cc register.
3811 Comment cmnt(masm_, "[ UnaryOperation"); 3866 Comment cmnt(masm_, "[ UnaryOperation");
3812 3867
3813 Token::Value op = node->op(); 3868 Token::Value op = node->op();
3814 3869
3815 if (op == Token::NOT) { 3870 if (op == Token::NOT) {
3816 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, 3871 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF,
3817 false_target(), true_target(), true); 3872 false_target(), true_target(), fall_through(), true);
3818 3873
3819 } else if (op == Token::DELETE) { 3874 } else if (op == Token::DELETE) {
3820 Property* property = node->expression()->AsProperty(); 3875 Property* property = node->expression()->AsProperty();
3821 if (property != NULL) { 3876 if (property != NULL) {
3822 Load(property->obj()); 3877 Load(property->obj());
3823 Load(property->key()); 3878 Load(property->key());
3824 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); 3879 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2);
3825 frame_->Push(&answer); 3880 frame_->Push(&answer);
3826 return; 3881 return;
3827 } 3882 }
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
4142 4197
4143 // NOTE: If the left hand side produces a materialized value (not in 4198 // NOTE: If the left hand side produces a materialized value (not in
4144 // the CC register), we force the right hand side to do the 4199 // the CC register), we force the right hand side to do the
4145 // same. This is necessary because we may have to branch to the exit 4200 // same. This is necessary because we may have to branch to the exit
4146 // after evaluating the left hand side (due to the shortcut 4201 // after evaluating the left hand side (due to the shortcut
4147 // semantics), but the compiler must (statically) know if the result 4202 // semantics), but the compiler must (statically) know if the result
4148 // of compiling the binary operation is materialized or not. 4203 // of compiling the binary operation is materialized or not.
4149 4204
4150 if (op == Token::AND) { 4205 if (op == Token::AND) {
4151 JumpTarget is_true(this); 4206 JumpTarget is_true(this);
4207 bool backward = false_target()->is_bound();
4152 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, 4208 LoadCondition(node->left(), NOT_INSIDE_TYPEOF,
4153 &is_true, false_target(), false); 4209 &is_true, false_target(), &is_true, false);
4154 if (!has_valid_frame()) { 4210 if (is_true.is_bound()) {
4155 if (is_true.is_linked()) { 4211 LoadCondition(node->right(), NOT_INSIDE_TYPEOF,
4156 // Evaluate right side expression. 4212 true_target(), false_target(), fall_through(),
4157 is_true.Bind(); 4213 false);
4158 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, 4214 } else if (!backward && false_target()->is_bound()) {
4159 true_target(), false_target(), false); 4215 // If the false target became bound due to the left operand,
4160 } 4216 // then that operand was unconditionally false.
4161 } else { 4217 return;
4218 } else if (has_valid_frame()) {
4162 // We have a materialized value on the frame. 4219 // We have a materialized value on the frame.
4163 JumpTarget pop_and_continue(this); 4220 JumpTarget pop_and_continue(this);
4164 JumpTarget exit(this); 4221 JumpTarget exit(this);
4165 4222
4166 // Avoid popping the result if it converts to 'false' using the 4223 // Avoid popping the result if it converts to 'false' using the
4167 // standard ToBoolean() conversion as described in ECMA-262, section 4224 // standard ToBoolean() conversion as described in ECMA-262, section
4168 // 9.2, page 30. 4225 // 9.2, page 30.
4169 // 4226 //
4170 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. 4227 // Duplicate the TOS value. The duplicate will be popped by ToBoolean.
4171 frame_->Dup(); 4228 frame_->Dup();
4172 ToBoolean(&pop_and_continue, &exit); 4229 ToBoolean(&pop_and_continue, &exit, &pop_and_continue);
4173 4230
4174 // Pop the result of evaluating the first part. 4231 // Pop the result of evaluating the first part.
4175 pop_and_continue.Bind();
4176 frame_->Drop(); 4232 frame_->Drop();
4177 4233
4178 // Evaluate right side expression. 4234 // Evaluate right side expression.
4179 is_true.Bind(); 4235 is_true.Bind();
4180 Load(node->right()); 4236 Load(node->right());
4181 4237
4182 // Exit (always with a materialized value). 4238 // Exit (always with a materialized value).
4183 exit.Bind(); 4239 exit.Bind();
4184 } 4240 }
4185 4241
4186 } else if (op == Token::OR) { 4242 } else if (op == Token::OR) {
4187 JumpTarget is_false(this); 4243 JumpTarget is_false(this);
4244 bool backward = true_target()->is_bound();
4188 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, 4245 LoadCondition(node->left(), NOT_INSIDE_TYPEOF,
4189 true_target(), &is_false, false); 4246 true_target(), &is_false, &is_false, false);
4190 if (!has_valid_frame()) { 4247 if (is_false.is_bound()) {
4191 if (is_false.is_linked()) { 4248 LoadCondition(node->right(), NOT_INSIDE_TYPEOF,
4192 // Evaluate right side expression. 4249 true_target(), false_target(), fall_through(),
4193 is_false.Bind(); 4250 false);
4194 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, 4251 } else if (!backward && true_target()->is_bound()) {
4195 true_target(), false_target(), false); 4252 // If the true target became bound due to the left operand, then
4196 } 4253 // that operand was unconditionally true.
4254 return;
4197 } else { 4255 } else {
4198 // We have a materialized value on the frame. 4256 // We have a materialized value on the frame.
4199 JumpTarget pop_and_continue(this); 4257 JumpTarget pop_and_continue(this);
4200 JumpTarget exit(this); 4258 JumpTarget exit(this);
4201 4259
4202 // Avoid popping the result if it converts to 'true' using the 4260 // Avoid popping the result if it converts to 'true' using the
4203 // standard ToBoolean() conversion as described in ECMA-262, 4261 // standard ToBoolean() conversion as described in ECMA-262,
4204 // section 9.2, page 30. 4262 // section 9.2, page 30.
4205 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. 4263 // Duplicate the TOS value. The duplicate will be popped by ToBoolean.
4206 frame_->Dup(); 4264 frame_->Dup();
4207 ToBoolean(&exit, &pop_and_continue); 4265 ToBoolean(&exit, &pop_and_continue, &pop_and_continue);
4208 4266
4209 // Pop the result of evaluating the first part. 4267 // Pop the result of evaluating the first part.
4210 pop_and_continue.Bind();
4211 frame_->Drop(); 4268 frame_->Drop();
4212 4269
4213 // Evaluate right side expression. 4270 // Evaluate right side expression.
4214 is_false.Bind(); 4271 is_false.Bind();
4215 Load(node->right()); 4272 Load(node->right());
4216 4273
4217 // Exit (always with a materialized value). 4274 // Exit (always with a materialized value).
4218 exit.Bind(); 4275 exit.Bind();
4219 } 4276 }
4220 4277
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
4308 // Use a scratch register in preference to spilling operand.reg(). 4365 // Use a scratch register in preference to spilling operand.reg().
4309 Result temp = allocator()->Allocate(); 4366 Result temp = allocator()->Allocate();
4310 ASSERT(temp.is_valid()); 4367 ASSERT(temp.is_valid());
4311 __ mov(temp.reg(), 4368 __ mov(temp.reg(),
4312 FieldOperand(operand.reg(), HeapObject::kMapOffset)); 4369 FieldOperand(operand.reg(), HeapObject::kMapOffset));
4313 __ movzx_b(temp.reg(), 4370 __ movzx_b(temp.reg(),
4314 FieldOperand(temp.reg(), Map::kBitFieldOffset)); 4371 FieldOperand(temp.reg(), Map::kBitFieldOffset));
4315 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); 4372 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
4316 cc = not_zero; 4373 cc = not_zero;
4317 } 4374 }
4375
4318 operand.Unuse(); 4376 operand.Unuse();
4319 true_target()->Branch(cc); 4377 Branch(cc);
4320 false_target()->Jump();
4321 return; 4378 return;
4322 } 4379 }
4323 } 4380 }
4324 4381
4325 // To make typeof testing for natives implemented in JavaScript really 4382 // To make typeof testing for natives implemented in JavaScript really
4326 // efficient, we generate special code for expressions of the form: 4383 // efficient, we generate special code for expressions of the form:
4327 // 'typeof <expression> == <string>'. 4384 // 'typeof <expression> == <string>'.
4328 UnaryOperation* operation = left->AsUnaryOperation(); 4385 UnaryOperation* operation = left->AsUnaryOperation();
4329 if ((op == Token::EQ || op == Token::EQ_STRICT) && 4386 if ((op == Token::EQ || op == Token::EQ_STRICT) &&
4330 (operation != NULL && operation->op() == Token::TYPEOF) && 4387 (operation != NULL && operation->op() == Token::TYPEOF) &&
4331 (right->AsLiteral() != NULL && 4388 (right->AsLiteral() != NULL &&
4332 right->AsLiteral()->handle()->IsString())) { 4389 right->AsLiteral()->handle()->IsString())) {
4333 Handle<String> check(String::cast(*right->AsLiteral()->handle())); 4390 Handle<String> check(String::cast(*right->AsLiteral()->handle()));
4334 4391
4335 // Load the operand and move it to a register. 4392 // Load the operand and move it to a register.
4336 LoadTypeofExpression(operation->expression()); 4393 LoadTypeofExpression(operation->expression());
4337 Result answer = frame_->Pop(); 4394 Result answer = frame_->Pop();
4338 answer.ToRegister(); 4395 answer.ToRegister();
4339 4396
4340 if (check->Equals(Heap::number_symbol())) { 4397 if (check->Equals(Heap::number_symbol())) {
4341 __ test(answer.reg(), Immediate(kSmiTagMask)); 4398 __ test(answer.reg(), Immediate(kSmiTagMask));
4342 true_target()->Branch(zero); 4399 true_target()->Branch(zero);
4343 frame_->Spill(answer.reg()); 4400 frame_->Spill(answer.reg());
4344 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); 4401 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
4345 __ cmp(answer.reg(), Factory::heap_number_map()); 4402 __ cmp(answer.reg(), Factory::heap_number_map());
4346 answer.Unuse(); 4403 answer.Unuse();
4347 true_target()->Branch(equal); 4404 Branch(equal);
4348 false_target()->Jump();
4349 4405
4350 } else if (check->Equals(Heap::string_symbol())) { 4406 } else if (check->Equals(Heap::string_symbol())) {
4351 __ test(answer.reg(), Immediate(kSmiTagMask)); 4407 __ test(answer.reg(), Immediate(kSmiTagMask));
4352 false_target()->Branch(zero); 4408 false_target()->Branch(zero);
4353 4409
4354 // It can be an undetectable string object. 4410 // It can be an undetectable string object.
4355 Result temp = allocator()->Allocate(); 4411 Result temp = allocator()->Allocate();
4356 ASSERT(temp.is_valid()); 4412 ASSERT(temp.is_valid());
4357 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); 4413 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
4358 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset)); 4414 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset));
4359 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); 4415 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
4360 false_target()->Branch(not_zero); 4416 false_target()->Branch(not_zero);
4361 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); 4417 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
4362 __ movzx_b(temp.reg(), 4418 __ movzx_b(temp.reg(),
4363 FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); 4419 FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
4364 __ cmp(temp.reg(), FIRST_NONSTRING_TYPE); 4420 __ cmp(temp.reg(), FIRST_NONSTRING_TYPE);
4365 temp.Unuse(); 4421 temp.Unuse();
4366 answer.Unuse(); 4422 answer.Unuse();
4367 true_target()->Branch(less); 4423 Branch(less);
4368 false_target()->Jump();
4369 4424
4370 } else if (check->Equals(Heap::boolean_symbol())) { 4425 } else if (check->Equals(Heap::boolean_symbol())) {
4371 __ cmp(answer.reg(), Factory::true_value()); 4426 __ cmp(answer.reg(), Factory::true_value());
4372 true_target()->Branch(equal); 4427 true_target()->Branch(equal);
4373 __ cmp(answer.reg(), Factory::false_value()); 4428 __ cmp(answer.reg(), Factory::false_value());
4374 answer.Unuse(); 4429 answer.Unuse();
4375 true_target()->Branch(equal); 4430 Branch(equal);
4376 false_target()->Jump();
4377 4431
4378 } else if (check->Equals(Heap::undefined_symbol())) { 4432 } else if (check->Equals(Heap::undefined_symbol())) {
4379 __ cmp(answer.reg(), Factory::undefined_value()); 4433 __ cmp(answer.reg(), Factory::undefined_value());
4380 true_target()->Branch(equal); 4434 true_target()->Branch(equal);
4381 4435
4382 __ test(answer.reg(), Immediate(kSmiTagMask)); 4436 __ test(answer.reg(), Immediate(kSmiTagMask));
4383 false_target()->Branch(zero); 4437 false_target()->Branch(zero);
4384 4438
4385 // It can be an undetectable object. 4439 // It can be an undetectable object.
4386 frame_->Spill(answer.reg()); 4440 frame_->Spill(answer.reg());
4387 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); 4441 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
4388 __ movzx_b(answer.reg(), 4442 __ movzx_b(answer.reg(),
4389 FieldOperand(answer.reg(), Map::kBitFieldOffset)); 4443 FieldOperand(answer.reg(), Map::kBitFieldOffset));
4390 __ test(answer.reg(), Immediate(1 << Map::kIsUndetectable)); 4444 __ test(answer.reg(), Immediate(1 << Map::kIsUndetectable));
4391 answer.Unuse(); 4445 answer.Unuse();
4392 true_target()->Branch(not_zero); 4446 Branch(not_zero);
4393 false_target()->Jump();
4394 4447
4395 } else if (check->Equals(Heap::function_symbol())) { 4448 } else if (check->Equals(Heap::function_symbol())) {
4396 __ test(answer.reg(), Immediate(kSmiTagMask)); 4449 __ test(answer.reg(), Immediate(kSmiTagMask));
4397 false_target()->Branch(zero); 4450 false_target()->Branch(zero);
4398 frame_->Spill(answer.reg()); 4451 frame_->Spill(answer.reg());
4399 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); 4452 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
4400 __ movzx_b(answer.reg(), 4453 __ movzx_b(answer.reg(),
4401 FieldOperand(answer.reg(), Map::kInstanceTypeOffset)); 4454 FieldOperand(answer.reg(), Map::kInstanceTypeOffset));
4402 __ cmp(answer.reg(), JS_FUNCTION_TYPE); 4455 __ cmp(answer.reg(), JS_FUNCTION_TYPE);
4403 answer.Unuse(); 4456 answer.Unuse();
4404 true_target()->Branch(equal); 4457 Branch(equal);
4405 false_target()->Jump();
4406 4458
4407 } else if (check->Equals(Heap::object_symbol())) { 4459 } else if (check->Equals(Heap::object_symbol())) {
4408 __ test(answer.reg(), Immediate(kSmiTagMask)); 4460 __ test(answer.reg(), Immediate(kSmiTagMask));
4409 false_target()->Branch(zero); 4461 false_target()->Branch(zero);
4410 __ cmp(answer.reg(), Factory::null_value()); 4462 __ cmp(answer.reg(), Factory::null_value());
4411 true_target()->Branch(equal); 4463 true_target()->Branch(equal);
4412 4464
4413 // It can be an undetectable object. 4465 // It can be an undetectable object.
4414 Result map = allocator()->Allocate(); 4466 Result map = allocator()->Allocate();
4415 ASSERT(map.is_valid()); 4467 ASSERT(map.is_valid());
4416 __ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); 4468 __ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
4417 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset)); 4469 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset));
4418 __ test(map.reg(), Immediate(1 << Map::kIsUndetectable)); 4470 __ test(map.reg(), Immediate(1 << Map::kIsUndetectable));
4419 false_target()->Branch(not_zero); 4471 false_target()->Branch(not_zero);
4420 __ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); 4472 __ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
4421 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset)); 4473 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset));
4422 __ cmp(map.reg(), FIRST_JS_OBJECT_TYPE); 4474 __ cmp(map.reg(), FIRST_JS_OBJECT_TYPE);
4423 false_target()->Branch(less); 4475 false_target()->Branch(less);
4424 __ cmp(map.reg(), LAST_JS_OBJECT_TYPE); 4476 __ cmp(map.reg(), LAST_JS_OBJECT_TYPE);
4425 answer.Unuse(); 4477 answer.Unuse();
4426 map.Unuse(); 4478 map.Unuse();
4427 true_target()->Branch(less_equal); 4479 Branch(less_equal);
4428 false_target()->Jump();
4429 } else { 4480 } else {
4430 // Uncommon case: typeof testing against a string literal that is 4481 // Uncommon case: typeof testing against a string literal that is
4431 // never returned from the typeof operator. 4482 // never returned from the typeof operator.
4432 answer.Unuse(); 4483 answer.Unuse();
4433 false_target()->Jump(); 4484 if (false_target()->is_bound()) {
4485 false_target()->Jump();
4486 } else {
4487 false_target()->Bind();
4488 }
4434 } 4489 }
4435 return; 4490 return;
4436 } 4491 }
4437 4492
4438 Condition cc = no_condition; 4493 Condition cc = no_condition;
4439 bool strict = false; 4494 bool strict = false;
4440 switch (op) { 4495 switch (op) {
4441 case Token::EQ_STRICT: 4496 case Token::EQ_STRICT:
4442 strict = true; 4497 strict = true;
4443 // Fall through 4498 // Fall through
(...skipping 20 matching lines...) Expand all
4464 return; 4519 return;
4465 } 4520 }
4466 case Token::INSTANCEOF: { 4521 case Token::INSTANCEOF: {
4467 Load(left); 4522 Load(left);
4468 Load(right); 4523 Load(right);
4469 InstanceofStub stub; 4524 InstanceofStub stub;
4470 Result answer = frame_->CallStub(&stub, 2); 4525 Result answer = frame_->CallStub(&stub, 2);
4471 answer.ToRegister(); 4526 answer.ToRegister();
4472 __ test(answer.reg(), Operand(answer.reg())); 4527 __ test(answer.reg(), Operand(answer.reg()));
4473 answer.Unuse(); 4528 answer.Unuse();
4474 true_target()->Branch(zero); 4529 Branch(zero);
4475 false_target()->Jump();
4476 return; 4530 return;
4477 } 4531 }
4478 default: 4532 default:
4479 UNREACHABLE(); 4533 UNREACHABLE();
4480 } 4534 }
4481 4535
4482 // Optimize for the case where (at least) one of the expressions 4536 // Optimize for the case where (at least) one of the expressions
4483 // is a literal small integer. 4537 // is a literal small integer.
4484 if (IsInlineSmi(left->AsLiteral())) { 4538 if (IsInlineSmi(left->AsLiteral())) {
4485 Load(right); 4539 Load(right);
4486 SmiComparison(ReverseCondition(cc), left->AsLiteral()->handle(), strict); 4540 SmiComparison(ReverseCondition(cc), left->AsLiteral()->handle(), strict);
4487 } else if (IsInlineSmi(right->AsLiteral())) { 4541 } else if (IsInlineSmi(right->AsLiteral())) {
4488 Load(left); 4542 Load(left);
4489 SmiComparison(cc, right->AsLiteral()->handle(), strict); 4543 SmiComparison(cc, right->AsLiteral()->handle(), strict);
4490 } else { 4544 } else {
4491 Load(left); 4545 Load(left);
4492 Load(right); 4546 Load(right);
4493 Comparison(cc, strict, true_target(), false_target()); 4547 Comparison(cc, strict, true_target(), false_target(), fall_through());
4494 } 4548 }
4495 } 4549 }
4496 4550
4497 4551
4498 #ifdef DEBUG 4552 #ifdef DEBUG
4499 bool CodeGenerator::HasValidEntryRegisters() { 4553 bool CodeGenerator::HasValidEntryRegisters() {
4500 return (allocator()->count(eax) == frame()->register_count(eax)) 4554 return (allocator()->count(eax) == frame()->register_count(eax))
4501 && (allocator()->count(ebx) == frame()->register_count(ebx)) 4555 && (allocator()->count(ebx) == frame()->register_count(ebx))
4502 && (allocator()->count(ecx) == frame()->register_count(ecx)) 4556 && (allocator()->count(ecx) == frame()->register_count(ecx))
4503 && (allocator()->count(edx) == frame()->register_count(edx)) 4557 && (allocator()->count(edx) == frame()->register_count(edx))
(...skipping 1794 matching lines...) Expand 10 before | Expand all | Expand 10 after
6298 6352
6299 // Slow-case: Go through the JavaScript implementation. 6353 // Slow-case: Go through the JavaScript implementation.
6300 __ bind(&slow); 6354 __ bind(&slow);
6301 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 6355 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
6302 } 6356 }
6303 6357
6304 6358
6305 #undef __ 6359 #undef __
6306 6360
6307 } } // namespace v8::internal 6361 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-ia32.h ('k') | src/disassembler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698