| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 | 452 |
| 453 | 453 |
| 454 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { | 454 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { |
| 455 Heap::RootListIndex value_root_index = | 455 Heap::RootListIndex value_root_index = |
| 456 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; | 456 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; |
| 457 __ PushRoot(value_root_index); | 457 __ PushRoot(value_root_index); |
| 458 } | 458 } |
| 459 | 459 |
| 460 | 460 |
| 461 void FullCodeGenerator::TestContext::Plug(bool flag) const { | 461 void FullCodeGenerator::TestContext::Plug(bool flag) const { |
| 462 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 462 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, true, NULL, NULL); |
| 463 if (flag) { | 463 if (flag) { |
| 464 if (true_label_ != fall_through_) __ jmp(true_label_); | 464 if (true_label_ != fall_through_) __ jmp(true_label_); |
| 465 } else { | 465 } else { |
| 466 if (false_label_ != fall_through_) __ jmp(false_label_); | 466 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 467 } | 467 } |
| 468 } | 468 } |
| 469 | 469 |
| 470 | 470 |
| 471 void FullCodeGenerator::DoTest(Label* if_true, | 471 void FullCodeGenerator::DoTest(Label* if_true, |
| 472 Label* if_false, | 472 Label* if_false, |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 548 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; | 548 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; |
| 549 __ RecordWrite(scratch1, offset, src, scratch2); | 549 __ RecordWrite(scratch1, offset, src, scratch2); |
| 550 } | 550 } |
| 551 } | 551 } |
| 552 | 552 |
| 553 | 553 |
| 554 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 554 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
| 555 bool should_normalize, | 555 bool should_normalize, |
| 556 Label* if_true, | 556 Label* if_true, |
| 557 Label* if_false) { | 557 Label* if_false) { |
| 558 // Only prepare for bailouts before splits if we're in a test |
| 559 // context. Otherwise, we let the Visit function deal with the |
| 560 // preparation to avoid preparing with the same AST id twice. |
| 561 if (!context()->IsTest() || !info_->IsOptimizable()) return; |
| 562 |
| 563 NearLabel skip; |
| 564 if (should_normalize) __ jmp(&skip); |
| 565 |
| 566 ForwardBailoutStack* current = forward_bailout_stack_; |
| 567 while (current != NULL) { |
| 568 PrepareForBailout(current->expr(), state); |
| 569 current = current->parent(); |
| 570 } |
| 571 |
| 572 if (should_normalize) { |
| 573 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 574 Split(equal, if_true, if_false, NULL); |
| 575 __ bind(&skip); |
| 576 } |
| 558 } | 577 } |
| 559 | 578 |
| 560 | 579 |
| 561 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 580 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
| 562 Variable::Mode mode, | 581 Variable::Mode mode, |
| 563 FunctionLiteral* function) { | 582 FunctionLiteral* function) { |
| 564 Comment cmnt(masm_, "[ Declaration"); | 583 Comment cmnt(masm_, "[ Declaration"); |
| 565 ASSERT(variable != NULL); // Must have been resolved. | 584 ASSERT(variable != NULL); // Must have been resolved. |
| 566 Slot* slot = variable->AsSlot(); | 585 Slot* slot = variable->AsSlot(); |
| 567 Property* prop = variable->AsProperty(); | 586 Property* prop = variable->AsProperty(); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 662 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); | 681 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); |
| 663 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 682 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| 664 // Return value is ignored. | 683 // Return value is ignored. |
| 665 } | 684 } |
| 666 | 685 |
| 667 | 686 |
| 668 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 687 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
| 669 Comment cmnt(masm_, "[ SwitchStatement"); | 688 Comment cmnt(masm_, "[ SwitchStatement"); |
| 670 Breakable nested_statement(this, stmt); | 689 Breakable nested_statement(this, stmt); |
| 671 SetStatementPosition(stmt); | 690 SetStatementPosition(stmt); |
| 691 |
| 672 // Keep the switch value on the stack until a case matches. | 692 // Keep the switch value on the stack until a case matches. |
| 673 VisitForStackValue(stmt->tag()); | 693 VisitForStackValue(stmt->tag()); |
| 694 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
| 674 | 695 |
| 675 ZoneList<CaseClause*>* clauses = stmt->cases(); | 696 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 676 CaseClause* default_clause = NULL; // Can occur anywhere in the list. | 697 CaseClause* default_clause = NULL; // Can occur anywhere in the list. |
| 677 | 698 |
| 678 Label next_test; // Recycled for each test. | 699 Label next_test; // Recycled for each test. |
| 679 // Compile all the tests with branches to their bodies. | 700 // Compile all the tests with branches to their bodies. |
| 680 for (int i = 0; i < clauses->length(); i++) { | 701 for (int i = 0; i < clauses->length(); i++) { |
| 681 CaseClause* clause = clauses->at(i); | 702 CaseClause* clause = clauses->at(i); |
| 682 // The default is not a test, but remember it as final fall through. | 703 // The default is not a test, but remember it as final fall through. |
| 683 if (clause->is_default()) { | 704 if (clause->is_default()) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 728 | 749 |
| 729 // Compile all the case bodies. | 750 // Compile all the case bodies. |
| 730 for (int i = 0; i < clauses->length(); i++) { | 751 for (int i = 0; i < clauses->length(); i++) { |
| 731 Comment cmnt(masm_, "[ Case body"); | 752 Comment cmnt(masm_, "[ Case body"); |
| 732 CaseClause* clause = clauses->at(i); | 753 CaseClause* clause = clauses->at(i); |
| 733 __ bind(clause->body_target()->entry_label()); | 754 __ bind(clause->body_target()->entry_label()); |
| 734 VisitStatements(clause->statements()); | 755 VisitStatements(clause->statements()); |
| 735 } | 756 } |
| 736 | 757 |
| 737 __ bind(nested_statement.break_target()); | 758 __ bind(nested_statement.break_target()); |
| 759 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 738 } | 760 } |
| 739 | 761 |
| 740 | 762 |
| 741 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 763 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 742 Comment cmnt(masm_, "[ ForInStatement"); | 764 Comment cmnt(masm_, "[ ForInStatement"); |
| 743 SetStatementPosition(stmt); | 765 SetStatementPosition(stmt); |
| 744 | 766 |
| 745 Label loop, exit; | 767 Label loop, exit; |
| 746 ForIn loop_statement(this, stmt); | 768 ForIn loop_statement(this, stmt); |
| 747 increment_loop_depth(); | 769 increment_loop_depth(); |
| (...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1217 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 1239 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 1218 // Fall through. | 1240 // Fall through. |
| 1219 case ObjectLiteral::Property::COMPUTED: | 1241 case ObjectLiteral::Property::COMPUTED: |
| 1220 if (key->handle()->IsSymbol()) { | 1242 if (key->handle()->IsSymbol()) { |
| 1221 VisitForAccumulatorValue(value); | 1243 VisitForAccumulatorValue(value); |
| 1222 __ Move(rcx, key->handle()); | 1244 __ Move(rcx, key->handle()); |
| 1223 __ movq(rdx, Operand(rsp, 0)); | 1245 __ movq(rdx, Operand(rsp, 0)); |
| 1224 if (property->emit_store()) { | 1246 if (property->emit_store()) { |
| 1225 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1247 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 1226 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1248 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1249 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1227 } | 1250 } |
| 1228 break; | 1251 break; |
| 1229 } | 1252 } |
| 1230 // Fall through. | 1253 // Fall through. |
| 1231 case ObjectLiteral::Property::PROTOTYPE: | 1254 case ObjectLiteral::Property::PROTOTYPE: |
| 1232 __ push(Operand(rsp, 0)); // Duplicate receiver. | 1255 __ push(Operand(rsp, 0)); // Duplicate receiver. |
| 1233 VisitForStackValue(key); | 1256 VisitForStackValue(key); |
| 1234 VisitForStackValue(value); | 1257 VisitForStackValue(value); |
| 1235 if (property->emit_store()) { | 1258 if (property->emit_store()) { |
| 1236 __ CallRuntime(Runtime::kSetProperty, 3); | 1259 __ CallRuntime(Runtime::kSetProperty, 3); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1304 VisitForAccumulatorValue(subexpr); | 1327 VisitForAccumulatorValue(subexpr); |
| 1305 | 1328 |
| 1306 // Store the subexpression value in the array's elements. | 1329 // Store the subexpression value in the array's elements. |
| 1307 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 1330 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. |
| 1308 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 1331 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
| 1309 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1332 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 1310 __ movq(FieldOperand(rbx, offset), result_register()); | 1333 __ movq(FieldOperand(rbx, offset), result_register()); |
| 1311 | 1334 |
| 1312 // Update the write barrier for the array store. | 1335 // Update the write barrier for the array store. |
| 1313 __ RecordWrite(rbx, offset, result_register(), rcx); | 1336 __ RecordWrite(rbx, offset, result_register(), rcx); |
| 1337 |
| 1338 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
| 1314 } | 1339 } |
| 1315 | 1340 |
| 1316 if (result_saved) { | 1341 if (result_saved) { |
| 1317 context()->PlugTOS(); | 1342 context()->PlugTOS(); |
| 1318 } else { | 1343 } else { |
| 1319 context()->Plug(rax); | 1344 context()->Plug(rax); |
| 1320 } | 1345 } |
| 1321 } | 1346 } |
| 1322 | 1347 |
| 1323 | 1348 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1376 break; | 1401 break; |
| 1377 case NAMED_PROPERTY: | 1402 case NAMED_PROPERTY: |
| 1378 EmitNamedPropertyLoad(property); | 1403 EmitNamedPropertyLoad(property); |
| 1379 break; | 1404 break; |
| 1380 case KEYED_PROPERTY: | 1405 case KEYED_PROPERTY: |
| 1381 EmitKeyedPropertyLoad(property); | 1406 EmitKeyedPropertyLoad(property); |
| 1382 break; | 1407 break; |
| 1383 } | 1408 } |
| 1384 } | 1409 } |
| 1385 | 1410 |
| 1411 // For property compound assignments we need another deoptimization |
| 1412 // point after the property load. |
| 1413 if (property != NULL) { |
| 1414 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); |
| 1415 } |
| 1416 |
| 1386 Token::Value op = expr->binary_op(); | 1417 Token::Value op = expr->binary_op(); |
| 1387 ConstantOperand constant = ShouldInlineSmiCase(op) | 1418 ConstantOperand constant = ShouldInlineSmiCase(op) |
| 1388 ? GetConstantOperand(op, expr->target(), expr->value()) | 1419 ? GetConstantOperand(op, expr->target(), expr->value()) |
| 1389 : kNoConstants; | 1420 : kNoConstants; |
| 1390 ASSERT(constant == kRightConstant || constant == kNoConstants); | 1421 ASSERT(constant == kRightConstant || constant == kNoConstants); |
| 1391 if (constant == kNoConstants) { | 1422 if (constant == kNoConstants) { |
| 1392 __ push(rax); // Left operand goes on the stack. | 1423 __ push(rax); // Left operand goes on the stack. |
| 1393 VisitForAccumulatorValue(expr->value()); | 1424 VisitForAccumulatorValue(expr->value()); |
| 1394 } | 1425 } |
| 1395 | 1426 |
| 1396 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() | 1427 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() |
| 1397 ? OVERWRITE_RIGHT | 1428 ? OVERWRITE_RIGHT |
| 1398 : NO_OVERWRITE; | 1429 : NO_OVERWRITE; |
| 1399 SetSourcePosition(expr->position() + 1); | 1430 SetSourcePosition(expr->position() + 1); |
| 1400 AccumulatorValueContext context(this); | 1431 AccumulatorValueContext context(this); |
| 1401 if (ShouldInlineSmiCase(op)) { | 1432 if (ShouldInlineSmiCase(op)) { |
| 1402 EmitInlineSmiBinaryOp(expr, | 1433 EmitInlineSmiBinaryOp(expr, |
| 1403 op, | 1434 op, |
| 1404 mode, | 1435 mode, |
| 1405 expr->target(), | 1436 expr->target(), |
| 1406 expr->value(), | 1437 expr->value(), |
| 1407 constant); | 1438 constant); |
| 1408 } else { | 1439 } else { |
| 1409 EmitBinaryOp(op, mode); | 1440 EmitBinaryOp(op, mode); |
| 1410 } | 1441 } |
| 1442 // Deoptimization point in case the binary operation may have side effects. |
| 1443 PrepareForBailout(expr->binary_operation(), TOS_REG); |
| 1411 } else { | 1444 } else { |
| 1412 VisitForAccumulatorValue(expr->value()); | 1445 VisitForAccumulatorValue(expr->value()); |
| 1413 } | 1446 } |
| 1414 | 1447 |
| 1415 // Record source position before possible IC call. | 1448 // Record source position before possible IC call. |
| 1416 SetSourcePosition(expr->position()); | 1449 SetSourcePosition(expr->position()); |
| 1417 | 1450 |
| 1418 // Store the value. | 1451 // Store the value. |
| 1419 switch (assign_type) { | 1452 switch (assign_type) { |
| 1420 case VARIABLE: | 1453 case VARIABLE: |
| 1421 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), | 1454 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), |
| 1422 expr->op()); | 1455 expr->op()); |
| 1456 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 1423 context()->Plug(rax); | 1457 context()->Plug(rax); |
| 1424 break; | 1458 break; |
| 1425 case NAMED_PROPERTY: | 1459 case NAMED_PROPERTY: |
| 1426 EmitNamedPropertyAssignment(expr); | 1460 EmitNamedPropertyAssignment(expr); |
| 1427 break; | 1461 break; |
| 1428 case KEYED_PROPERTY: | 1462 case KEYED_PROPERTY: |
| 1429 EmitKeyedPropertyAssignment(expr); | 1463 EmitKeyedPropertyAssignment(expr); |
| 1430 break; | 1464 break; |
| 1431 } | 1465 } |
| 1432 } | 1466 } |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1522 __ pop(rdx); | 1556 __ pop(rdx); |
| 1523 stub.GenerateCall(masm_, rdx, rax); | 1557 stub.GenerateCall(masm_, rdx, rax); |
| 1524 } else { | 1558 } else { |
| 1525 __ push(result_register()); | 1559 __ push(result_register()); |
| 1526 __ CallStub(&stub); | 1560 __ CallStub(&stub); |
| 1527 } | 1561 } |
| 1528 context()->Plug(rax); | 1562 context()->Plug(rax); |
| 1529 } | 1563 } |
| 1530 | 1564 |
| 1531 | 1565 |
| 1532 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_id) { | 1566 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
| 1533 // Invalid left-hand sides are rewritten to have a 'throw | 1567 // Invalid left-hand sides are rewritten to have a 'throw |
| 1534 // ReferenceError' on the left-hand side. | 1568 // ReferenceError' on the left-hand side. |
| 1535 if (!expr->IsValidLeftHandSide()) { | 1569 if (!expr->IsValidLeftHandSide()) { |
| 1536 VisitForEffect(expr); | 1570 VisitForEffect(expr); |
| 1537 return; | 1571 return; |
| 1538 } | 1572 } |
| 1539 | 1573 |
| 1540 // Left-hand side can only be a property, a global or a (parameter or local) | 1574 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1541 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1575 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
| 1542 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1576 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1570 VisitForStackValue(prop->obj()); | 1604 VisitForStackValue(prop->obj()); |
| 1571 VisitForAccumulatorValue(prop->key()); | 1605 VisitForAccumulatorValue(prop->key()); |
| 1572 __ movq(rcx, rax); | 1606 __ movq(rcx, rax); |
| 1573 __ pop(rdx); | 1607 __ pop(rdx); |
| 1574 __ pop(rax); | 1608 __ pop(rax); |
| 1575 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1609 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 1576 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1610 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1577 break; | 1611 break; |
| 1578 } | 1612 } |
| 1579 } | 1613 } |
| 1614 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 1580 context()->Plug(rax); | 1615 context()->Plug(rax); |
| 1581 } | 1616 } |
| 1582 | 1617 |
| 1583 | 1618 |
| 1584 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1619 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1585 Token::Value op) { | 1620 Token::Value op) { |
| 1586 // Left-hand sides that rewrite to explicit property accesses do not reach | 1621 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 1587 // here. | 1622 // here. |
| 1588 ASSERT(var != NULL); | 1623 ASSERT(var != NULL); |
| 1589 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1624 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1681 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1716 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1682 | 1717 |
| 1683 // If the assignment ends an initialization block, revert to fast case. | 1718 // If the assignment ends an initialization block, revert to fast case. |
| 1684 if (expr->ends_initialization_block()) { | 1719 if (expr->ends_initialization_block()) { |
| 1685 __ push(rax); // Result of assignment, saved even if not needed. | 1720 __ push(rax); // Result of assignment, saved even if not needed. |
| 1686 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1721 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. |
| 1687 __ CallRuntime(Runtime::kToFastProperties, 1); | 1722 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1688 __ pop(rax); | 1723 __ pop(rax); |
| 1689 __ Drop(1); | 1724 __ Drop(1); |
| 1690 } | 1725 } |
| 1726 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 1691 context()->Plug(rax); | 1727 context()->Plug(rax); |
| 1692 } | 1728 } |
| 1693 | 1729 |
| 1694 | 1730 |
| 1695 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 1731 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
| 1696 // Assignment to a property, using a keyed store IC. | 1732 // Assignment to a property, using a keyed store IC. |
| 1697 | 1733 |
| 1698 // If the assignment starts a block of assignments to the same object, | 1734 // If the assignment starts a block of assignments to the same object, |
| 1699 // change to slow case to avoid the quadratic behavior of repeatedly | 1735 // change to slow case to avoid the quadratic behavior of repeatedly |
| 1700 // adding fast properties. | 1736 // adding fast properties. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1719 | 1755 |
| 1720 // If the assignment ends an initialization block, revert to fast case. | 1756 // If the assignment ends an initialization block, revert to fast case. |
| 1721 if (expr->ends_initialization_block()) { | 1757 if (expr->ends_initialization_block()) { |
| 1722 __ pop(rdx); | 1758 __ pop(rdx); |
| 1723 __ push(rax); // Result of assignment, saved even if not needed. | 1759 __ push(rax); // Result of assignment, saved even if not needed. |
| 1724 __ push(rdx); | 1760 __ push(rdx); |
| 1725 __ CallRuntime(Runtime::kToFastProperties, 1); | 1761 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1726 __ pop(rax); | 1762 __ pop(rax); |
| 1727 } | 1763 } |
| 1728 | 1764 |
| 1765 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 1729 context()->Plug(rax); | 1766 context()->Plug(rax); |
| 1730 } | 1767 } |
| 1731 | 1768 |
| 1732 | 1769 |
| 1733 void FullCodeGenerator::VisitProperty(Property* expr) { | 1770 void FullCodeGenerator::VisitProperty(Property* expr) { |
| 1734 Comment cmnt(masm_, "[ Property"); | 1771 Comment cmnt(masm_, "[ Property"); |
| 1735 Expression* key = expr->key(); | 1772 Expression* key = expr->key(); |
| 1736 | 1773 |
| 1737 if (key->IsPropertyName()) { | 1774 if (key->IsPropertyName()) { |
| 1738 VisitForAccumulatorValue(expr->obj()); | 1775 VisitForAccumulatorValue(expr->obj()); |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2016 | 2053 |
| 2017 VisitForAccumulatorValue(args->at(0)); | 2054 VisitForAccumulatorValue(args->at(0)); |
| 2018 | 2055 |
| 2019 Label materialize_true, materialize_false; | 2056 Label materialize_true, materialize_false; |
| 2020 Label* if_true = NULL; | 2057 Label* if_true = NULL; |
| 2021 Label* if_false = NULL; | 2058 Label* if_false = NULL; |
| 2022 Label* fall_through = NULL; | 2059 Label* fall_through = NULL; |
| 2023 context()->PrepareTest(&materialize_true, &materialize_false, | 2060 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2024 &if_true, &if_false, &fall_through); | 2061 &if_true, &if_false, &fall_through); |
| 2025 | 2062 |
| 2063 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2026 __ JumpIfSmi(rax, if_true); | 2064 __ JumpIfSmi(rax, if_true); |
| 2027 __ jmp(if_false); | 2065 __ jmp(if_false); |
| 2028 | 2066 |
| 2029 context()->Plug(if_true, if_false); | 2067 context()->Plug(if_true, if_false); |
| 2030 } | 2068 } |
| 2031 | 2069 |
| 2032 | 2070 |
| 2033 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { | 2071 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 2034 ASSERT(args->length() == 1); | 2072 ASSERT(args->length() == 1); |
| 2035 | 2073 |
| 2036 VisitForAccumulatorValue(args->at(0)); | 2074 VisitForAccumulatorValue(args->at(0)); |
| 2037 | 2075 |
| 2038 Label materialize_true, materialize_false; | 2076 Label materialize_true, materialize_false; |
| 2039 Label* if_true = NULL; | 2077 Label* if_true = NULL; |
| 2040 Label* if_false = NULL; | 2078 Label* if_false = NULL; |
| 2041 Label* fall_through = NULL; | 2079 Label* fall_through = NULL; |
| 2042 context()->PrepareTest(&materialize_true, &materialize_false, | 2080 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2043 &if_true, &if_false, &fall_through); | 2081 &if_true, &if_false, &fall_through); |
| 2044 | 2082 |
| 2083 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2045 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax); | 2084 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax); |
| 2046 Split(non_negative_smi, if_true, if_false, fall_through); | 2085 Split(non_negative_smi, if_true, if_false, fall_through); |
| 2047 | 2086 |
| 2048 context()->Plug(if_true, if_false); | 2087 context()->Plug(if_true, if_false); |
| 2049 } | 2088 } |
| 2050 | 2089 |
| 2051 | 2090 |
| 2052 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { | 2091 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { |
| 2053 ASSERT(args->length() == 1); | 2092 ASSERT(args->length() == 1); |
| 2054 | 2093 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2066 __ j(equal, if_true); | 2105 __ j(equal, if_true); |
| 2067 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 2106 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 2068 // Undetectable objects behave like undefined when tested with typeof. | 2107 // Undetectable objects behave like undefined when tested with typeof. |
| 2069 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2108 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 2070 Immediate(1 << Map::kIsUndetectable)); | 2109 Immediate(1 << Map::kIsUndetectable)); |
| 2071 __ j(not_zero, if_false); | 2110 __ j(not_zero, if_false); |
| 2072 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 2111 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 2073 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE)); | 2112 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE)); |
| 2074 __ j(below, if_false); | 2113 __ j(below, if_false); |
| 2075 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE)); | 2114 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE)); |
| 2115 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2076 Split(below_equal, if_true, if_false, fall_through); | 2116 Split(below_equal, if_true, if_false, fall_through); |
| 2077 | 2117 |
| 2078 context()->Plug(if_true, if_false); | 2118 context()->Plug(if_true, if_false); |
| 2079 } | 2119 } |
| 2080 | 2120 |
| 2081 | 2121 |
| 2082 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { | 2122 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { |
| 2083 ASSERT(args->length() == 1); | 2123 ASSERT(args->length() == 1); |
| 2084 | 2124 |
| 2085 VisitForAccumulatorValue(args->at(0)); | 2125 VisitForAccumulatorValue(args->at(0)); |
| 2086 | 2126 |
| 2087 Label materialize_true, materialize_false; | 2127 Label materialize_true, materialize_false; |
| 2088 Label* if_true = NULL; | 2128 Label* if_true = NULL; |
| 2089 Label* if_false = NULL; | 2129 Label* if_false = NULL; |
| 2090 Label* fall_through = NULL; | 2130 Label* fall_through = NULL; |
| 2091 context()->PrepareTest(&materialize_true, &materialize_false, | 2131 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2092 &if_true, &if_false, &fall_through); | 2132 &if_true, &if_false, &fall_through); |
| 2093 | 2133 |
| 2094 __ JumpIfSmi(rax, if_false); | 2134 __ JumpIfSmi(rax, if_false); |
| 2095 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | 2135 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); |
| 2136 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2096 Split(above_equal, if_true, if_false, fall_through); | 2137 Split(above_equal, if_true, if_false, fall_through); |
| 2097 | 2138 |
| 2098 context()->Plug(if_true, if_false); | 2139 context()->Plug(if_true, if_false); |
| 2099 } | 2140 } |
| 2100 | 2141 |
| 2101 | 2142 |
| 2102 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { | 2143 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { |
| 2103 ASSERT(args->length() == 1); | 2144 ASSERT(args->length() == 1); |
| 2104 | 2145 |
| 2105 VisitForAccumulatorValue(args->at(0)); | 2146 VisitForAccumulatorValue(args->at(0)); |
| 2106 | 2147 |
| 2107 Label materialize_true, materialize_false; | 2148 Label materialize_true, materialize_false; |
| 2108 Label* if_true = NULL; | 2149 Label* if_true = NULL; |
| 2109 Label* if_false = NULL; | 2150 Label* if_false = NULL; |
| 2110 Label* fall_through = NULL; | 2151 Label* fall_through = NULL; |
| 2111 context()->PrepareTest(&materialize_true, &materialize_false, | 2152 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2112 &if_true, &if_false, &fall_through); | 2153 &if_true, &if_false, &fall_through); |
| 2113 | 2154 |
| 2114 __ JumpIfSmi(rax, if_false); | 2155 __ JumpIfSmi(rax, if_false); |
| 2115 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 2156 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 2116 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2157 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 2117 Immediate(1 << Map::kIsUndetectable)); | 2158 Immediate(1 << Map::kIsUndetectable)); |
| 2159 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2118 Split(not_zero, if_true, if_false, fall_through); | 2160 Split(not_zero, if_true, if_false, fall_through); |
| 2119 | 2161 |
| 2120 context()->Plug(if_true, if_false); | 2162 context()->Plug(if_true, if_false); |
| 2121 } | 2163 } |
| 2122 | 2164 |
| 2123 | 2165 |
| 2124 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( | 2166 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( |
| 2125 ZoneList<Expression*>* args) { | 2167 ZoneList<Expression*>* args) { |
| 2126 ASSERT(args->length() == 1); | 2168 ASSERT(args->length() == 1); |
| 2127 | 2169 |
| 2128 VisitForAccumulatorValue(args->at(0)); | 2170 VisitForAccumulatorValue(args->at(0)); |
| 2129 | 2171 |
| 2130 Label materialize_true, materialize_false; | 2172 Label materialize_true, materialize_false; |
| 2131 Label* if_true = NULL; | 2173 Label* if_true = NULL; |
| 2132 Label* if_false = NULL; | 2174 Label* if_false = NULL; |
| 2133 Label* fall_through = NULL; | 2175 Label* fall_through = NULL; |
| 2134 context()->PrepareTest(&materialize_true, &materialize_false, | 2176 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2135 &if_true, &if_false, &fall_through); | 2177 &if_true, &if_false, &fall_through); |
| 2136 | 2178 |
| 2137 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only | 2179 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only |
| 2138 // used in a few functions in runtime.js which should not normally be hit by | 2180 // used in a few functions in runtime.js which should not normally be hit by |
| 2139 // this compiler. | 2181 // this compiler. |
| 2182 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2140 __ jmp(if_false); | 2183 __ jmp(if_false); |
| 2141 context()->Plug(if_true, if_false); | 2184 context()->Plug(if_true, if_false); |
| 2142 } | 2185 } |
| 2143 | 2186 |
| 2144 | 2187 |
| 2145 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { | 2188 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { |
| 2146 ASSERT(args->length() == 1); | 2189 ASSERT(args->length() == 1); |
| 2147 | 2190 |
| 2148 VisitForAccumulatorValue(args->at(0)); | 2191 VisitForAccumulatorValue(args->at(0)); |
| 2149 | 2192 |
| 2150 Label materialize_true, materialize_false; | 2193 Label materialize_true, materialize_false; |
| 2151 Label* if_true = NULL; | 2194 Label* if_true = NULL; |
| 2152 Label* if_false = NULL; | 2195 Label* if_false = NULL; |
| 2153 Label* fall_through = NULL; | 2196 Label* fall_through = NULL; |
| 2154 context()->PrepareTest(&materialize_true, &materialize_false, | 2197 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2155 &if_true, &if_false, &fall_through); | 2198 &if_true, &if_false, &fall_through); |
| 2156 | 2199 |
| 2157 __ JumpIfSmi(rax, if_false); | 2200 __ JumpIfSmi(rax, if_false); |
| 2158 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); | 2201 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); |
| 2202 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2159 Split(equal, if_true, if_false, fall_through); | 2203 Split(equal, if_true, if_false, fall_through); |
| 2160 | 2204 |
| 2161 context()->Plug(if_true, if_false); | 2205 context()->Plug(if_true, if_false); |
| 2162 } | 2206 } |
| 2163 | 2207 |
| 2164 | 2208 |
| 2165 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { | 2209 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { |
| 2166 ASSERT(args->length() == 1); | 2210 ASSERT(args->length() == 1); |
| 2167 | 2211 |
| 2168 VisitForAccumulatorValue(args->at(0)); | 2212 VisitForAccumulatorValue(args->at(0)); |
| 2169 | 2213 |
| 2170 Label materialize_true, materialize_false; | 2214 Label materialize_true, materialize_false; |
| 2171 Label* if_true = NULL; | 2215 Label* if_true = NULL; |
| 2172 Label* if_false = NULL; | 2216 Label* if_false = NULL; |
| 2173 Label* fall_through = NULL; | 2217 Label* fall_through = NULL; |
| 2174 context()->PrepareTest(&materialize_true, &materialize_false, | 2218 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2175 &if_true, &if_false, &fall_through); | 2219 &if_true, &if_false, &fall_through); |
| 2176 | 2220 |
| 2177 __ JumpIfSmi(rax, if_false); | 2221 __ JumpIfSmi(rax, if_false); |
| 2178 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx); | 2222 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx); |
| 2223 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2179 Split(equal, if_true, if_false, fall_through); | 2224 Split(equal, if_true, if_false, fall_through); |
| 2180 | 2225 |
| 2181 context()->Plug(if_true, if_false); | 2226 context()->Plug(if_true, if_false); |
| 2182 } | 2227 } |
| 2183 | 2228 |
| 2184 | 2229 |
| 2185 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { | 2230 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { |
| 2186 ASSERT(args->length() == 1); | 2231 ASSERT(args->length() == 1); |
| 2187 | 2232 |
| 2188 VisitForAccumulatorValue(args->at(0)); | 2233 VisitForAccumulatorValue(args->at(0)); |
| 2189 | 2234 |
| 2190 Label materialize_true, materialize_false; | 2235 Label materialize_true, materialize_false; |
| 2191 Label* if_true = NULL; | 2236 Label* if_true = NULL; |
| 2192 Label* if_false = NULL; | 2237 Label* if_false = NULL; |
| 2193 Label* fall_through = NULL; | 2238 Label* fall_through = NULL; |
| 2194 context()->PrepareTest(&materialize_true, &materialize_false, | 2239 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2195 &if_true, &if_false, &fall_through); | 2240 &if_true, &if_false, &fall_through); |
| 2196 | 2241 |
| 2197 __ JumpIfSmi(rax, if_false); | 2242 __ JumpIfSmi(rax, if_false); |
| 2198 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx); | 2243 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx); |
| 2244 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2199 Split(equal, if_true, if_false, fall_through); | 2245 Split(equal, if_true, if_false, fall_through); |
| 2200 | 2246 |
| 2201 context()->Plug(if_true, if_false); | 2247 context()->Plug(if_true, if_false); |
| 2202 } | 2248 } |
| 2203 | 2249 |
| 2204 | 2250 |
| 2205 | 2251 |
| 2206 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { | 2252 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { |
| 2207 ASSERT(args->length() == 0); | 2253 ASSERT(args->length() == 0); |
| 2208 | 2254 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2220 Label check_frame_marker; | 2266 Label check_frame_marker; |
| 2221 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), | 2267 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), |
| 2222 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2268 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2223 __ j(not_equal, &check_frame_marker); | 2269 __ j(not_equal, &check_frame_marker); |
| 2224 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); | 2270 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); |
| 2225 | 2271 |
| 2226 // Check the marker in the calling frame. | 2272 // Check the marker in the calling frame. |
| 2227 __ bind(&check_frame_marker); | 2273 __ bind(&check_frame_marker); |
| 2228 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), | 2274 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), |
| 2229 Smi::FromInt(StackFrame::CONSTRUCT)); | 2275 Smi::FromInt(StackFrame::CONSTRUCT)); |
| 2276 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2230 Split(equal, if_true, if_false, fall_through); | 2277 Split(equal, if_true, if_false, fall_through); |
| 2231 | 2278 |
| 2232 context()->Plug(if_true, if_false); | 2279 context()->Plug(if_true, if_false); |
| 2233 } | 2280 } |
| 2234 | 2281 |
| 2235 | 2282 |
| 2236 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { | 2283 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { |
| 2237 ASSERT(args->length() == 2); | 2284 ASSERT(args->length() == 2); |
| 2238 | 2285 |
| 2239 // Load the two objects into registers and perform the comparison. | 2286 // Load the two objects into registers and perform the comparison. |
| 2240 VisitForStackValue(args->at(0)); | 2287 VisitForStackValue(args->at(0)); |
| 2241 VisitForAccumulatorValue(args->at(1)); | 2288 VisitForAccumulatorValue(args->at(1)); |
| 2242 | 2289 |
| 2243 Label materialize_true, materialize_false; | 2290 Label materialize_true, materialize_false; |
| 2244 Label* if_true = NULL; | 2291 Label* if_true = NULL; |
| 2245 Label* if_false = NULL; | 2292 Label* if_false = NULL; |
| 2246 Label* fall_through = NULL; | 2293 Label* fall_through = NULL; |
| 2247 context()->PrepareTest(&materialize_true, &materialize_false, | 2294 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2248 &if_true, &if_false, &fall_through); | 2295 &if_true, &if_false, &fall_through); |
| 2249 | 2296 |
| 2250 __ pop(rbx); | 2297 __ pop(rbx); |
| 2251 __ cmpq(rax, rbx); | 2298 __ cmpq(rax, rbx); |
| 2299 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2252 Split(equal, if_true, if_false, fall_through); | 2300 Split(equal, if_true, if_false, fall_through); |
| 2253 | 2301 |
| 2254 context()->Plug(if_true, if_false); | 2302 context()->Plug(if_true, if_false); |
| 2255 } | 2303 } |
| 2256 | 2304 |
| 2257 | 2305 |
| 2258 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2306 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
| 2259 ASSERT(args->length() == 1); | 2307 ASSERT(args->length() == 1); |
| 2260 | 2308 |
| 2261 // ArgumentsAccessStub expects the key in rdx and the formal | 2309 // ArgumentsAccessStub expects the key in rdx and the formal |
| (...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2815 | 2863 |
| 2816 Label materialize_true, materialize_false; | 2864 Label materialize_true, materialize_false; |
| 2817 Label* if_true = NULL; | 2865 Label* if_true = NULL; |
| 2818 Label* if_false = NULL; | 2866 Label* if_false = NULL; |
| 2819 Label* fall_through = NULL; | 2867 Label* fall_through = NULL; |
| 2820 context()->PrepareTest(&materialize_true, &materialize_false, | 2868 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2821 &if_true, &if_false, &fall_through); | 2869 &if_true, &if_false, &fall_through); |
| 2822 | 2870 |
| 2823 __ testl(FieldOperand(rax, String::kHashFieldOffset), | 2871 __ testl(FieldOperand(rax, String::kHashFieldOffset), |
| 2824 Immediate(String::kContainsCachedArrayIndexMask)); | 2872 Immediate(String::kContainsCachedArrayIndexMask)); |
| 2873 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2825 __ j(zero, if_true); | 2874 __ j(zero, if_true); |
| 2826 __ jmp(if_false); | 2875 __ jmp(if_false); |
| 2827 | 2876 |
| 2828 context()->Plug(if_true, if_false); | 2877 context()->Plug(if_true, if_false); |
| 2829 } | 2878 } |
| 2830 | 2879 |
| 2831 | 2880 |
| 2832 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { | 2881 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { |
| 2833 ASSERT(args->length() == 1); | 2882 ASSERT(args->length() == 1); |
| 2834 | 2883 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2936 | 2985 |
| 2937 case Token::NOT: { | 2986 case Token::NOT: { |
| 2938 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 2987 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
| 2939 Label materialize_true, materialize_false; | 2988 Label materialize_true, materialize_false; |
| 2940 Label* if_true = NULL; | 2989 Label* if_true = NULL; |
| 2941 Label* if_false = NULL; | 2990 Label* if_false = NULL; |
| 2942 Label* fall_through = NULL; | 2991 Label* fall_through = NULL; |
| 2943 // Notice that the labels are swapped. | 2992 // Notice that the labels are swapped. |
| 2944 context()->PrepareTest(&materialize_true, &materialize_false, | 2993 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2945 &if_false, &if_true, &fall_through); | 2994 &if_false, &if_true, &fall_through); |
| 2995 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 2946 VisitForControl(expr->expression(), if_true, if_false, fall_through); | 2996 VisitForControl(expr->expression(), if_true, if_false, fall_through); |
| 2947 context()->Plug(if_false, if_true); // Labels swapped. | 2997 context()->Plug(if_false, if_true); // Labels swapped. |
| 2948 break; | 2998 break; |
| 2949 } | 2999 } |
| 2950 | 3000 |
| 2951 case Token::TYPEOF: { | 3001 case Token::TYPEOF: { |
| 2952 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 3002 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
| 2953 { StackValueContext context(this); | 3003 { StackValueContext context(this); |
| 2954 VisitForTypeofValue(expr->expression()); | 3004 VisitForTypeofValue(expr->expression()); |
| 2955 } | 3005 } |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3057 EmitNamedPropertyLoad(prop); | 3107 EmitNamedPropertyLoad(prop); |
| 3058 } else { | 3108 } else { |
| 3059 VisitForStackValue(prop->obj()); | 3109 VisitForStackValue(prop->obj()); |
| 3060 VisitForAccumulatorValue(prop->key()); | 3110 VisitForAccumulatorValue(prop->key()); |
| 3061 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack | 3111 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack |
| 3062 __ push(rax); // Copy of key, needed for later store. | 3112 __ push(rax); // Copy of key, needed for later store. |
| 3063 EmitKeyedPropertyLoad(prop); | 3113 EmitKeyedPropertyLoad(prop); |
| 3064 } | 3114 } |
| 3065 } | 3115 } |
| 3066 | 3116 |
| 3117 // We need a second deoptimization point after loading the value |
| 3118 // in case evaluating the property load my have a side effect. |
| 3119 PrepareForBailout(expr->increment(), TOS_REG); |
| 3120 |
| 3067 // Call ToNumber only if operand is not a smi. | 3121 // Call ToNumber only if operand is not a smi. |
| 3068 NearLabel no_conversion; | 3122 NearLabel no_conversion; |
| 3069 Condition is_smi; | 3123 Condition is_smi; |
| 3070 is_smi = masm_->CheckSmi(rax); | 3124 is_smi = masm_->CheckSmi(rax); |
| 3071 __ j(is_smi, &no_conversion); | 3125 __ j(is_smi, &no_conversion); |
| 3072 __ push(rax); | 3126 __ push(rax); |
| 3073 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 3127 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
| 3074 __ bind(&no_conversion); | 3128 __ bind(&no_conversion); |
| 3075 | 3129 |
| 3076 // Save result for postfix expressions. | 3130 // Save result for postfix expressions. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3126 __ bind(&done); | 3180 __ bind(&done); |
| 3127 | 3181 |
| 3128 // Store the value returned in rax. | 3182 // Store the value returned in rax. |
| 3129 switch (assign_type) { | 3183 switch (assign_type) { |
| 3130 case VARIABLE: | 3184 case VARIABLE: |
| 3131 if (expr->is_postfix()) { | 3185 if (expr->is_postfix()) { |
| 3132 // Perform the assignment as if via '='. | 3186 // Perform the assignment as if via '='. |
| 3133 { EffectContext context(this); | 3187 { EffectContext context(this); |
| 3134 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3188 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3135 Token::ASSIGN); | 3189 Token::ASSIGN); |
| 3190 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3136 context.Plug(rax); | 3191 context.Plug(rax); |
| 3137 } | 3192 } |
| 3138 // For all contexts except kEffect: We have the result on | 3193 // For all contexts except kEffect: We have the result on |
| 3139 // top of the stack. | 3194 // top of the stack. |
| 3140 if (!context()->IsEffect()) { | 3195 if (!context()->IsEffect()) { |
| 3141 context()->PlugTOS(); | 3196 context()->PlugTOS(); |
| 3142 } | 3197 } |
| 3143 } else { | 3198 } else { |
| 3144 // Perform the assignment as if via '='. | 3199 // Perform the assignment as if via '='. |
| 3145 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3200 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3146 Token::ASSIGN); | 3201 Token::ASSIGN); |
| 3202 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3147 context()->Plug(rax); | 3203 context()->Plug(rax); |
| 3148 } | 3204 } |
| 3149 break; | 3205 break; |
| 3150 case NAMED_PROPERTY: { | 3206 case NAMED_PROPERTY: { |
| 3151 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 3207 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 3152 __ pop(rdx); | 3208 __ pop(rdx); |
| 3153 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 3209 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 3154 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3210 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3211 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3155 if (expr->is_postfix()) { | 3212 if (expr->is_postfix()) { |
| 3156 if (!context()->IsEffect()) { | 3213 if (!context()->IsEffect()) { |
| 3157 context()->PlugTOS(); | 3214 context()->PlugTOS(); |
| 3158 } | 3215 } |
| 3159 } else { | 3216 } else { |
| 3160 context()->Plug(rax); | 3217 context()->Plug(rax); |
| 3161 } | 3218 } |
| 3162 break; | 3219 break; |
| 3163 } | 3220 } |
| 3164 case KEYED_PROPERTY: { | 3221 case KEYED_PROPERTY: { |
| 3165 __ pop(rcx); | 3222 __ pop(rcx); |
| 3166 __ pop(rdx); | 3223 __ pop(rdx); |
| 3167 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 3224 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 3168 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3225 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3226 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3169 if (expr->is_postfix()) { | 3227 if (expr->is_postfix()) { |
| 3170 if (!context()->IsEffect()) { | 3228 if (!context()->IsEffect()) { |
| 3171 context()->PlugTOS(); | 3229 context()->PlugTOS(); |
| 3172 } | 3230 } |
| 3173 } else { | 3231 } else { |
| 3174 context()->Plug(rax); | 3232 context()->Plug(rax); |
| 3175 } | 3233 } |
| 3176 break; | 3234 break; |
| 3177 } | 3235 } |
| 3178 } | 3236 } |
| 3179 } | 3237 } |
| 3180 | 3238 |
| 3181 | 3239 |
| 3182 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 3240 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 3183 VariableProxy* proxy = expr->AsVariableProxy(); | 3241 VariableProxy* proxy = expr->AsVariableProxy(); |
| 3184 ASSERT(!context()->IsEffect()); | 3242 ASSERT(!context()->IsEffect()); |
| 3185 ASSERT(!context()->IsTest()); | 3243 ASSERT(!context()->IsTest()); |
| 3186 | 3244 |
| 3187 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3245 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
| 3188 Comment cmnt(masm_, "Global variable"); | 3246 Comment cmnt(masm_, "Global variable"); |
| 3189 __ Move(rcx, proxy->name()); | 3247 __ Move(rcx, proxy->name()); |
| 3190 __ movq(rax, GlobalObjectOperand()); | 3248 __ movq(rax, GlobalObjectOperand()); |
| 3191 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3249 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 3192 // Use a regular load, not a contextual load, to avoid a reference | 3250 // Use a regular load, not a contextual load, to avoid a reference |
| 3193 // error. | 3251 // error. |
| 3194 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3252 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3253 PrepareForBailout(expr, TOS_REG); |
| 3195 context()->Plug(rax); | 3254 context()->Plug(rax); |
| 3196 } else if (proxy != NULL && | 3255 } else if (proxy != NULL && |
| 3197 proxy->var()->AsSlot() != NULL && | 3256 proxy->var()->AsSlot() != NULL && |
| 3198 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { | 3257 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { |
| 3199 Label done, slow; | 3258 Label done, slow; |
| 3200 | 3259 |
| 3201 // Generate code for loading from variables potentially shadowed | 3260 // Generate code for loading from variables potentially shadowed |
| 3202 // by eval-introduced variables. | 3261 // by eval-introduced variables. |
| 3203 Slot* slot = proxy->var()->AsSlot(); | 3262 Slot* slot = proxy->var()->AsSlot(); |
| 3204 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); | 3263 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); |
| 3205 | 3264 |
| 3206 __ bind(&slow); | 3265 __ bind(&slow); |
| 3207 __ push(rsi); | 3266 __ push(rsi); |
| 3208 __ Push(proxy->name()); | 3267 __ Push(proxy->name()); |
| 3209 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3268 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 3269 PrepareForBailout(expr, TOS_REG); |
| 3210 __ bind(&done); | 3270 __ bind(&done); |
| 3211 | 3271 |
| 3212 context()->Plug(rax); | 3272 context()->Plug(rax); |
| 3213 } else { | 3273 } else { |
| 3214 // This expression cannot throw a reference error at the top level. | 3274 // This expression cannot throw a reference error at the top level. |
| 3215 Visit(expr); | 3275 Visit(expr); |
| 3216 } | 3276 } |
| 3217 } | 3277 } |
| 3218 | 3278 |
| 3219 | 3279 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3230 if (right_literal == NULL) return false; | 3290 if (right_literal == NULL) return false; |
| 3231 Handle<Object> right_literal_value = right_literal->handle(); | 3291 Handle<Object> right_literal_value = right_literal->handle(); |
| 3232 if (!right_literal_value->IsString()) return false; | 3292 if (!right_literal_value->IsString()) return false; |
| 3233 UnaryOperation* left_unary = left->AsUnaryOperation(); | 3293 UnaryOperation* left_unary = left->AsUnaryOperation(); |
| 3234 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | 3294 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; |
| 3235 Handle<String> check = Handle<String>::cast(right_literal_value); | 3295 Handle<String> check = Handle<String>::cast(right_literal_value); |
| 3236 | 3296 |
| 3237 { AccumulatorValueContext context(this); | 3297 { AccumulatorValueContext context(this); |
| 3238 VisitForTypeofValue(left_unary->expression()); | 3298 VisitForTypeofValue(left_unary->expression()); |
| 3239 } | 3299 } |
| 3300 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3240 | 3301 |
| 3241 if (check->Equals(Heap::number_symbol())) { | 3302 if (check->Equals(Heap::number_symbol())) { |
| 3242 Condition is_smi = masm_->CheckSmi(rax); | 3303 Condition is_smi = masm_->CheckSmi(rax); |
| 3243 __ j(is_smi, if_true); | 3304 __ j(is_smi, if_true); |
| 3244 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); | 3305 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
| 3245 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); | 3306 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); |
| 3246 Split(equal, if_true, if_false, fall_through); | 3307 Split(equal, if_true, if_false, fall_through); |
| 3247 } else if (check->Equals(Heap::string_symbol())) { | 3308 } else if (check->Equals(Heap::string_symbol())) { |
| 3248 Condition is_smi = masm_->CheckSmi(rax); | 3309 Condition is_smi = masm_->CheckSmi(rax); |
| 3249 __ j(is_smi, if_false); | 3310 __ j(is_smi, if_false); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3323 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { | 3384 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { |
| 3324 context()->Plug(if_true, if_false); | 3385 context()->Plug(if_true, if_false); |
| 3325 return; | 3386 return; |
| 3326 } | 3387 } |
| 3327 | 3388 |
| 3328 VisitForStackValue(expr->left()); | 3389 VisitForStackValue(expr->left()); |
| 3329 switch (op) { | 3390 switch (op) { |
| 3330 case Token::IN: | 3391 case Token::IN: |
| 3331 VisitForStackValue(expr->right()); | 3392 VisitForStackValue(expr->right()); |
| 3332 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 3393 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 3394 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 3333 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 3395 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 3334 Split(equal, if_true, if_false, fall_through); | 3396 Split(equal, if_true, if_false, fall_through); |
| 3335 break; | 3397 break; |
| 3336 | 3398 |
| 3337 case Token::INSTANCEOF: { | 3399 case Token::INSTANCEOF: { |
| 3338 VisitForStackValue(expr->right()); | 3400 VisitForStackValue(expr->right()); |
| 3339 InstanceofStub stub(InstanceofStub::kNoFlags); | 3401 InstanceofStub stub(InstanceofStub::kNoFlags); |
| 3340 __ CallStub(&stub); | 3402 __ CallStub(&stub); |
| 3403 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3341 __ testq(rax, rax); | 3404 __ testq(rax, rax); |
| 3342 // The stub returns 0 for true. | 3405 // The stub returns 0 for true. |
| 3343 Split(zero, if_true, if_false, fall_through); | 3406 Split(zero, if_true, if_false, fall_through); |
| 3344 break; | 3407 break; |
| 3345 } | 3408 } |
| 3346 | 3409 |
| 3347 default: { | 3410 default: { |
| 3348 VisitForAccumulatorValue(expr->right()); | 3411 VisitForAccumulatorValue(expr->right()); |
| 3349 Condition cc = no_condition; | 3412 Condition cc = no_condition; |
| 3350 bool strict = false; | 3413 bool strict = false; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3389 __ SmiCompare(rdx, rax); | 3452 __ SmiCompare(rdx, rax); |
| 3390 Split(cc, if_true, if_false, NULL); | 3453 Split(cc, if_true, if_false, NULL); |
| 3391 __ bind(&slow_case); | 3454 __ bind(&slow_case); |
| 3392 } | 3455 } |
| 3393 | 3456 |
| 3394 CompareFlags flags = inline_smi_code | 3457 CompareFlags flags = inline_smi_code |
| 3395 ? NO_SMI_COMPARE_IN_STUB | 3458 ? NO_SMI_COMPARE_IN_STUB |
| 3396 : NO_COMPARE_FLAGS; | 3459 : NO_COMPARE_FLAGS; |
| 3397 CompareStub stub(cc, strict, flags); | 3460 CompareStub stub(cc, strict, flags); |
| 3398 __ CallStub(&stub); | 3461 __ CallStub(&stub); |
| 3462 |
| 3463 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3399 __ testq(rax, rax); | 3464 __ testq(rax, rax); |
| 3400 Split(cc, if_true, if_false, fall_through); | 3465 Split(cc, if_true, if_false, fall_through); |
| 3401 } | 3466 } |
| 3402 } | 3467 } |
| 3403 | 3468 |
| 3404 // Convert the result of the comparison into one expected for this | 3469 // Convert the result of the comparison into one expected for this |
| 3405 // expression's context. | 3470 // expression's context. |
| 3406 context()->Plug(if_true, if_false); | 3471 context()->Plug(if_true, if_false); |
| 3407 } | 3472 } |
| 3408 | 3473 |
| 3409 | 3474 |
| 3410 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { | 3475 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { |
| 3411 Comment cmnt(masm_, "[ CompareToNull"); | 3476 Comment cmnt(masm_, "[ CompareToNull"); |
| 3412 Label materialize_true, materialize_false; | 3477 Label materialize_true, materialize_false; |
| 3413 Label* if_true = NULL; | 3478 Label* if_true = NULL; |
| 3414 Label* if_false = NULL; | 3479 Label* if_false = NULL; |
| 3415 Label* fall_through = NULL; | 3480 Label* fall_through = NULL; |
| 3416 context()->PrepareTest(&materialize_true, &materialize_false, | 3481 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3417 &if_true, &if_false, &fall_through); | 3482 &if_true, &if_false, &fall_through); |
| 3418 | 3483 |
| 3419 VisitForAccumulatorValue(expr->expression()); | 3484 VisitForAccumulatorValue(expr->expression()); |
| 3485 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3420 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 3486 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 3421 if (expr->is_strict()) { | 3487 if (expr->is_strict()) { |
| 3422 Split(equal, if_true, if_false, fall_through); | 3488 Split(equal, if_true, if_false, fall_through); |
| 3423 } else { | 3489 } else { |
| 3424 __ j(equal, if_true); | 3490 __ j(equal, if_true); |
| 3425 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 3491 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 3426 __ j(equal, if_true); | 3492 __ j(equal, if_true); |
| 3427 Condition is_smi = masm_->CheckSmi(rax); | 3493 Condition is_smi = masm_->CheckSmi(rax); |
| 3428 __ j(is_smi, if_false); | 3494 __ j(is_smi, if_false); |
| 3429 // It can be an undetectable object. | 3495 // It can be an undetectable object. |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3521 __ ret(0); | 3587 __ ret(0); |
| 3522 } | 3588 } |
| 3523 | 3589 |
| 3524 | 3590 |
| 3525 #undef __ | 3591 #undef __ |
| 3526 | 3592 |
| 3527 | 3593 |
| 3528 } } // namespace v8::internal | 3594 } } // namespace v8::internal |
| 3529 | 3595 |
| 3530 #endif // V8_TARGET_ARCH_X64 | 3596 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |