| 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 |