OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 |
11 // with the distribution. | 11 // with the distribution. |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 } | 203 } |
204 | 204 |
205 | 205 |
206 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) { | 206 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) { |
207 Comment cmnt(masm_, "[ Stack check"); | 207 Comment cmnt(masm_, "[ Stack check"); |
208 NearLabel ok; | 208 NearLabel ok; |
209 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 209 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
210 __ j(above_equal, &ok); | 210 __ j(above_equal, &ok); |
211 StackCheckStub stub; | 211 StackCheckStub stub; |
212 __ CallStub(&stub); | 212 __ CallStub(&stub); |
| 213 // Record a mapping of this PC offset to the OSR id. This is used to find |
| 214 // the AST id from the unoptimized code in order to use it as a key into |
| 215 // the deoptimization input data found in the optimized code. |
| 216 RecordStackCheck(stmt->OsrEntryId()); |
| 217 |
213 __ bind(&ok); | 218 __ bind(&ok); |
214 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); | 219 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
| 220 // Record a mapping of the OSR id to this PC. This is used if the OSR |
| 221 // entry becomes the target of a bailout. We don't expect it to be, but |
| 222 // we want it to work if it is. |
215 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS); | 223 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS); |
216 RecordStackCheck(stmt->OsrEntryId()); | |
217 } | 224 } |
218 | 225 |
219 | 226 |
220 void FullCodeGenerator::EmitReturnSequence() { | 227 void FullCodeGenerator::EmitReturnSequence() { |
221 Comment cmnt(masm_, "[ Return sequence"); | 228 Comment cmnt(masm_, "[ Return sequence"); |
222 if (return_label_.is_bound()) { | 229 if (return_label_.is_bound()) { |
223 __ jmp(&return_label_); | 230 __ jmp(&return_label_); |
224 } else { | 231 } else { |
225 __ bind(&return_label_); | 232 __ bind(&return_label_); |
226 if (FLAG_trace) { | 233 if (FLAG_trace) { |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
452 | 459 |
453 | 460 |
454 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { | 461 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { |
455 Heap::RootListIndex value_root_index = | 462 Heap::RootListIndex value_root_index = |
456 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; | 463 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; |
457 __ PushRoot(value_root_index); | 464 __ PushRoot(value_root_index); |
458 } | 465 } |
459 | 466 |
460 | 467 |
461 void FullCodeGenerator::TestContext::Plug(bool flag) const { | 468 void FullCodeGenerator::TestContext::Plug(bool flag) const { |
462 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 469 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, |
| 470 true, |
| 471 true_label_, |
| 472 false_label_); |
463 if (flag) { | 473 if (flag) { |
464 if (true_label_ != fall_through_) __ jmp(true_label_); | 474 if (true_label_ != fall_through_) __ jmp(true_label_); |
465 } else { | 475 } else { |
466 if (false_label_ != fall_through_) __ jmp(false_label_); | 476 if (false_label_ != fall_through_) __ jmp(false_label_); |
467 } | 477 } |
468 } | 478 } |
469 | 479 |
470 | 480 |
471 void FullCodeGenerator::DoTest(Label* if_true, | 481 void FullCodeGenerator::DoTest(Label* if_true, |
472 Label* if_false, | 482 Label* if_false, |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; | 558 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; |
549 __ RecordWrite(scratch1, offset, src, scratch2); | 559 __ RecordWrite(scratch1, offset, src, scratch2); |
550 } | 560 } |
551 } | 561 } |
552 | 562 |
553 | 563 |
554 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 564 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
555 bool should_normalize, | 565 bool should_normalize, |
556 Label* if_true, | 566 Label* if_true, |
557 Label* if_false) { | 567 Label* if_false) { |
| 568 // Only prepare for bailouts before splits if we're in a test |
| 569 // context. Otherwise, we let the Visit function deal with the |
| 570 // preparation to avoid preparing with the same AST id twice. |
| 571 if (!context()->IsTest() || !info_->IsOptimizable()) return; |
| 572 |
| 573 NearLabel skip; |
| 574 if (should_normalize) __ jmp(&skip); |
| 575 |
| 576 ForwardBailoutStack* current = forward_bailout_stack_; |
| 577 while (current != NULL) { |
| 578 PrepareForBailout(current->expr(), state); |
| 579 current = current->parent(); |
| 580 } |
| 581 |
| 582 if (should_normalize) { |
| 583 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 584 Split(equal, if_true, if_false, NULL); |
| 585 __ bind(&skip); |
| 586 } |
558 } | 587 } |
559 | 588 |
560 | 589 |
561 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 590 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
562 Variable::Mode mode, | 591 Variable::Mode mode, |
563 FunctionLiteral* function) { | 592 FunctionLiteral* function) { |
564 Comment cmnt(masm_, "[ Declaration"); | 593 Comment cmnt(masm_, "[ Declaration"); |
565 ASSERT(variable != NULL); // Must have been resolved. | 594 ASSERT(variable != NULL); // Must have been resolved. |
566 Slot* slot = variable->AsSlot(); | 595 Slot* slot = variable->AsSlot(); |
567 Property* prop = variable->AsProperty(); | 596 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)); | 691 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); |
663 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 692 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
664 // Return value is ignored. | 693 // Return value is ignored. |
665 } | 694 } |
666 | 695 |
667 | 696 |
668 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 697 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
669 Comment cmnt(masm_, "[ SwitchStatement"); | 698 Comment cmnt(masm_, "[ SwitchStatement"); |
670 Breakable nested_statement(this, stmt); | 699 Breakable nested_statement(this, stmt); |
671 SetStatementPosition(stmt); | 700 SetStatementPosition(stmt); |
| 701 |
672 // Keep the switch value on the stack until a case matches. | 702 // Keep the switch value on the stack until a case matches. |
673 VisitForStackValue(stmt->tag()); | 703 VisitForStackValue(stmt->tag()); |
| 704 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
674 | 705 |
675 ZoneList<CaseClause*>* clauses = stmt->cases(); | 706 ZoneList<CaseClause*>* clauses = stmt->cases(); |
676 CaseClause* default_clause = NULL; // Can occur anywhere in the list. | 707 CaseClause* default_clause = NULL; // Can occur anywhere in the list. |
677 | 708 |
678 Label next_test; // Recycled for each test. | 709 Label next_test; // Recycled for each test. |
679 // Compile all the tests with branches to their bodies. | 710 // Compile all the tests with branches to their bodies. |
680 for (int i = 0; i < clauses->length(); i++) { | 711 for (int i = 0; i < clauses->length(); i++) { |
681 CaseClause* clause = clauses->at(i); | 712 CaseClause* clause = clauses->at(i); |
682 // The default is not a test, but remember it as final fall through. | 713 // The default is not a test, but remember it as final fall through. |
683 if (clause->is_default()) { | 714 if (clause->is_default()) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
728 | 759 |
729 // Compile all the case bodies. | 760 // Compile all the case bodies. |
730 for (int i = 0; i < clauses->length(); i++) { | 761 for (int i = 0; i < clauses->length(); i++) { |
731 Comment cmnt(masm_, "[ Case body"); | 762 Comment cmnt(masm_, "[ Case body"); |
732 CaseClause* clause = clauses->at(i); | 763 CaseClause* clause = clauses->at(i); |
733 __ bind(clause->body_target()->entry_label()); | 764 __ bind(clause->body_target()->entry_label()); |
734 VisitStatements(clause->statements()); | 765 VisitStatements(clause->statements()); |
735 } | 766 } |
736 | 767 |
737 __ bind(nested_statement.break_target()); | 768 __ bind(nested_statement.break_target()); |
| 769 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
738 } | 770 } |
739 | 771 |
740 | 772 |
741 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 773 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
742 Comment cmnt(masm_, "[ ForInStatement"); | 774 Comment cmnt(masm_, "[ ForInStatement"); |
743 SetStatementPosition(stmt); | 775 SetStatementPosition(stmt); |
744 | 776 |
745 Label loop, exit; | 777 Label loop, exit; |
746 ForIn loop_statement(this, stmt); | 778 ForIn loop_statement(this, stmt); |
747 increment_loop_depth(); | 779 increment_loop_depth(); |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1217 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 1249 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
1218 // Fall through. | 1250 // Fall through. |
1219 case ObjectLiteral::Property::COMPUTED: | 1251 case ObjectLiteral::Property::COMPUTED: |
1220 if (key->handle()->IsSymbol()) { | 1252 if (key->handle()->IsSymbol()) { |
1221 VisitForAccumulatorValue(value); | 1253 VisitForAccumulatorValue(value); |
1222 __ Move(rcx, key->handle()); | 1254 __ Move(rcx, key->handle()); |
1223 __ movq(rdx, Operand(rsp, 0)); | 1255 __ movq(rdx, Operand(rsp, 0)); |
1224 if (property->emit_store()) { | 1256 if (property->emit_store()) { |
1225 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1257 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
1226 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1258 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1259 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
1227 } | 1260 } |
1228 break; | 1261 break; |
1229 } | 1262 } |
1230 // Fall through. | 1263 // Fall through. |
1231 case ObjectLiteral::Property::PROTOTYPE: | 1264 case ObjectLiteral::Property::PROTOTYPE: |
1232 __ push(Operand(rsp, 0)); // Duplicate receiver. | 1265 __ push(Operand(rsp, 0)); // Duplicate receiver. |
1233 VisitForStackValue(key); | 1266 VisitForStackValue(key); |
1234 VisitForStackValue(value); | 1267 VisitForStackValue(value); |
1235 if (property->emit_store()) { | 1268 if (property->emit_store()) { |
1236 __ CallRuntime(Runtime::kSetProperty, 3); | 1269 __ CallRuntime(Runtime::kSetProperty, 3); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1304 VisitForAccumulatorValue(subexpr); | 1337 VisitForAccumulatorValue(subexpr); |
1305 | 1338 |
1306 // Store the subexpression value in the array's elements. | 1339 // Store the subexpression value in the array's elements. |
1307 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 1340 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. |
1308 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 1341 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
1309 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1342 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
1310 __ movq(FieldOperand(rbx, offset), result_register()); | 1343 __ movq(FieldOperand(rbx, offset), result_register()); |
1311 | 1344 |
1312 // Update the write barrier for the array store. | 1345 // Update the write barrier for the array store. |
1313 __ RecordWrite(rbx, offset, result_register(), rcx); | 1346 __ RecordWrite(rbx, offset, result_register(), rcx); |
| 1347 |
| 1348 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
1314 } | 1349 } |
1315 | 1350 |
1316 if (result_saved) { | 1351 if (result_saved) { |
1317 context()->PlugTOS(); | 1352 context()->PlugTOS(); |
1318 } else { | 1353 } else { |
1319 context()->Plug(rax); | 1354 context()->Plug(rax); |
1320 } | 1355 } |
1321 } | 1356 } |
1322 | 1357 |
1323 | 1358 |
(...skipping 24 matching lines...) Expand all Loading... |
1348 break; | 1383 break; |
1349 case NAMED_PROPERTY: | 1384 case NAMED_PROPERTY: |
1350 if (expr->is_compound()) { | 1385 if (expr->is_compound()) { |
1351 // We need the receiver both on the stack and in the accumulator. | 1386 // We need the receiver both on the stack and in the accumulator. |
1352 VisitForAccumulatorValue(property->obj()); | 1387 VisitForAccumulatorValue(property->obj()); |
1353 __ push(result_register()); | 1388 __ push(result_register()); |
1354 } else { | 1389 } else { |
1355 VisitForStackValue(property->obj()); | 1390 VisitForStackValue(property->obj()); |
1356 } | 1391 } |
1357 break; | 1392 break; |
1358 case KEYED_PROPERTY: | 1393 case KEYED_PROPERTY: { |
1359 if (expr->is_compound()) { | 1394 if (expr->is_compound()) { |
1360 VisitForStackValue(property->obj()); | 1395 if (property->is_arguments_access()) { |
1361 VisitForAccumulatorValue(property->key()); | 1396 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1397 MemOperand slot_operand = |
| 1398 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); |
| 1399 __ push(slot_operand); |
| 1400 __ Move(rax, property->key()->AsLiteral()->handle()); |
| 1401 } else { |
| 1402 VisitForStackValue(property->obj()); |
| 1403 VisitForAccumulatorValue(property->key()); |
| 1404 } |
1362 __ movq(rdx, Operand(rsp, 0)); | 1405 __ movq(rdx, Operand(rsp, 0)); |
1363 __ push(rax); | 1406 __ push(rax); |
1364 } else { | 1407 } else { |
1365 VisitForStackValue(property->obj()); | 1408 if (property->is_arguments_access()) { |
1366 VisitForStackValue(property->key()); | 1409 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1410 MemOperand slot_operand = |
| 1411 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); |
| 1412 __ push(slot_operand); |
| 1413 __ Push(property->key()->AsLiteral()->handle()); |
| 1414 } else { |
| 1415 VisitForStackValue(property->obj()); |
| 1416 VisitForStackValue(property->key()); |
| 1417 } |
1367 } | 1418 } |
1368 break; | 1419 break; |
| 1420 } |
1369 } | 1421 } |
1370 | 1422 |
1371 if (expr->is_compound()) { | 1423 if (expr->is_compound()) { |
1372 { AccumulatorValueContext context(this); | 1424 { AccumulatorValueContext context(this); |
1373 switch (assign_type) { | 1425 switch (assign_type) { |
1374 case VARIABLE: | 1426 case VARIABLE: |
1375 EmitVariableLoad(expr->target()->AsVariableProxy()->var()); | 1427 EmitVariableLoad(expr->target()->AsVariableProxy()->var()); |
1376 break; | 1428 break; |
1377 case NAMED_PROPERTY: | 1429 case NAMED_PROPERTY: |
1378 EmitNamedPropertyLoad(property); | 1430 EmitNamedPropertyLoad(property); |
1379 break; | 1431 break; |
1380 case KEYED_PROPERTY: | 1432 case KEYED_PROPERTY: |
1381 EmitKeyedPropertyLoad(property); | 1433 EmitKeyedPropertyLoad(property); |
1382 break; | 1434 break; |
1383 } | 1435 } |
1384 } | 1436 } |
1385 | 1437 |
| 1438 // For property compound assignments we need another deoptimization |
| 1439 // point after the property load. |
| 1440 if (property != NULL) { |
| 1441 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); |
| 1442 } |
| 1443 |
1386 Token::Value op = expr->binary_op(); | 1444 Token::Value op = expr->binary_op(); |
1387 ConstantOperand constant = ShouldInlineSmiCase(op) | 1445 ConstantOperand constant = ShouldInlineSmiCase(op) |
1388 ? GetConstantOperand(op, expr->target(), expr->value()) | 1446 ? GetConstantOperand(op, expr->target(), expr->value()) |
1389 : kNoConstants; | 1447 : kNoConstants; |
1390 ASSERT(constant == kRightConstant || constant == kNoConstants); | 1448 ASSERT(constant == kRightConstant || constant == kNoConstants); |
1391 if (constant == kNoConstants) { | 1449 if (constant == kNoConstants) { |
1392 __ push(rax); // Left operand goes on the stack. | 1450 __ push(rax); // Left operand goes on the stack. |
1393 VisitForAccumulatorValue(expr->value()); | 1451 VisitForAccumulatorValue(expr->value()); |
1394 } | 1452 } |
1395 | 1453 |
1396 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() | 1454 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() |
1397 ? OVERWRITE_RIGHT | 1455 ? OVERWRITE_RIGHT |
1398 : NO_OVERWRITE; | 1456 : NO_OVERWRITE; |
1399 SetSourcePosition(expr->position() + 1); | 1457 SetSourcePosition(expr->position() + 1); |
1400 AccumulatorValueContext context(this); | 1458 AccumulatorValueContext context(this); |
1401 if (ShouldInlineSmiCase(op)) { | 1459 if (ShouldInlineSmiCase(op)) { |
1402 EmitInlineSmiBinaryOp(expr, | 1460 EmitInlineSmiBinaryOp(expr, |
1403 op, | 1461 op, |
1404 mode, | 1462 mode, |
1405 expr->target(), | 1463 expr->target(), |
1406 expr->value(), | 1464 expr->value(), |
1407 constant); | 1465 constant); |
1408 } else { | 1466 } else { |
1409 EmitBinaryOp(op, mode); | 1467 EmitBinaryOp(op, mode); |
1410 } | 1468 } |
| 1469 // Deoptimization point in case the binary operation may have side effects. |
| 1470 PrepareForBailout(expr->binary_operation(), TOS_REG); |
1411 } else { | 1471 } else { |
1412 VisitForAccumulatorValue(expr->value()); | 1472 VisitForAccumulatorValue(expr->value()); |
1413 } | 1473 } |
1414 | 1474 |
1415 // Record source position before possible IC call. | 1475 // Record source position before possible IC call. |
1416 SetSourcePosition(expr->position()); | 1476 SetSourcePosition(expr->position()); |
1417 | 1477 |
1418 // Store the value. | 1478 // Store the value. |
1419 switch (assign_type) { | 1479 switch (assign_type) { |
1420 case VARIABLE: | 1480 case VARIABLE: |
1421 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), | 1481 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), |
1422 expr->op()); | 1482 expr->op()); |
| 1483 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
1423 context()->Plug(rax); | 1484 context()->Plug(rax); |
1424 break; | 1485 break; |
1425 case NAMED_PROPERTY: | 1486 case NAMED_PROPERTY: |
1426 EmitNamedPropertyAssignment(expr); | 1487 EmitNamedPropertyAssignment(expr); |
1427 break; | 1488 break; |
1428 case KEYED_PROPERTY: | 1489 case KEYED_PROPERTY: |
1429 EmitKeyedPropertyAssignment(expr); | 1490 EmitKeyedPropertyAssignment(expr); |
1430 break; | 1491 break; |
1431 } | 1492 } |
1432 } | 1493 } |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1522 __ pop(rdx); | 1583 __ pop(rdx); |
1523 stub.GenerateCall(masm_, rdx, rax); | 1584 stub.GenerateCall(masm_, rdx, rax); |
1524 } else { | 1585 } else { |
1525 __ push(result_register()); | 1586 __ push(result_register()); |
1526 __ CallStub(&stub); | 1587 __ CallStub(&stub); |
1527 } | 1588 } |
1528 context()->Plug(rax); | 1589 context()->Plug(rax); |
1529 } | 1590 } |
1530 | 1591 |
1531 | 1592 |
1532 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_id) { | 1593 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
1533 // Invalid left-hand sides are rewritten to have a 'throw | 1594 // Invalid left-hand sides are rewritten to have a 'throw |
1534 // ReferenceError' on the left-hand side. | 1595 // ReferenceError' on the left-hand side. |
1535 if (!expr->IsValidLeftHandSide()) { | 1596 if (!expr->IsValidLeftHandSide()) { |
1536 VisitForEffect(expr); | 1597 VisitForEffect(expr); |
1537 return; | 1598 return; |
1538 } | 1599 } |
1539 | 1600 |
1540 // Left-hand side can only be a property, a global or a (parameter or local) | 1601 // 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. | 1602 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
1542 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1603 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
(...skipping 27 matching lines...) Expand all Loading... |
1570 VisitForStackValue(prop->obj()); | 1631 VisitForStackValue(prop->obj()); |
1571 VisitForAccumulatorValue(prop->key()); | 1632 VisitForAccumulatorValue(prop->key()); |
1572 __ movq(rcx, rax); | 1633 __ movq(rcx, rax); |
1573 __ pop(rdx); | 1634 __ pop(rdx); |
1574 __ pop(rax); | 1635 __ pop(rax); |
1575 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1636 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
1576 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1637 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
1577 break; | 1638 break; |
1578 } | 1639 } |
1579 } | 1640 } |
| 1641 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
1580 context()->Plug(rax); | 1642 context()->Plug(rax); |
1581 } | 1643 } |
1582 | 1644 |
1583 | 1645 |
1584 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1646 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
1585 Token::Value op) { | 1647 Token::Value op) { |
1586 // Left-hand sides that rewrite to explicit property accesses do not reach | 1648 // Left-hand sides that rewrite to explicit property accesses do not reach |
1587 // here. | 1649 // here. |
1588 ASSERT(var != NULL); | 1650 ASSERT(var != NULL); |
1589 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1651 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); | 1743 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
1682 | 1744 |
1683 // If the assignment ends an initialization block, revert to fast case. | 1745 // If the assignment ends an initialization block, revert to fast case. |
1684 if (expr->ends_initialization_block()) { | 1746 if (expr->ends_initialization_block()) { |
1685 __ push(rax); // Result of assignment, saved even if not needed. | 1747 __ push(rax); // Result of assignment, saved even if not needed. |
1686 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1748 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. |
1687 __ CallRuntime(Runtime::kToFastProperties, 1); | 1749 __ CallRuntime(Runtime::kToFastProperties, 1); |
1688 __ pop(rax); | 1750 __ pop(rax); |
1689 __ Drop(1); | 1751 __ Drop(1); |
1690 } | 1752 } |
| 1753 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
1691 context()->Plug(rax); | 1754 context()->Plug(rax); |
1692 } | 1755 } |
1693 | 1756 |
1694 | 1757 |
1695 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 1758 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
1696 // Assignment to a property, using a keyed store IC. | 1759 // Assignment to a property, using a keyed store IC. |
1697 | 1760 |
1698 // If the assignment starts a block of assignments to the same object, | 1761 // If the assignment starts a block of assignments to the same object, |
1699 // change to slow case to avoid the quadratic behavior of repeatedly | 1762 // change to slow case to avoid the quadratic behavior of repeatedly |
1700 // adding fast properties. | 1763 // adding fast properties. |
(...skipping 18 matching lines...) Expand all Loading... |
1719 | 1782 |
1720 // If the assignment ends an initialization block, revert to fast case. | 1783 // If the assignment ends an initialization block, revert to fast case. |
1721 if (expr->ends_initialization_block()) { | 1784 if (expr->ends_initialization_block()) { |
1722 __ pop(rdx); | 1785 __ pop(rdx); |
1723 __ push(rax); // Result of assignment, saved even if not needed. | 1786 __ push(rax); // Result of assignment, saved even if not needed. |
1724 __ push(rdx); | 1787 __ push(rdx); |
1725 __ CallRuntime(Runtime::kToFastProperties, 1); | 1788 __ CallRuntime(Runtime::kToFastProperties, 1); |
1726 __ pop(rax); | 1789 __ pop(rax); |
1727 } | 1790 } |
1728 | 1791 |
| 1792 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
1729 context()->Plug(rax); | 1793 context()->Plug(rax); |
1730 } | 1794 } |
1731 | 1795 |
1732 | 1796 |
1733 void FullCodeGenerator::VisitProperty(Property* expr) { | 1797 void FullCodeGenerator::VisitProperty(Property* expr) { |
1734 Comment cmnt(masm_, "[ Property"); | 1798 Comment cmnt(masm_, "[ Property"); |
1735 Expression* key = expr->key(); | 1799 Expression* key = expr->key(); |
1736 | 1800 |
1737 if (key->IsPropertyName()) { | 1801 if (key->IsPropertyName()) { |
1738 VisitForAccumulatorValue(expr->obj()); | 1802 VisitForAccumulatorValue(expr->obj()); |
(...skipping 20 matching lines...) Expand all Loading... |
1759 VisitForStackValue(args->at(i)); | 1823 VisitForStackValue(args->at(i)); |
1760 } | 1824 } |
1761 __ Move(rcx, name); | 1825 __ Move(rcx, name); |
1762 } | 1826 } |
1763 // Record source position for debugger. | 1827 // Record source position for debugger. |
1764 SetSourcePosition(expr->position()); | 1828 SetSourcePosition(expr->position()); |
1765 // Call the IC initialization code. | 1829 // Call the IC initialization code. |
1766 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1830 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
1767 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop); | 1831 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop); |
1768 EmitCallIC(ic, mode); | 1832 EmitCallIC(ic, mode); |
| 1833 RecordJSReturnSite(expr); |
1769 // Restore context register. | 1834 // Restore context register. |
1770 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1835 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1771 context()->Plug(rax); | 1836 context()->Plug(rax); |
1772 } | 1837 } |
1773 | 1838 |
1774 | 1839 |
1775 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 1840 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
1776 Expression* key, | 1841 Expression* key, |
1777 RelocInfo::Mode mode) { | 1842 RelocInfo::Mode mode) { |
1778 // Load the key. | 1843 // Load the key. |
(...skipping 13 matching lines...) Expand all Loading... |
1792 VisitForStackValue(args->at(i)); | 1857 VisitForStackValue(args->at(i)); |
1793 } | 1858 } |
1794 } | 1859 } |
1795 // Record source position for debugger. | 1860 // Record source position for debugger. |
1796 SetSourcePosition(expr->position()); | 1861 SetSourcePosition(expr->position()); |
1797 // Call the IC initialization code. | 1862 // Call the IC initialization code. |
1798 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1863 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
1799 Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop); | 1864 Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop); |
1800 __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key. | 1865 __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key. |
1801 EmitCallIC(ic, mode); | 1866 EmitCallIC(ic, mode); |
| 1867 RecordJSReturnSite(expr); |
1802 // Restore context register. | 1868 // Restore context register. |
1803 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1869 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1804 context()->DropAndPlug(1, rax); // Drop the key still on the stack. | 1870 context()->DropAndPlug(1, rax); // Drop the key still on the stack. |
1805 } | 1871 } |
1806 | 1872 |
1807 | 1873 |
1808 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 1874 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
1809 // Code common for calls using the call stub. | 1875 // Code common for calls using the call stub. |
1810 ZoneList<Expression*>* args = expr->arguments(); | 1876 ZoneList<Expression*>* args = expr->arguments(); |
1811 int arg_count = args->length(); | 1877 int arg_count = args->length(); |
1812 { PreservePositionScope scope(masm()->positions_recorder()); | 1878 { PreservePositionScope scope(masm()->positions_recorder()); |
1813 for (int i = 0; i < arg_count; i++) { | 1879 for (int i = 0; i < arg_count; i++) { |
1814 VisitForStackValue(args->at(i)); | 1880 VisitForStackValue(args->at(i)); |
1815 } | 1881 } |
1816 } | 1882 } |
1817 // Record source position for debugger. | 1883 // Record source position for debugger. |
1818 SetSourcePosition(expr->position()); | 1884 SetSourcePosition(expr->position()); |
1819 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1885 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
1820 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 1886 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
1821 __ CallStub(&stub); | 1887 __ CallStub(&stub); |
| 1888 RecordJSReturnSite(expr); |
1822 // Restore context register. | 1889 // Restore context register. |
1823 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1890 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1824 // Discard the function left on TOS. | 1891 // Discard the function left on TOS. |
1825 context()->DropAndPlug(1, rax); | 1892 context()->DropAndPlug(1, rax); |
1826 } | 1893 } |
1827 | 1894 |
1828 | 1895 |
1829 void FullCodeGenerator::VisitCall(Call* expr) { | 1896 void FullCodeGenerator::VisitCall(Call* expr) { |
| 1897 #ifdef DEBUG |
| 1898 // We want to verify that RecordJSReturnSite gets called on all paths |
| 1899 // through this function. Avoid early returns. |
| 1900 expr->return_is_recorded_ = false; |
| 1901 #endif |
| 1902 |
1830 Comment cmnt(masm_, "[ Call"); | 1903 Comment cmnt(masm_, "[ Call"); |
1831 Expression* fun = expr->expression(); | 1904 Expression* fun = expr->expression(); |
1832 Variable* var = fun->AsVariableProxy()->AsVariable(); | 1905 Variable* var = fun->AsVariableProxy()->AsVariable(); |
1833 | 1906 |
1834 if (var != NULL && var->is_possibly_eval()) { | 1907 if (var != NULL && var->is_possibly_eval()) { |
1835 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 1908 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
1836 // resolve the function we need to call and the receiver of the | 1909 // resolve the function we need to call and the receiver of the |
1837 // call. The we call the resolved function using the given | 1910 // call. Then we call the resolved function using the given |
1838 // arguments. | 1911 // arguments. |
1839 ZoneList<Expression*>* args = expr->arguments(); | 1912 ZoneList<Expression*>* args = expr->arguments(); |
1840 int arg_count = args->length(); | 1913 int arg_count = args->length(); |
1841 { PreservePositionScope pos_scope(masm()->positions_recorder()); | 1914 { PreservePositionScope pos_scope(masm()->positions_recorder()); |
1842 VisitForStackValue(fun); | 1915 VisitForStackValue(fun); |
1843 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. | 1916 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. |
1844 | 1917 |
1845 // Push the arguments. | 1918 // Push the arguments. |
1846 for (int i = 0; i < arg_count; i++) { | 1919 for (int i = 0; i < arg_count; i++) { |
1847 VisitForStackValue(args->at(i)); | 1920 VisitForStackValue(args->at(i)); |
(...skipping 16 matching lines...) Expand all Loading... |
1864 // The runtime call returns a pair of values in rax (function) and | 1937 // The runtime call returns a pair of values in rax (function) and |
1865 // rdx (receiver). Touch up the stack with the right values. | 1938 // rdx (receiver). Touch up the stack with the right values. |
1866 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx); | 1939 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx); |
1867 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax); | 1940 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax); |
1868 } | 1941 } |
1869 // Record source position for debugger. | 1942 // Record source position for debugger. |
1870 SetSourcePosition(expr->position()); | 1943 SetSourcePosition(expr->position()); |
1871 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1944 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
1872 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 1945 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
1873 __ CallStub(&stub); | 1946 __ CallStub(&stub); |
| 1947 RecordJSReturnSite(expr); |
1874 // Restore context register. | 1948 // Restore context register. |
1875 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1949 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1876 context()->DropAndPlug(1, rax); | 1950 context()->DropAndPlug(1, rax); |
1877 } else if (var != NULL && !var->is_this() && var->is_global()) { | 1951 } else if (var != NULL && !var->is_this() && var->is_global()) { |
1878 // Call to a global variable. | 1952 // Call to a global variable. |
1879 // Push global object as receiver for the call IC lookup. | 1953 // Push global object as receiver for the call IC lookup. |
1880 __ push(GlobalObjectOperand()); | 1954 __ push(GlobalObjectOperand()); |
1881 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); | 1955 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); |
1882 } else if (var != NULL && var->AsSlot() != NULL && | 1956 } else if (var != NULL && var->AsSlot() != NULL && |
1883 var->AsSlot()->type() == Slot::LOOKUP) { | 1957 var->AsSlot()->type() == Slot::LOOKUP) { |
1884 // Call to a lookup slot (dynamically introduced variable). | 1958 // Call to a lookup slot (dynamically introduced variable). |
1885 Label slow, done; | 1959 Label slow, done; |
1886 | 1960 |
1887 { PreservePositionScope scope(masm()->positions_recorder()); | 1961 { PreservePositionScope scope(masm()->positions_recorder()); |
1888 // Generate code for loading from variables potentially shadowed | 1962 // Generate code for loading from variables potentially shadowed |
1889 // by eval-introduced variables. | 1963 // by eval-introduced variables. |
1890 EmitDynamicLoadFromSlotFastCase(var->AsSlot(), | 1964 EmitDynamicLoadFromSlotFastCase(var->AsSlot(), |
1891 NOT_INSIDE_TYPEOF, | 1965 NOT_INSIDE_TYPEOF, |
1892 &slow, | 1966 &slow, |
1893 &done); | 1967 &done); |
1894 | 1968 |
1895 __ bind(&slow); | 1969 __ bind(&slow); |
1896 // Call the runtime to find the function to call (returned in rax) | 1970 } |
1897 // and the object holding it (returned in rdx). | 1971 // Call the runtime to find the function to call (returned in rax) |
1898 __ push(context_register()); | 1972 // and the object holding it (returned in rdx). |
1899 __ Push(var->name()); | 1973 __ push(context_register()); |
1900 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1974 __ Push(var->name()); |
1901 __ push(rax); // Function. | 1975 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
1902 __ push(rdx); // Receiver. | 1976 __ push(rax); // Function. |
| 1977 __ push(rdx); // Receiver. |
1903 | 1978 |
1904 // If fast case code has been generated, emit code to push the | 1979 // If fast case code has been generated, emit code to push the |
1905 // function and receiver and have the slow path jump around this | 1980 // function and receiver and have the slow path jump around this |
1906 // code. | 1981 // code. |
1907 if (done.is_linked()) { | 1982 if (done.is_linked()) { |
1908 NearLabel call; | 1983 NearLabel call; |
1909 __ jmp(&call); | 1984 __ jmp(&call); |
1910 __ bind(&done); | 1985 __ bind(&done); |
1911 // Push function. | 1986 // Push function. |
1912 __ push(rax); | 1987 __ push(rax); |
1913 // Push global receiver. | 1988 // Push global receiver. |
1914 __ movq(rbx, GlobalObjectOperand()); | 1989 __ movq(rbx, GlobalObjectOperand()); |
1915 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); | 1990 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); |
1916 __ bind(&call); | 1991 __ bind(&call); |
1917 } | |
1918 } | 1992 } |
1919 | 1993 |
1920 EmitCallWithStub(expr); | 1994 EmitCallWithStub(expr); |
1921 | |
1922 } else if (fun->AsProperty() != NULL) { | 1995 } else if (fun->AsProperty() != NULL) { |
1923 // Call to an object property. | 1996 // Call to an object property. |
1924 Property* prop = fun->AsProperty(); | 1997 Property* prop = fun->AsProperty(); |
1925 Literal* key = prop->key()->AsLiteral(); | 1998 Literal* key = prop->key()->AsLiteral(); |
1926 if (key != NULL && key->handle()->IsSymbol()) { | 1999 if (key != NULL && key->handle()->IsSymbol()) { |
1927 // Call to a named property, use call IC. | 2000 // Call to a named property, use call IC. |
1928 { PreservePositionScope scope(masm()->positions_recorder()); | 2001 { PreservePositionScope scope(masm()->positions_recorder()); |
1929 VisitForStackValue(prop->obj()); | 2002 VisitForStackValue(prop->obj()); |
1930 } | 2003 } |
1931 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2004 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
1932 } else { | 2005 } else { |
1933 // Call to a keyed property. | 2006 // Call to a keyed property. |
1934 // For a synthetic property use keyed load IC followed by function call, | 2007 // For a synthetic property use keyed load IC followed by function call, |
1935 // for a regular property use KeyedCallIC. | 2008 // for a regular property use keyed EmitCallIC. |
1936 { PreservePositionScope scope(masm()->positions_recorder()); | 2009 { PreservePositionScope scope(masm()->positions_recorder()); |
1937 VisitForStackValue(prop->obj()); | 2010 VisitForStackValue(prop->obj()); |
1938 } | 2011 } |
1939 if (prop->is_synthetic()) { | 2012 if (prop->is_synthetic()) { |
1940 { PreservePositionScope scope(masm()->positions_recorder()); | 2013 { PreservePositionScope scope(masm()->positions_recorder()); |
1941 VisitForAccumulatorValue(prop->key()); | 2014 VisitForAccumulatorValue(prop->key()); |
1942 __ movq(rdx, Operand(rsp, 0)); | |
1943 } | 2015 } |
1944 // Record source code position for IC call. | 2016 // Record source code position for IC call. |
1945 SetSourcePosition(prop->position()); | 2017 SetSourcePosition(prop->position()); |
| 2018 __ pop(rdx); // We do not need to keep the receiver. |
| 2019 |
1946 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 2020 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
1947 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 2021 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
1948 // Pop receiver. | |
1949 __ pop(rbx); | |
1950 // Push result (function). | 2022 // Push result (function). |
1951 __ push(rax); | 2023 __ push(rax); |
1952 // Push receiver object on stack. | 2024 // Push Global receiver. |
1953 __ movq(rcx, GlobalObjectOperand()); | 2025 __ movq(rcx, GlobalObjectOperand()); |
1954 __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); | 2026 __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); |
1955 EmitCallWithStub(expr); | 2027 EmitCallWithStub(expr); |
1956 } else { | 2028 } else { |
1957 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); | 2029 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); |
1958 } | 2030 } |
1959 } | 2031 } |
1960 } else { | 2032 } else { |
1961 // Call to some other expression. If the expression is an anonymous | 2033 // Call to some other expression. If the expression is an anonymous |
1962 // function literal not called in a loop, mark it as one that should | 2034 // function literal not called in a loop, mark it as one that should |
1963 // also use the fast code generator. | 2035 // also use the full code generator. |
1964 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 2036 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
1965 if (lit != NULL && | 2037 if (lit != NULL && |
1966 lit->name()->Equals(Heap::empty_string()) && | 2038 lit->name()->Equals(Heap::empty_string()) && |
1967 loop_depth() == 0) { | 2039 loop_depth() == 0) { |
1968 lit->set_try_full_codegen(true); | 2040 lit->set_try_full_codegen(true); |
1969 } | 2041 } |
1970 { PreservePositionScope scope(masm()->positions_recorder()); | 2042 { PreservePositionScope scope(masm()->positions_recorder()); |
1971 VisitForStackValue(fun); | 2043 VisitForStackValue(fun); |
1972 } | 2044 } |
1973 // Load global receiver object. | 2045 // Load global receiver object. |
1974 __ movq(rbx, GlobalObjectOperand()); | 2046 __ movq(rbx, GlobalObjectOperand()); |
1975 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); | 2047 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); |
1976 // Emit function call. | 2048 // Emit function call. |
1977 EmitCallWithStub(expr); | 2049 EmitCallWithStub(expr); |
1978 } | 2050 } |
| 2051 |
| 2052 #ifdef DEBUG |
| 2053 // RecordJSReturnSite should have been called. |
| 2054 ASSERT(expr->return_is_recorded_); |
| 2055 #endif |
1979 } | 2056 } |
1980 | 2057 |
1981 | 2058 |
1982 void FullCodeGenerator::VisitCallNew(CallNew* expr) { | 2059 void FullCodeGenerator::VisitCallNew(CallNew* expr) { |
1983 Comment cmnt(masm_, "[ CallNew"); | 2060 Comment cmnt(masm_, "[ CallNew"); |
1984 // According to ECMA-262, section 11.2.2, page 44, the function | 2061 // According to ECMA-262, section 11.2.2, page 44, the function |
1985 // expression in new calls must be evaluated before the | 2062 // expression in new calls must be evaluated before the |
1986 // arguments. | 2063 // arguments. |
1987 | 2064 |
1988 // Push constructor on the stack. If it's not a function it's used as | 2065 // Push constructor on the stack. If it's not a function it's used as |
(...skipping 27 matching lines...) Expand all Loading... |
2016 | 2093 |
2017 VisitForAccumulatorValue(args->at(0)); | 2094 VisitForAccumulatorValue(args->at(0)); |
2018 | 2095 |
2019 Label materialize_true, materialize_false; | 2096 Label materialize_true, materialize_false; |
2020 Label* if_true = NULL; | 2097 Label* if_true = NULL; |
2021 Label* if_false = NULL; | 2098 Label* if_false = NULL; |
2022 Label* fall_through = NULL; | 2099 Label* fall_through = NULL; |
2023 context()->PrepareTest(&materialize_true, &materialize_false, | 2100 context()->PrepareTest(&materialize_true, &materialize_false, |
2024 &if_true, &if_false, &fall_through); | 2101 &if_true, &if_false, &fall_through); |
2025 | 2102 |
| 2103 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2026 __ JumpIfSmi(rax, if_true); | 2104 __ JumpIfSmi(rax, if_true); |
2027 __ jmp(if_false); | 2105 __ jmp(if_false); |
2028 | 2106 |
2029 context()->Plug(if_true, if_false); | 2107 context()->Plug(if_true, if_false); |
2030 } | 2108 } |
2031 | 2109 |
2032 | 2110 |
2033 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { | 2111 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { |
2034 ASSERT(args->length() == 1); | 2112 ASSERT(args->length() == 1); |
2035 | 2113 |
2036 VisitForAccumulatorValue(args->at(0)); | 2114 VisitForAccumulatorValue(args->at(0)); |
2037 | 2115 |
2038 Label materialize_true, materialize_false; | 2116 Label materialize_true, materialize_false; |
2039 Label* if_true = NULL; | 2117 Label* if_true = NULL; |
2040 Label* if_false = NULL; | 2118 Label* if_false = NULL; |
2041 Label* fall_through = NULL; | 2119 Label* fall_through = NULL; |
2042 context()->PrepareTest(&materialize_true, &materialize_false, | 2120 context()->PrepareTest(&materialize_true, &materialize_false, |
2043 &if_true, &if_false, &fall_through); | 2121 &if_true, &if_false, &fall_through); |
2044 | 2122 |
| 2123 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2045 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax); | 2124 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax); |
2046 Split(non_negative_smi, if_true, if_false, fall_through); | 2125 Split(non_negative_smi, if_true, if_false, fall_through); |
2047 | 2126 |
2048 context()->Plug(if_true, if_false); | 2127 context()->Plug(if_true, if_false); |
2049 } | 2128 } |
2050 | 2129 |
2051 | 2130 |
2052 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { | 2131 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { |
2053 ASSERT(args->length() == 1); | 2132 ASSERT(args->length() == 1); |
2054 | 2133 |
(...skipping 11 matching lines...) Expand all Loading... |
2066 __ j(equal, if_true); | 2145 __ j(equal, if_true); |
2067 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 2146 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
2068 // Undetectable objects behave like undefined when tested with typeof. | 2147 // Undetectable objects behave like undefined when tested with typeof. |
2069 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2148 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
2070 Immediate(1 << Map::kIsUndetectable)); | 2149 Immediate(1 << Map::kIsUndetectable)); |
2071 __ j(not_zero, if_false); | 2150 __ j(not_zero, if_false); |
2072 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 2151 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
2073 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE)); | 2152 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE)); |
2074 __ j(below, if_false); | 2153 __ j(below, if_false); |
2075 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE)); | 2154 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE)); |
| 2155 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2076 Split(below_equal, if_true, if_false, fall_through); | 2156 Split(below_equal, if_true, if_false, fall_through); |
2077 | 2157 |
2078 context()->Plug(if_true, if_false); | 2158 context()->Plug(if_true, if_false); |
2079 } | 2159 } |
2080 | 2160 |
2081 | 2161 |
2082 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { | 2162 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { |
2083 ASSERT(args->length() == 1); | 2163 ASSERT(args->length() == 1); |
2084 | 2164 |
2085 VisitForAccumulatorValue(args->at(0)); | 2165 VisitForAccumulatorValue(args->at(0)); |
2086 | 2166 |
2087 Label materialize_true, materialize_false; | 2167 Label materialize_true, materialize_false; |
2088 Label* if_true = NULL; | 2168 Label* if_true = NULL; |
2089 Label* if_false = NULL; | 2169 Label* if_false = NULL; |
2090 Label* fall_through = NULL; | 2170 Label* fall_through = NULL; |
2091 context()->PrepareTest(&materialize_true, &materialize_false, | 2171 context()->PrepareTest(&materialize_true, &materialize_false, |
2092 &if_true, &if_false, &fall_through); | 2172 &if_true, &if_false, &fall_through); |
2093 | 2173 |
2094 __ JumpIfSmi(rax, if_false); | 2174 __ JumpIfSmi(rax, if_false); |
2095 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | 2175 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); |
| 2176 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2096 Split(above_equal, if_true, if_false, fall_through); | 2177 Split(above_equal, if_true, if_false, fall_through); |
2097 | 2178 |
2098 context()->Plug(if_true, if_false); | 2179 context()->Plug(if_true, if_false); |
2099 } | 2180 } |
2100 | 2181 |
2101 | 2182 |
2102 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { | 2183 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { |
2103 ASSERT(args->length() == 1); | 2184 ASSERT(args->length() == 1); |
2104 | 2185 |
2105 VisitForAccumulatorValue(args->at(0)); | 2186 VisitForAccumulatorValue(args->at(0)); |
2106 | 2187 |
2107 Label materialize_true, materialize_false; | 2188 Label materialize_true, materialize_false; |
2108 Label* if_true = NULL; | 2189 Label* if_true = NULL; |
2109 Label* if_false = NULL; | 2190 Label* if_false = NULL; |
2110 Label* fall_through = NULL; | 2191 Label* fall_through = NULL; |
2111 context()->PrepareTest(&materialize_true, &materialize_false, | 2192 context()->PrepareTest(&materialize_true, &materialize_false, |
2112 &if_true, &if_false, &fall_through); | 2193 &if_true, &if_false, &fall_through); |
2113 | 2194 |
2114 __ JumpIfSmi(rax, if_false); | 2195 __ JumpIfSmi(rax, if_false); |
2115 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 2196 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
2116 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2197 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
2117 Immediate(1 << Map::kIsUndetectable)); | 2198 Immediate(1 << Map::kIsUndetectable)); |
| 2199 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2118 Split(not_zero, if_true, if_false, fall_through); | 2200 Split(not_zero, if_true, if_false, fall_through); |
2119 | 2201 |
2120 context()->Plug(if_true, if_false); | 2202 context()->Plug(if_true, if_false); |
2121 } | 2203 } |
2122 | 2204 |
2123 | 2205 |
2124 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( | 2206 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( |
2125 ZoneList<Expression*>* args) { | 2207 ZoneList<Expression*>* args) { |
2126 ASSERT(args->length() == 1); | 2208 ASSERT(args->length() == 1); |
2127 | 2209 |
2128 VisitForAccumulatorValue(args->at(0)); | 2210 VisitForAccumulatorValue(args->at(0)); |
2129 | 2211 |
2130 Label materialize_true, materialize_false; | 2212 Label materialize_true, materialize_false; |
2131 Label* if_true = NULL; | 2213 Label* if_true = NULL; |
2132 Label* if_false = NULL; | 2214 Label* if_false = NULL; |
2133 Label* fall_through = NULL; | 2215 Label* fall_through = NULL; |
2134 context()->PrepareTest(&materialize_true, &materialize_false, | 2216 context()->PrepareTest(&materialize_true, &materialize_false, |
2135 &if_true, &if_false, &fall_through); | 2217 &if_true, &if_false, &fall_through); |
2136 | 2218 |
2137 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only | 2219 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only |
2138 // used in a few functions in runtime.js which should not normally be hit by | 2220 // used in a few functions in runtime.js which should not normally be hit by |
2139 // this compiler. | 2221 // this compiler. |
| 2222 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2140 __ jmp(if_false); | 2223 __ jmp(if_false); |
2141 context()->Plug(if_true, if_false); | 2224 context()->Plug(if_true, if_false); |
2142 } | 2225 } |
2143 | 2226 |
2144 | 2227 |
2145 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { | 2228 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { |
2146 ASSERT(args->length() == 1); | 2229 ASSERT(args->length() == 1); |
2147 | 2230 |
2148 VisitForAccumulatorValue(args->at(0)); | 2231 VisitForAccumulatorValue(args->at(0)); |
2149 | 2232 |
2150 Label materialize_true, materialize_false; | 2233 Label materialize_true, materialize_false; |
2151 Label* if_true = NULL; | 2234 Label* if_true = NULL; |
2152 Label* if_false = NULL; | 2235 Label* if_false = NULL; |
2153 Label* fall_through = NULL; | 2236 Label* fall_through = NULL; |
2154 context()->PrepareTest(&materialize_true, &materialize_false, | 2237 context()->PrepareTest(&materialize_true, &materialize_false, |
2155 &if_true, &if_false, &fall_through); | 2238 &if_true, &if_false, &fall_through); |
2156 | 2239 |
2157 __ JumpIfSmi(rax, if_false); | 2240 __ JumpIfSmi(rax, if_false); |
2158 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); | 2241 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); |
| 2242 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2159 Split(equal, if_true, if_false, fall_through); | 2243 Split(equal, if_true, if_false, fall_through); |
2160 | 2244 |
2161 context()->Plug(if_true, if_false); | 2245 context()->Plug(if_true, if_false); |
2162 } | 2246 } |
2163 | 2247 |
2164 | 2248 |
2165 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { | 2249 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { |
2166 ASSERT(args->length() == 1); | 2250 ASSERT(args->length() == 1); |
2167 | 2251 |
2168 VisitForAccumulatorValue(args->at(0)); | 2252 VisitForAccumulatorValue(args->at(0)); |
2169 | 2253 |
2170 Label materialize_true, materialize_false; | 2254 Label materialize_true, materialize_false; |
2171 Label* if_true = NULL; | 2255 Label* if_true = NULL; |
2172 Label* if_false = NULL; | 2256 Label* if_false = NULL; |
2173 Label* fall_through = NULL; | 2257 Label* fall_through = NULL; |
2174 context()->PrepareTest(&materialize_true, &materialize_false, | 2258 context()->PrepareTest(&materialize_true, &materialize_false, |
2175 &if_true, &if_false, &fall_through); | 2259 &if_true, &if_false, &fall_through); |
2176 | 2260 |
2177 __ JumpIfSmi(rax, if_false); | 2261 __ JumpIfSmi(rax, if_false); |
2178 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx); | 2262 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx); |
| 2263 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2179 Split(equal, if_true, if_false, fall_through); | 2264 Split(equal, if_true, if_false, fall_through); |
2180 | 2265 |
2181 context()->Plug(if_true, if_false); | 2266 context()->Plug(if_true, if_false); |
2182 } | 2267 } |
2183 | 2268 |
2184 | 2269 |
2185 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { | 2270 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { |
2186 ASSERT(args->length() == 1); | 2271 ASSERT(args->length() == 1); |
2187 | 2272 |
2188 VisitForAccumulatorValue(args->at(0)); | 2273 VisitForAccumulatorValue(args->at(0)); |
2189 | 2274 |
2190 Label materialize_true, materialize_false; | 2275 Label materialize_true, materialize_false; |
2191 Label* if_true = NULL; | 2276 Label* if_true = NULL; |
2192 Label* if_false = NULL; | 2277 Label* if_false = NULL; |
2193 Label* fall_through = NULL; | 2278 Label* fall_through = NULL; |
2194 context()->PrepareTest(&materialize_true, &materialize_false, | 2279 context()->PrepareTest(&materialize_true, &materialize_false, |
2195 &if_true, &if_false, &fall_through); | 2280 &if_true, &if_false, &fall_through); |
2196 | 2281 |
2197 __ JumpIfSmi(rax, if_false); | 2282 __ JumpIfSmi(rax, if_false); |
2198 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx); | 2283 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx); |
| 2284 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2199 Split(equal, if_true, if_false, fall_through); | 2285 Split(equal, if_true, if_false, fall_through); |
2200 | 2286 |
2201 context()->Plug(if_true, if_false); | 2287 context()->Plug(if_true, if_false); |
2202 } | 2288 } |
2203 | 2289 |
2204 | 2290 |
2205 | 2291 |
2206 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { | 2292 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { |
2207 ASSERT(args->length() == 0); | 2293 ASSERT(args->length() == 0); |
2208 | 2294 |
(...skipping 11 matching lines...) Expand all Loading... |
2220 Label check_frame_marker; | 2306 Label check_frame_marker; |
2221 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), | 2307 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), |
2222 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2308 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
2223 __ j(not_equal, &check_frame_marker); | 2309 __ j(not_equal, &check_frame_marker); |
2224 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); | 2310 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); |
2225 | 2311 |
2226 // Check the marker in the calling frame. | 2312 // Check the marker in the calling frame. |
2227 __ bind(&check_frame_marker); | 2313 __ bind(&check_frame_marker); |
2228 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), | 2314 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), |
2229 Smi::FromInt(StackFrame::CONSTRUCT)); | 2315 Smi::FromInt(StackFrame::CONSTRUCT)); |
| 2316 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2230 Split(equal, if_true, if_false, fall_through); | 2317 Split(equal, if_true, if_false, fall_through); |
2231 | 2318 |
2232 context()->Plug(if_true, if_false); | 2319 context()->Plug(if_true, if_false); |
2233 } | 2320 } |
2234 | 2321 |
2235 | 2322 |
2236 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { | 2323 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { |
2237 ASSERT(args->length() == 2); | 2324 ASSERT(args->length() == 2); |
2238 | 2325 |
2239 // Load the two objects into registers and perform the comparison. | 2326 // Load the two objects into registers and perform the comparison. |
2240 VisitForStackValue(args->at(0)); | 2327 VisitForStackValue(args->at(0)); |
2241 VisitForAccumulatorValue(args->at(1)); | 2328 VisitForAccumulatorValue(args->at(1)); |
2242 | 2329 |
2243 Label materialize_true, materialize_false; | 2330 Label materialize_true, materialize_false; |
2244 Label* if_true = NULL; | 2331 Label* if_true = NULL; |
2245 Label* if_false = NULL; | 2332 Label* if_false = NULL; |
2246 Label* fall_through = NULL; | 2333 Label* fall_through = NULL; |
2247 context()->PrepareTest(&materialize_true, &materialize_false, | 2334 context()->PrepareTest(&materialize_true, &materialize_false, |
2248 &if_true, &if_false, &fall_through); | 2335 &if_true, &if_false, &fall_through); |
2249 | 2336 |
2250 __ pop(rbx); | 2337 __ pop(rbx); |
2251 __ cmpq(rax, rbx); | 2338 __ cmpq(rax, rbx); |
| 2339 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2252 Split(equal, if_true, if_false, fall_through); | 2340 Split(equal, if_true, if_false, fall_through); |
2253 | 2341 |
2254 context()->Plug(if_true, if_false); | 2342 context()->Plug(if_true, if_false); |
2255 } | 2343 } |
2256 | 2344 |
2257 | 2345 |
2258 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2346 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
2259 ASSERT(args->length() == 1); | 2347 ASSERT(args->length() == 1); |
2260 | 2348 |
2261 // ArgumentsAccessStub expects the key in rdx and the formal | 2349 // ArgumentsAccessStub expects the key in rdx and the formal |
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2815 | 2903 |
2816 Label materialize_true, materialize_false; | 2904 Label materialize_true, materialize_false; |
2817 Label* if_true = NULL; | 2905 Label* if_true = NULL; |
2818 Label* if_false = NULL; | 2906 Label* if_false = NULL; |
2819 Label* fall_through = NULL; | 2907 Label* fall_through = NULL; |
2820 context()->PrepareTest(&materialize_true, &materialize_false, | 2908 context()->PrepareTest(&materialize_true, &materialize_false, |
2821 &if_true, &if_false, &fall_through); | 2909 &if_true, &if_false, &fall_through); |
2822 | 2910 |
2823 __ testl(FieldOperand(rax, String::kHashFieldOffset), | 2911 __ testl(FieldOperand(rax, String::kHashFieldOffset), |
2824 Immediate(String::kContainsCachedArrayIndexMask)); | 2912 Immediate(String::kContainsCachedArrayIndexMask)); |
| 2913 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2825 __ j(zero, if_true); | 2914 __ j(zero, if_true); |
2826 __ jmp(if_false); | 2915 __ jmp(if_false); |
2827 | 2916 |
2828 context()->Plug(if_true, if_false); | 2917 context()->Plug(if_true, if_false); |
2829 } | 2918 } |
2830 | 2919 |
2831 | 2920 |
2832 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { | 2921 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { |
2833 ASSERT(args->length() == 1); | 2922 ASSERT(args->length() == 1); |
2834 | 2923 |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2936 | 3025 |
2937 case Token::NOT: { | 3026 case Token::NOT: { |
2938 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 3027 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
2939 Label materialize_true, materialize_false; | 3028 Label materialize_true, materialize_false; |
2940 Label* if_true = NULL; | 3029 Label* if_true = NULL; |
2941 Label* if_false = NULL; | 3030 Label* if_false = NULL; |
2942 Label* fall_through = NULL; | 3031 Label* fall_through = NULL; |
2943 // Notice that the labels are swapped. | 3032 // Notice that the labels are swapped. |
2944 context()->PrepareTest(&materialize_true, &materialize_false, | 3033 context()->PrepareTest(&materialize_true, &materialize_false, |
2945 &if_false, &if_true, &fall_through); | 3034 &if_false, &if_true, &fall_through); |
| 3035 if (context()->IsTest()) ForwardBailoutToChild(expr); |
2946 VisitForControl(expr->expression(), if_true, if_false, fall_through); | 3036 VisitForControl(expr->expression(), if_true, if_false, fall_through); |
2947 context()->Plug(if_false, if_true); // Labels swapped. | 3037 context()->Plug(if_false, if_true); // Labels swapped. |
2948 break; | 3038 break; |
2949 } | 3039 } |
2950 | 3040 |
2951 case Token::TYPEOF: { | 3041 case Token::TYPEOF: { |
2952 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 3042 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
2953 { StackValueContext context(this); | 3043 { StackValueContext context(this); |
2954 VisitForTypeofValue(expr->expression()); | 3044 VisitForTypeofValue(expr->expression()); |
2955 } | 3045 } |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3049 } else { | 3139 } else { |
3050 // Reserve space for result of postfix operation. | 3140 // Reserve space for result of postfix operation. |
3051 if (expr->is_postfix() && !context()->IsEffect()) { | 3141 if (expr->is_postfix() && !context()->IsEffect()) { |
3052 __ Push(Smi::FromInt(0)); | 3142 __ Push(Smi::FromInt(0)); |
3053 } | 3143 } |
3054 if (assign_type == NAMED_PROPERTY) { | 3144 if (assign_type == NAMED_PROPERTY) { |
3055 VisitForAccumulatorValue(prop->obj()); | 3145 VisitForAccumulatorValue(prop->obj()); |
3056 __ push(rax); // Copy of receiver, needed for later store. | 3146 __ push(rax); // Copy of receiver, needed for later store. |
3057 EmitNamedPropertyLoad(prop); | 3147 EmitNamedPropertyLoad(prop); |
3058 } else { | 3148 } else { |
3059 VisitForStackValue(prop->obj()); | 3149 if (prop->is_arguments_access()) { |
3060 VisitForAccumulatorValue(prop->key()); | 3150 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); |
| 3151 MemOperand slot_operand = |
| 3152 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); |
| 3153 __ push(slot_operand); |
| 3154 __ Move(rax, prop->key()->AsLiteral()->handle()); |
| 3155 } else { |
| 3156 VisitForStackValue(prop->obj()); |
| 3157 VisitForAccumulatorValue(prop->key()); |
| 3158 } |
3061 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack | 3159 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack |
3062 __ push(rax); // Copy of key, needed for later store. | 3160 __ push(rax); // Copy of key, needed for later store. |
3063 EmitKeyedPropertyLoad(prop); | 3161 EmitKeyedPropertyLoad(prop); |
3064 } | 3162 } |
3065 } | 3163 } |
3066 | 3164 |
| 3165 // We need a second deoptimization point after loading the value |
| 3166 // in case evaluating the property load my have a side effect. |
| 3167 PrepareForBailout(expr->increment(), TOS_REG); |
| 3168 |
3067 // Call ToNumber only if operand is not a smi. | 3169 // Call ToNumber only if operand is not a smi. |
3068 NearLabel no_conversion; | 3170 NearLabel no_conversion; |
3069 Condition is_smi; | 3171 Condition is_smi; |
3070 is_smi = masm_->CheckSmi(rax); | 3172 is_smi = masm_->CheckSmi(rax); |
3071 __ j(is_smi, &no_conversion); | 3173 __ j(is_smi, &no_conversion); |
3072 __ push(rax); | 3174 __ push(rax); |
3073 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 3175 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
3074 __ bind(&no_conversion); | 3176 __ bind(&no_conversion); |
3075 | 3177 |
3076 // Save result for postfix expressions. | 3178 // Save result for postfix expressions. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3126 __ bind(&done); | 3228 __ bind(&done); |
3127 | 3229 |
3128 // Store the value returned in rax. | 3230 // Store the value returned in rax. |
3129 switch (assign_type) { | 3231 switch (assign_type) { |
3130 case VARIABLE: | 3232 case VARIABLE: |
3131 if (expr->is_postfix()) { | 3233 if (expr->is_postfix()) { |
3132 // Perform the assignment as if via '='. | 3234 // Perform the assignment as if via '='. |
3133 { EffectContext context(this); | 3235 { EffectContext context(this); |
3134 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3236 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
3135 Token::ASSIGN); | 3237 Token::ASSIGN); |
| 3238 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3136 context.Plug(rax); | 3239 context.Plug(rax); |
3137 } | 3240 } |
3138 // For all contexts except kEffect: We have the result on | 3241 // For all contexts except kEffect: We have the result on |
3139 // top of the stack. | 3242 // top of the stack. |
3140 if (!context()->IsEffect()) { | 3243 if (!context()->IsEffect()) { |
3141 context()->PlugTOS(); | 3244 context()->PlugTOS(); |
3142 } | 3245 } |
3143 } else { | 3246 } else { |
3144 // Perform the assignment as if via '='. | 3247 // Perform the assignment as if via '='. |
3145 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3248 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
3146 Token::ASSIGN); | 3249 Token::ASSIGN); |
| 3250 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3147 context()->Plug(rax); | 3251 context()->Plug(rax); |
3148 } | 3252 } |
3149 break; | 3253 break; |
3150 case NAMED_PROPERTY: { | 3254 case NAMED_PROPERTY: { |
3151 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 3255 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
3152 __ pop(rdx); | 3256 __ pop(rdx); |
3153 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 3257 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
3154 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3258 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3259 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3155 if (expr->is_postfix()) { | 3260 if (expr->is_postfix()) { |
3156 if (!context()->IsEffect()) { | 3261 if (!context()->IsEffect()) { |
3157 context()->PlugTOS(); | 3262 context()->PlugTOS(); |
3158 } | 3263 } |
3159 } else { | 3264 } else { |
3160 context()->Plug(rax); | 3265 context()->Plug(rax); |
3161 } | 3266 } |
3162 break; | 3267 break; |
3163 } | 3268 } |
3164 case KEYED_PROPERTY: { | 3269 case KEYED_PROPERTY: { |
3165 __ pop(rcx); | 3270 __ pop(rcx); |
3166 __ pop(rdx); | 3271 __ pop(rdx); |
3167 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 3272 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
3168 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3273 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3274 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3169 if (expr->is_postfix()) { | 3275 if (expr->is_postfix()) { |
3170 if (!context()->IsEffect()) { | 3276 if (!context()->IsEffect()) { |
3171 context()->PlugTOS(); | 3277 context()->PlugTOS(); |
3172 } | 3278 } |
3173 } else { | 3279 } else { |
3174 context()->Plug(rax); | 3280 context()->Plug(rax); |
3175 } | 3281 } |
3176 break; | 3282 break; |
3177 } | 3283 } |
3178 } | 3284 } |
3179 } | 3285 } |
3180 | 3286 |
3181 | 3287 |
3182 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 3288 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
3183 VariableProxy* proxy = expr->AsVariableProxy(); | 3289 VariableProxy* proxy = expr->AsVariableProxy(); |
3184 ASSERT(!context()->IsEffect()); | 3290 ASSERT(!context()->IsEffect()); |
3185 ASSERT(!context()->IsTest()); | 3291 ASSERT(!context()->IsTest()); |
3186 | 3292 |
3187 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3293 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
3188 Comment cmnt(masm_, "Global variable"); | 3294 Comment cmnt(masm_, "Global variable"); |
3189 __ Move(rcx, proxy->name()); | 3295 __ Move(rcx, proxy->name()); |
3190 __ movq(rax, GlobalObjectOperand()); | 3296 __ movq(rax, GlobalObjectOperand()); |
3191 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3297 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
3192 // Use a regular load, not a contextual load, to avoid a reference | 3298 // Use a regular load, not a contextual load, to avoid a reference |
3193 // error. | 3299 // error. |
3194 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3300 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3301 PrepareForBailout(expr, TOS_REG); |
3195 context()->Plug(rax); | 3302 context()->Plug(rax); |
3196 } else if (proxy != NULL && | 3303 } else if (proxy != NULL && |
3197 proxy->var()->AsSlot() != NULL && | 3304 proxy->var()->AsSlot() != NULL && |
3198 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { | 3305 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { |
3199 Label done, slow; | 3306 Label done, slow; |
3200 | 3307 |
3201 // Generate code for loading from variables potentially shadowed | 3308 // Generate code for loading from variables potentially shadowed |
3202 // by eval-introduced variables. | 3309 // by eval-introduced variables. |
3203 Slot* slot = proxy->var()->AsSlot(); | 3310 Slot* slot = proxy->var()->AsSlot(); |
3204 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); | 3311 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); |
3205 | 3312 |
3206 __ bind(&slow); | 3313 __ bind(&slow); |
3207 __ push(rsi); | 3314 __ push(rsi); |
3208 __ Push(proxy->name()); | 3315 __ Push(proxy->name()); |
3209 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3316 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 3317 PrepareForBailout(expr, TOS_REG); |
3210 __ bind(&done); | 3318 __ bind(&done); |
3211 | 3319 |
3212 context()->Plug(rax); | 3320 context()->Plug(rax); |
3213 } else { | 3321 } else { |
3214 // This expression cannot throw a reference error at the top level. | 3322 // This expression cannot throw a reference error at the top level. |
3215 Visit(expr); | 3323 context()->HandleExpression(expr); |
3216 } | 3324 } |
3217 } | 3325 } |
3218 | 3326 |
3219 | 3327 |
3220 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, | 3328 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, |
3221 Expression* left, | 3329 Expression* left, |
3222 Expression* right, | 3330 Expression* right, |
3223 Label* if_true, | 3331 Label* if_true, |
3224 Label* if_false, | 3332 Label* if_false, |
3225 Label* fall_through) { | 3333 Label* fall_through) { |
3226 if (op != Token::EQ && op != Token::EQ_STRICT) return false; | 3334 if (op != Token::EQ && op != Token::EQ_STRICT) return false; |
3227 | 3335 |
3228 // Check for the pattern: typeof <expression> == <string literal>. | 3336 // Check for the pattern: typeof <expression> == <string literal>. |
3229 Literal* right_literal = right->AsLiteral(); | 3337 Literal* right_literal = right->AsLiteral(); |
3230 if (right_literal == NULL) return false; | 3338 if (right_literal == NULL) return false; |
3231 Handle<Object> right_literal_value = right_literal->handle(); | 3339 Handle<Object> right_literal_value = right_literal->handle(); |
3232 if (!right_literal_value->IsString()) return false; | 3340 if (!right_literal_value->IsString()) return false; |
3233 UnaryOperation* left_unary = left->AsUnaryOperation(); | 3341 UnaryOperation* left_unary = left->AsUnaryOperation(); |
3234 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | 3342 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; |
3235 Handle<String> check = Handle<String>::cast(right_literal_value); | 3343 Handle<String> check = Handle<String>::cast(right_literal_value); |
3236 | 3344 |
3237 { AccumulatorValueContext context(this); | 3345 { AccumulatorValueContext context(this); |
3238 VisitForTypeofValue(left_unary->expression()); | 3346 VisitForTypeofValue(left_unary->expression()); |
3239 } | 3347 } |
| 3348 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3240 | 3349 |
3241 if (check->Equals(Heap::number_symbol())) { | 3350 if (check->Equals(Heap::number_symbol())) { |
3242 Condition is_smi = masm_->CheckSmi(rax); | 3351 Condition is_smi = masm_->CheckSmi(rax); |
3243 __ j(is_smi, if_true); | 3352 __ j(is_smi, if_true); |
3244 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); | 3353 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
3245 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); | 3354 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); |
3246 Split(equal, if_true, if_false, fall_through); | 3355 Split(equal, if_true, if_false, fall_through); |
3247 } else if (check->Equals(Heap::string_symbol())) { | 3356 } else if (check->Equals(Heap::string_symbol())) { |
3248 Condition is_smi = masm_->CheckSmi(rax); | 3357 Condition is_smi = masm_->CheckSmi(rax); |
3249 __ j(is_smi, if_false); | 3358 __ 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)) { | 3432 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { |
3324 context()->Plug(if_true, if_false); | 3433 context()->Plug(if_true, if_false); |
3325 return; | 3434 return; |
3326 } | 3435 } |
3327 | 3436 |
3328 VisitForStackValue(expr->left()); | 3437 VisitForStackValue(expr->left()); |
3329 switch (op) { | 3438 switch (op) { |
3330 case Token::IN: | 3439 case Token::IN: |
3331 VisitForStackValue(expr->right()); | 3440 VisitForStackValue(expr->right()); |
3332 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 3441 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 3442 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
3333 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 3443 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
3334 Split(equal, if_true, if_false, fall_through); | 3444 Split(equal, if_true, if_false, fall_through); |
3335 break; | 3445 break; |
3336 | 3446 |
3337 case Token::INSTANCEOF: { | 3447 case Token::INSTANCEOF: { |
3338 VisitForStackValue(expr->right()); | 3448 VisitForStackValue(expr->right()); |
3339 InstanceofStub stub(InstanceofStub::kNoFlags); | 3449 InstanceofStub stub(InstanceofStub::kNoFlags); |
3340 __ CallStub(&stub); | 3450 __ CallStub(&stub); |
| 3451 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3341 __ testq(rax, rax); | 3452 __ testq(rax, rax); |
3342 // The stub returns 0 for true. | 3453 // The stub returns 0 for true. |
3343 Split(zero, if_true, if_false, fall_through); | 3454 Split(zero, if_true, if_false, fall_through); |
3344 break; | 3455 break; |
3345 } | 3456 } |
3346 | 3457 |
3347 default: { | 3458 default: { |
3348 VisitForAccumulatorValue(expr->right()); | 3459 VisitForAccumulatorValue(expr->right()); |
3349 Condition cc = no_condition; | 3460 Condition cc = no_condition; |
3350 bool strict = false; | 3461 bool strict = false; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3389 __ SmiCompare(rdx, rax); | 3500 __ SmiCompare(rdx, rax); |
3390 Split(cc, if_true, if_false, NULL); | 3501 Split(cc, if_true, if_false, NULL); |
3391 __ bind(&slow_case); | 3502 __ bind(&slow_case); |
3392 } | 3503 } |
3393 | 3504 |
3394 CompareFlags flags = inline_smi_code | 3505 CompareFlags flags = inline_smi_code |
3395 ? NO_SMI_COMPARE_IN_STUB | 3506 ? NO_SMI_COMPARE_IN_STUB |
3396 : NO_COMPARE_FLAGS; | 3507 : NO_COMPARE_FLAGS; |
3397 CompareStub stub(cc, strict, flags); | 3508 CompareStub stub(cc, strict, flags); |
3398 __ CallStub(&stub); | 3509 __ CallStub(&stub); |
| 3510 |
| 3511 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3399 __ testq(rax, rax); | 3512 __ testq(rax, rax); |
3400 Split(cc, if_true, if_false, fall_through); | 3513 Split(cc, if_true, if_false, fall_through); |
3401 } | 3514 } |
3402 } | 3515 } |
3403 | 3516 |
3404 // Convert the result of the comparison into one expected for this | 3517 // Convert the result of the comparison into one expected for this |
3405 // expression's context. | 3518 // expression's context. |
3406 context()->Plug(if_true, if_false); | 3519 context()->Plug(if_true, if_false); |
3407 } | 3520 } |
3408 | 3521 |
3409 | 3522 |
3410 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { | 3523 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { |
3411 Comment cmnt(masm_, "[ CompareToNull"); | 3524 Comment cmnt(masm_, "[ CompareToNull"); |
3412 Label materialize_true, materialize_false; | 3525 Label materialize_true, materialize_false; |
3413 Label* if_true = NULL; | 3526 Label* if_true = NULL; |
3414 Label* if_false = NULL; | 3527 Label* if_false = NULL; |
3415 Label* fall_through = NULL; | 3528 Label* fall_through = NULL; |
3416 context()->PrepareTest(&materialize_true, &materialize_false, | 3529 context()->PrepareTest(&materialize_true, &materialize_false, |
3417 &if_true, &if_false, &fall_through); | 3530 &if_true, &if_false, &fall_through); |
3418 | 3531 |
3419 VisitForAccumulatorValue(expr->expression()); | 3532 VisitForAccumulatorValue(expr->expression()); |
| 3533 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3420 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 3534 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
3421 if (expr->is_strict()) { | 3535 if (expr->is_strict()) { |
3422 Split(equal, if_true, if_false, fall_through); | 3536 Split(equal, if_true, if_false, fall_through); |
3423 } else { | 3537 } else { |
3424 __ j(equal, if_true); | 3538 __ j(equal, if_true); |
3425 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 3539 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
3426 __ j(equal, if_true); | 3540 __ j(equal, if_true); |
3427 Condition is_smi = masm_->CheckSmi(rax); | 3541 Condition is_smi = masm_->CheckSmi(rax); |
3428 __ j(is_smi, if_false); | 3542 __ j(is_smi, if_false); |
3429 // It can be an undetectable object. | 3543 // It can be an undetectable object. |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3521 __ ret(0); | 3635 __ ret(0); |
3522 } | 3636 } |
3523 | 3637 |
3524 | 3638 |
3525 #undef __ | 3639 #undef __ |
3526 | 3640 |
3527 | 3641 |
3528 } } // namespace v8::internal | 3642 } } // namespace v8::internal |
3529 | 3643 |
3530 #endif // V8_TARGET_ARCH_X64 | 3644 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |