| 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 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 | 192 |
| 193 { Comment cmnt(masm_, "[ return <undefined>;"); | 193 { Comment cmnt(masm_, "[ return <undefined>;"); |
| 194 // Emit a 'return undefined' in case control fell off the end of the body. | 194 // Emit a 'return undefined' in case control fell off the end of the body. |
| 195 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 195 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 196 EmitReturnSequence(); | 196 EmitReturnSequence(); |
| 197 } | 197 } |
| 198 } | 198 } |
| 199 | 199 |
| 200 | 200 |
| 201 void FullCodeGenerator::ClearAccumulator() { | 201 void FullCodeGenerator::ClearAccumulator() { |
| 202 __ xor_(rax, rax); | 202 __ Set(rax, 0); |
| 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 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); | 692 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); |
| 664 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 693 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| 665 // Return value is ignored. | 694 // Return value is ignored. |
| 666 } | 695 } |
| 667 | 696 |
| 668 | 697 |
| 669 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 698 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
| 670 Comment cmnt(masm_, "[ SwitchStatement"); | 699 Comment cmnt(masm_, "[ SwitchStatement"); |
| 671 Breakable nested_statement(this, stmt); | 700 Breakable nested_statement(this, stmt); |
| 672 SetStatementPosition(stmt); | 701 SetStatementPosition(stmt); |
| 702 |
| 673 // Keep the switch value on the stack until a case matches. | 703 // Keep the switch value on the stack until a case matches. |
| 674 VisitForStackValue(stmt->tag()); | 704 VisitForStackValue(stmt->tag()); |
| 705 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
| 675 | 706 |
| 676 ZoneList<CaseClause*>* clauses = stmt->cases(); | 707 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 677 CaseClause* default_clause = NULL; // Can occur anywhere in the list. | 708 CaseClause* default_clause = NULL; // Can occur anywhere in the list. |
| 678 | 709 |
| 679 Label next_test; // Recycled for each test. | 710 Label next_test; // Recycled for each test. |
| 680 // Compile all the tests with branches to their bodies. | 711 // Compile all the tests with branches to their bodies. |
| 681 for (int i = 0; i < clauses->length(); i++) { | 712 for (int i = 0; i < clauses->length(); i++) { |
| 682 CaseClause* clause = clauses->at(i); | 713 CaseClause* clause = clauses->at(i); |
| 683 // The default is not a test, but remember it as final fall through. | 714 // The default is not a test, but remember it as final fall through. |
| 684 if (clause->is_default()) { | 715 if (clause->is_default()) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 729 | 760 |
| 730 // Compile all the case bodies. | 761 // Compile all the case bodies. |
| 731 for (int i = 0; i < clauses->length(); i++) { | 762 for (int i = 0; i < clauses->length(); i++) { |
| 732 Comment cmnt(masm_, "[ Case body"); | 763 Comment cmnt(masm_, "[ Case body"); |
| 733 CaseClause* clause = clauses->at(i); | 764 CaseClause* clause = clauses->at(i); |
| 734 __ bind(clause->body_target()->entry_label()); | 765 __ bind(clause->body_target()->entry_label()); |
| 735 VisitStatements(clause->statements()); | 766 VisitStatements(clause->statements()); |
| 736 } | 767 } |
| 737 | 768 |
| 738 __ bind(nested_statement.break_target()); | 769 __ bind(nested_statement.break_target()); |
| 770 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 739 } | 771 } |
| 740 | 772 |
| 741 | 773 |
| 742 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 774 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 743 Comment cmnt(masm_, "[ ForInStatement"); | 775 Comment cmnt(masm_, "[ ForInStatement"); |
| 744 SetStatementPosition(stmt); | 776 SetStatementPosition(stmt); |
| 745 | 777 |
| 746 Label loop, exit; | 778 Label loop, exit; |
| 747 ForIn loop_statement(this, stmt); | 779 ForIn loop_statement(this, stmt); |
| 748 increment_loop_depth(); | 780 increment_loop_depth(); |
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1225 // Fall through. | 1257 // Fall through. |
| 1226 case ObjectLiteral::Property::COMPUTED: | 1258 case ObjectLiteral::Property::COMPUTED: |
| 1227 if (key->handle()->IsSymbol()) { | 1259 if (key->handle()->IsSymbol()) { |
| 1228 VisitForAccumulatorValue(value); | 1260 VisitForAccumulatorValue(value); |
| 1229 __ Move(rcx, key->handle()); | 1261 __ Move(rcx, key->handle()); |
| 1230 __ movq(rdx, Operand(rsp, 0)); | 1262 __ movq(rdx, Operand(rsp, 0)); |
| 1231 if (property->emit_store()) { | 1263 if (property->emit_store()) { |
| 1232 Handle<Code> ic(isolate()->builtins()->builtin( | 1264 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1233 Builtins::StoreIC_Initialize)); | 1265 Builtins::StoreIC_Initialize)); |
| 1234 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1266 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1267 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1235 } | 1268 } |
| 1236 break; | 1269 break; |
| 1237 } | 1270 } |
| 1238 // Fall through. | 1271 // Fall through. |
| 1239 case ObjectLiteral::Property::PROTOTYPE: | 1272 case ObjectLiteral::Property::PROTOTYPE: |
| 1240 __ push(Operand(rsp, 0)); // Duplicate receiver. | 1273 __ push(Operand(rsp, 0)); // Duplicate receiver. |
| 1241 VisitForStackValue(key); | 1274 VisitForStackValue(key); |
| 1242 VisitForStackValue(value); | 1275 VisitForStackValue(value); |
| 1243 if (property->emit_store()) { | 1276 if (property->emit_store()) { |
| 1244 __ CallRuntime(Runtime::kSetProperty, 3); | 1277 __ CallRuntime(Runtime::kSetProperty, 3); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1313 VisitForAccumulatorValue(subexpr); | 1346 VisitForAccumulatorValue(subexpr); |
| 1314 | 1347 |
| 1315 // Store the subexpression value in the array's elements. | 1348 // Store the subexpression value in the array's elements. |
| 1316 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 1349 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. |
| 1317 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 1350 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
| 1318 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1351 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 1319 __ movq(FieldOperand(rbx, offset), result_register()); | 1352 __ movq(FieldOperand(rbx, offset), result_register()); |
| 1320 | 1353 |
| 1321 // Update the write barrier for the array store. | 1354 // Update the write barrier for the array store. |
| 1322 __ RecordWrite(rbx, offset, result_register(), rcx); | 1355 __ RecordWrite(rbx, offset, result_register(), rcx); |
| 1356 |
| 1357 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
| 1323 } | 1358 } |
| 1324 | 1359 |
| 1325 if (result_saved) { | 1360 if (result_saved) { |
| 1326 context()->PlugTOS(); | 1361 context()->PlugTOS(); |
| 1327 } else { | 1362 } else { |
| 1328 context()->Plug(rax); | 1363 context()->Plug(rax); |
| 1329 } | 1364 } |
| 1330 } | 1365 } |
| 1331 | 1366 |
| 1332 | 1367 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1357 break; | 1392 break; |
| 1358 case NAMED_PROPERTY: | 1393 case NAMED_PROPERTY: |
| 1359 if (expr->is_compound()) { | 1394 if (expr->is_compound()) { |
| 1360 // We need the receiver both on the stack and in the accumulator. | 1395 // We need the receiver both on the stack and in the accumulator. |
| 1361 VisitForAccumulatorValue(property->obj()); | 1396 VisitForAccumulatorValue(property->obj()); |
| 1362 __ push(result_register()); | 1397 __ push(result_register()); |
| 1363 } else { | 1398 } else { |
| 1364 VisitForStackValue(property->obj()); | 1399 VisitForStackValue(property->obj()); |
| 1365 } | 1400 } |
| 1366 break; | 1401 break; |
| 1367 case KEYED_PROPERTY: | 1402 case KEYED_PROPERTY: { |
| 1368 if (expr->is_compound()) { | 1403 if (expr->is_compound()) { |
| 1369 VisitForStackValue(property->obj()); | 1404 if (property->is_arguments_access()) { |
| 1370 VisitForAccumulatorValue(property->key()); | 1405 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1406 MemOperand slot_operand = |
| 1407 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); |
| 1408 __ push(slot_operand); |
| 1409 __ Move(rax, property->key()->AsLiteral()->handle()); |
| 1410 } else { |
| 1411 VisitForStackValue(property->obj()); |
| 1412 VisitForAccumulatorValue(property->key()); |
| 1413 } |
| 1371 __ movq(rdx, Operand(rsp, 0)); | 1414 __ movq(rdx, Operand(rsp, 0)); |
| 1372 __ push(rax); | 1415 __ push(rax); |
| 1373 } else { | 1416 } else { |
| 1374 VisitForStackValue(property->obj()); | 1417 if (property->is_arguments_access()) { |
| 1375 VisitForStackValue(property->key()); | 1418 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1419 MemOperand slot_operand = |
| 1420 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); |
| 1421 __ push(slot_operand); |
| 1422 __ Push(property->key()->AsLiteral()->handle()); |
| 1423 } else { |
| 1424 VisitForStackValue(property->obj()); |
| 1425 VisitForStackValue(property->key()); |
| 1426 } |
| 1376 } | 1427 } |
| 1377 break; | 1428 break; |
| 1429 } |
| 1378 } | 1430 } |
| 1379 | 1431 |
| 1380 if (expr->is_compound()) { | 1432 if (expr->is_compound()) { |
| 1381 { AccumulatorValueContext context(this); | 1433 { AccumulatorValueContext context(this); |
| 1382 switch (assign_type) { | 1434 switch (assign_type) { |
| 1383 case VARIABLE: | 1435 case VARIABLE: |
| 1384 EmitVariableLoad(expr->target()->AsVariableProxy()->var()); | 1436 EmitVariableLoad(expr->target()->AsVariableProxy()->var()); |
| 1385 break; | 1437 break; |
| 1386 case NAMED_PROPERTY: | 1438 case NAMED_PROPERTY: |
| 1387 EmitNamedPropertyLoad(property); | 1439 EmitNamedPropertyLoad(property); |
| 1388 break; | 1440 break; |
| 1389 case KEYED_PROPERTY: | 1441 case KEYED_PROPERTY: |
| 1390 EmitKeyedPropertyLoad(property); | 1442 EmitKeyedPropertyLoad(property); |
| 1391 break; | 1443 break; |
| 1392 } | 1444 } |
| 1393 } | 1445 } |
| 1394 | 1446 |
| 1447 // For property compound assignments we need another deoptimization |
| 1448 // point after the property load. |
| 1449 if (property != NULL) { |
| 1450 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); |
| 1451 } |
| 1452 |
| 1395 Token::Value op = expr->binary_op(); | 1453 Token::Value op = expr->binary_op(); |
| 1396 ConstantOperand constant = ShouldInlineSmiCase(op) | 1454 ConstantOperand constant = ShouldInlineSmiCase(op) |
| 1397 ? GetConstantOperand(op, expr->target(), expr->value()) | 1455 ? GetConstantOperand(op, expr->target(), expr->value()) |
| 1398 : kNoConstants; | 1456 : kNoConstants; |
| 1399 ASSERT(constant == kRightConstant || constant == kNoConstants); | 1457 ASSERT(constant == kRightConstant || constant == kNoConstants); |
| 1400 if (constant == kNoConstants) { | 1458 if (constant == kNoConstants) { |
| 1401 __ push(rax); // Left operand goes on the stack. | 1459 __ push(rax); // Left operand goes on the stack. |
| 1402 VisitForAccumulatorValue(expr->value()); | 1460 VisitForAccumulatorValue(expr->value()); |
| 1403 } | 1461 } |
| 1404 | 1462 |
| 1405 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() | 1463 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() |
| 1406 ? OVERWRITE_RIGHT | 1464 ? OVERWRITE_RIGHT |
| 1407 : NO_OVERWRITE; | 1465 : NO_OVERWRITE; |
| 1408 SetSourcePosition(expr->position() + 1); | 1466 SetSourcePosition(expr->position() + 1); |
| 1409 AccumulatorValueContext context(this); | 1467 AccumulatorValueContext context(this); |
| 1410 if (ShouldInlineSmiCase(op)) { | 1468 if (ShouldInlineSmiCase(op)) { |
| 1411 EmitInlineSmiBinaryOp(expr, | 1469 EmitInlineSmiBinaryOp(expr, |
| 1412 op, | 1470 op, |
| 1413 mode, | 1471 mode, |
| 1414 expr->target(), | 1472 expr->target(), |
| 1415 expr->value(), | 1473 expr->value(), |
| 1416 constant); | 1474 constant); |
| 1417 } else { | 1475 } else { |
| 1418 EmitBinaryOp(op, mode); | 1476 EmitBinaryOp(op, mode); |
| 1419 } | 1477 } |
| 1478 // Deoptimization point in case the binary operation may have side effects. |
| 1479 PrepareForBailout(expr->binary_operation(), TOS_REG); |
| 1420 } else { | 1480 } else { |
| 1421 VisitForAccumulatorValue(expr->value()); | 1481 VisitForAccumulatorValue(expr->value()); |
| 1422 } | 1482 } |
| 1423 | 1483 |
| 1424 // Record source position before possible IC call. | 1484 // Record source position before possible IC call. |
| 1425 SetSourcePosition(expr->position()); | 1485 SetSourcePosition(expr->position()); |
| 1426 | 1486 |
| 1427 // Store the value. | 1487 // Store the value. |
| 1428 switch (assign_type) { | 1488 switch (assign_type) { |
| 1429 case VARIABLE: | 1489 case VARIABLE: |
| 1430 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), | 1490 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), |
| 1431 expr->op()); | 1491 expr->op()); |
| 1492 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 1432 context()->Plug(rax); | 1493 context()->Plug(rax); |
| 1433 break; | 1494 break; |
| 1434 case NAMED_PROPERTY: | 1495 case NAMED_PROPERTY: |
| 1435 EmitNamedPropertyAssignment(expr); | 1496 EmitNamedPropertyAssignment(expr); |
| 1436 break; | 1497 break; |
| 1437 case KEYED_PROPERTY: | 1498 case KEYED_PROPERTY: |
| 1438 EmitKeyedPropertyAssignment(expr); | 1499 EmitKeyedPropertyAssignment(expr); |
| 1439 break; | 1500 break; |
| 1440 } | 1501 } |
| 1441 } | 1502 } |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1533 __ pop(rdx); | 1594 __ pop(rdx); |
| 1534 stub.GenerateCall(masm_, rdx, rax); | 1595 stub.GenerateCall(masm_, rdx, rax); |
| 1535 } else { | 1596 } else { |
| 1536 __ push(result_register()); | 1597 __ push(result_register()); |
| 1537 __ CallStub(&stub); | 1598 __ CallStub(&stub); |
| 1538 } | 1599 } |
| 1539 context()->Plug(rax); | 1600 context()->Plug(rax); |
| 1540 } | 1601 } |
| 1541 | 1602 |
| 1542 | 1603 |
| 1543 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_id) { | 1604 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
| 1544 // Invalid left-hand sides are rewritten to have a 'throw | 1605 // Invalid left-hand sides are rewritten to have a 'throw |
| 1545 // ReferenceError' on the left-hand side. | 1606 // ReferenceError' on the left-hand side. |
| 1546 if (!expr->IsValidLeftHandSide()) { | 1607 if (!expr->IsValidLeftHandSide()) { |
| 1547 VisitForEffect(expr); | 1608 VisitForEffect(expr); |
| 1548 return; | 1609 return; |
| 1549 } | 1610 } |
| 1550 | 1611 |
| 1551 // Left-hand side can only be a property, a global or a (parameter or local) | 1612 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1552 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1613 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
| 1553 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1614 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1583 VisitForAccumulatorValue(prop->key()); | 1644 VisitForAccumulatorValue(prop->key()); |
| 1584 __ movq(rcx, rax); | 1645 __ movq(rcx, rax); |
| 1585 __ pop(rdx); | 1646 __ pop(rdx); |
| 1586 __ pop(rax); | 1647 __ pop(rax); |
| 1587 Handle<Code> ic(isolate()->builtins()->builtin( | 1648 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1588 Builtins::KeyedStoreIC_Initialize)); | 1649 Builtins::KeyedStoreIC_Initialize)); |
| 1589 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1650 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1590 break; | 1651 break; |
| 1591 } | 1652 } |
| 1592 } | 1653 } |
| 1654 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 1593 context()->Plug(rax); | 1655 context()->Plug(rax); |
| 1594 } | 1656 } |
| 1595 | 1657 |
| 1596 | 1658 |
| 1597 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1659 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1598 Token::Value op) { | 1660 Token::Value op) { |
| 1599 // Left-hand sides that rewrite to explicit property accesses do not reach | 1661 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 1600 // here. | 1662 // here. |
| 1601 ASSERT(var != NULL); | 1663 ASSERT(var != NULL); |
| 1602 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1664 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1696 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1758 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1697 | 1759 |
| 1698 // If the assignment ends an initialization block, revert to fast case. | 1760 // If the assignment ends an initialization block, revert to fast case. |
| 1699 if (expr->ends_initialization_block()) { | 1761 if (expr->ends_initialization_block()) { |
| 1700 __ push(rax); // Result of assignment, saved even if not needed. | 1762 __ push(rax); // Result of assignment, saved even if not needed. |
| 1701 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1763 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. |
| 1702 __ CallRuntime(Runtime::kToFastProperties, 1); | 1764 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1703 __ pop(rax); | 1765 __ pop(rax); |
| 1704 __ Drop(1); | 1766 __ Drop(1); |
| 1705 } | 1767 } |
| 1768 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 1706 context()->Plug(rax); | 1769 context()->Plug(rax); |
| 1707 } | 1770 } |
| 1708 | 1771 |
| 1709 | 1772 |
| 1710 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 1773 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
| 1711 // Assignment to a property, using a keyed store IC. | 1774 // Assignment to a property, using a keyed store IC. |
| 1712 | 1775 |
| 1713 // If the assignment starts a block of assignments to the same object, | 1776 // If the assignment starts a block of assignments to the same object, |
| 1714 // change to slow case to avoid the quadratic behavior of repeatedly | 1777 // change to slow case to avoid the quadratic behavior of repeatedly |
| 1715 // adding fast properties. | 1778 // adding fast properties. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1735 | 1798 |
| 1736 // If the assignment ends an initialization block, revert to fast case. | 1799 // If the assignment ends an initialization block, revert to fast case. |
| 1737 if (expr->ends_initialization_block()) { | 1800 if (expr->ends_initialization_block()) { |
| 1738 __ pop(rdx); | 1801 __ pop(rdx); |
| 1739 __ push(rax); // Result of assignment, saved even if not needed. | 1802 __ push(rax); // Result of assignment, saved even if not needed. |
| 1740 __ push(rdx); | 1803 __ push(rdx); |
| 1741 __ CallRuntime(Runtime::kToFastProperties, 1); | 1804 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1742 __ pop(rax); | 1805 __ pop(rax); |
| 1743 } | 1806 } |
| 1744 | 1807 |
| 1808 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 1745 context()->Plug(rax); | 1809 context()->Plug(rax); |
| 1746 } | 1810 } |
| 1747 | 1811 |
| 1748 | 1812 |
| 1749 void FullCodeGenerator::VisitProperty(Property* expr) { | 1813 void FullCodeGenerator::VisitProperty(Property* expr) { |
| 1750 Comment cmnt(masm_, "[ Property"); | 1814 Comment cmnt(masm_, "[ Property"); |
| 1751 Expression* key = expr->key(); | 1815 Expression* key = expr->key(); |
| 1752 | 1816 |
| 1753 if (key->IsPropertyName()) { | 1817 if (key->IsPropertyName()) { |
| 1754 VisitForAccumulatorValue(expr->obj()); | 1818 VisitForAccumulatorValue(expr->obj()); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1776 } | 1840 } |
| 1777 __ Move(rcx, name); | 1841 __ Move(rcx, name); |
| 1778 } | 1842 } |
| 1779 // Record source position for debugger. | 1843 // Record source position for debugger. |
| 1780 SetSourcePosition(expr->position()); | 1844 SetSourcePosition(expr->position()); |
| 1781 // Call the IC initialization code. | 1845 // Call the IC initialization code. |
| 1782 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1846 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1783 Handle<Code> ic = | 1847 Handle<Code> ic = |
| 1784 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop); | 1848 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop); |
| 1785 EmitCallIC(ic, mode); | 1849 EmitCallIC(ic, mode); |
| 1850 RecordJSReturnSite(expr); |
| 1786 // Restore context register. | 1851 // Restore context register. |
| 1787 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1852 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1788 context()->Plug(rax); | 1853 context()->Plug(rax); |
| 1789 } | 1854 } |
| 1790 | 1855 |
| 1791 | 1856 |
| 1792 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 1857 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 1793 Expression* key, | 1858 Expression* key, |
| 1794 RelocInfo::Mode mode) { | 1859 RelocInfo::Mode mode) { |
| 1795 // Load the key. | 1860 // Load the key. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1810 } | 1875 } |
| 1811 } | 1876 } |
| 1812 // Record source position for debugger. | 1877 // Record source position for debugger. |
| 1813 SetSourcePosition(expr->position()); | 1878 SetSourcePosition(expr->position()); |
| 1814 // Call the IC initialization code. | 1879 // Call the IC initialization code. |
| 1815 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1880 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1816 Handle<Code> ic = | 1881 Handle<Code> ic = |
| 1817 ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop); | 1882 ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop); |
| 1818 __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key. | 1883 __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key. |
| 1819 EmitCallIC(ic, mode); | 1884 EmitCallIC(ic, mode); |
| 1885 RecordJSReturnSite(expr); |
| 1820 // Restore context register. | 1886 // Restore context register. |
| 1821 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1887 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1822 context()->DropAndPlug(1, rax); // Drop the key still on the stack. | 1888 context()->DropAndPlug(1, rax); // Drop the key still on the stack. |
| 1823 } | 1889 } |
| 1824 | 1890 |
| 1825 | 1891 |
| 1826 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 1892 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
| 1827 // Code common for calls using the call stub. | 1893 // Code common for calls using the call stub. |
| 1828 ZoneList<Expression*>* args = expr->arguments(); | 1894 ZoneList<Expression*>* args = expr->arguments(); |
| 1829 int arg_count = args->length(); | 1895 int arg_count = args->length(); |
| 1830 { PreservePositionScope scope(masm()->positions_recorder()); | 1896 { PreservePositionScope scope(masm()->positions_recorder()); |
| 1831 for (int i = 0; i < arg_count; i++) { | 1897 for (int i = 0; i < arg_count; i++) { |
| 1832 VisitForStackValue(args->at(i)); | 1898 VisitForStackValue(args->at(i)); |
| 1833 } | 1899 } |
| 1834 } | 1900 } |
| 1835 // Record source position for debugger. | 1901 // Record source position for debugger. |
| 1836 SetSourcePosition(expr->position()); | 1902 SetSourcePosition(expr->position()); |
| 1837 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1903 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1838 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 1904 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| 1839 __ CallStub(&stub); | 1905 __ CallStub(&stub); |
| 1906 RecordJSReturnSite(expr); |
| 1840 // Restore context register. | 1907 // Restore context register. |
| 1841 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1908 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1842 // Discard the function left on TOS. | 1909 // Discard the function left on TOS. |
| 1843 context()->DropAndPlug(1, rax); | 1910 context()->DropAndPlug(1, rax); |
| 1844 } | 1911 } |
| 1845 | 1912 |
| 1846 | 1913 |
| 1847 void FullCodeGenerator::VisitCall(Call* expr) { | 1914 void FullCodeGenerator::VisitCall(Call* expr) { |
| 1915 #ifdef DEBUG |
| 1916 // We want to verify that RecordJSReturnSite gets called on all paths |
| 1917 // through this function. Avoid early returns. |
| 1918 expr->return_is_recorded_ = false; |
| 1919 #endif |
| 1920 |
| 1848 Comment cmnt(masm_, "[ Call"); | 1921 Comment cmnt(masm_, "[ Call"); |
| 1849 Expression* fun = expr->expression(); | 1922 Expression* fun = expr->expression(); |
| 1850 Variable* var = fun->AsVariableProxy()->AsVariable(); | 1923 Variable* var = fun->AsVariableProxy()->AsVariable(); |
| 1851 | 1924 |
| 1852 if (var != NULL && var->is_possibly_eval()) { | 1925 if (var != NULL && var->is_possibly_eval()) { |
| 1853 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 1926 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
| 1854 // resolve the function we need to call and the receiver of the | 1927 // resolve the function we need to call and the receiver of the |
| 1855 // call. The we call the resolved function using the given | 1928 // call. Then we call the resolved function using the given |
| 1856 // arguments. | 1929 // arguments. |
| 1857 ZoneList<Expression*>* args = expr->arguments(); | 1930 ZoneList<Expression*>* args = expr->arguments(); |
| 1858 int arg_count = args->length(); | 1931 int arg_count = args->length(); |
| 1859 { PreservePositionScope pos_scope(masm()->positions_recorder()); | 1932 { PreservePositionScope pos_scope(masm()->positions_recorder()); |
| 1860 VisitForStackValue(fun); | 1933 VisitForStackValue(fun); |
| 1861 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. | 1934 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. |
| 1862 | 1935 |
| 1863 // Push the arguments. | 1936 // Push the arguments. |
| 1864 for (int i = 0; i < arg_count; i++) { | 1937 for (int i = 0; i < arg_count; i++) { |
| 1865 VisitForStackValue(args->at(i)); | 1938 VisitForStackValue(args->at(i)); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1882 // The runtime call returns a pair of values in rax (function) and | 1955 // The runtime call returns a pair of values in rax (function) and |
| 1883 // rdx (receiver). Touch up the stack with the right values. | 1956 // rdx (receiver). Touch up the stack with the right values. |
| 1884 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx); | 1957 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx); |
| 1885 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax); | 1958 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax); |
| 1886 } | 1959 } |
| 1887 // Record source position for debugger. | 1960 // Record source position for debugger. |
| 1888 SetSourcePosition(expr->position()); | 1961 SetSourcePosition(expr->position()); |
| 1889 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1962 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1890 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 1963 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| 1891 __ CallStub(&stub); | 1964 __ CallStub(&stub); |
| 1965 RecordJSReturnSite(expr); |
| 1892 // Restore context register. | 1966 // Restore context register. |
| 1893 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1967 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1894 context()->DropAndPlug(1, rax); | 1968 context()->DropAndPlug(1, rax); |
| 1895 } else if (var != NULL && !var->is_this() && var->is_global()) { | 1969 } else if (var != NULL && !var->is_this() && var->is_global()) { |
| 1896 // Call to a global variable. | 1970 // Call to a global variable. |
| 1897 // Push global object as receiver for the call IC lookup. | 1971 // Push global object as receiver for the call IC lookup. |
| 1898 __ push(GlobalObjectOperand()); | 1972 __ push(GlobalObjectOperand()); |
| 1899 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); | 1973 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); |
| 1900 } else if (var != NULL && var->AsSlot() != NULL && | 1974 } else if (var != NULL && var->AsSlot() != NULL && |
| 1901 var->AsSlot()->type() == Slot::LOOKUP) { | 1975 var->AsSlot()->type() == Slot::LOOKUP) { |
| 1902 // Call to a lookup slot (dynamically introduced variable). | 1976 // Call to a lookup slot (dynamically introduced variable). |
| 1903 Label slow, done; | 1977 Label slow, done; |
| 1904 | 1978 |
| 1905 { PreservePositionScope scope(masm()->positions_recorder()); | 1979 { PreservePositionScope scope(masm()->positions_recorder()); |
| 1906 // Generate code for loading from variables potentially shadowed | 1980 // Generate code for loading from variables potentially shadowed |
| 1907 // by eval-introduced variables. | 1981 // by eval-introduced variables. |
| 1908 EmitDynamicLoadFromSlotFastCase(var->AsSlot(), | 1982 EmitDynamicLoadFromSlotFastCase(var->AsSlot(), |
| 1909 NOT_INSIDE_TYPEOF, | 1983 NOT_INSIDE_TYPEOF, |
| 1910 &slow, | 1984 &slow, |
| 1911 &done); | 1985 &done); |
| 1912 | 1986 |
| 1913 __ bind(&slow); | 1987 __ bind(&slow); |
| 1914 // Call the runtime to find the function to call (returned in rax) | 1988 } |
| 1915 // and the object holding it (returned in rdx). | 1989 // Call the runtime to find the function to call (returned in rax) |
| 1916 __ push(context_register()); | 1990 // and the object holding it (returned in rdx). |
| 1917 __ Push(var->name()); | 1991 __ push(context_register()); |
| 1918 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1992 __ Push(var->name()); |
| 1919 __ push(rax); // Function. | 1993 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1920 __ push(rdx); // Receiver. | 1994 __ push(rax); // Function. |
| 1995 __ push(rdx); // Receiver. |
| 1921 | 1996 |
| 1922 // If fast case code has been generated, emit code to push the | 1997 // If fast case code has been generated, emit code to push the |
| 1923 // function and receiver and have the slow path jump around this | 1998 // function and receiver and have the slow path jump around this |
| 1924 // code. | 1999 // code. |
| 1925 if (done.is_linked()) { | 2000 if (done.is_linked()) { |
| 1926 NearLabel call; | 2001 NearLabel call; |
| 1927 __ jmp(&call); | 2002 __ jmp(&call); |
| 1928 __ bind(&done); | 2003 __ bind(&done); |
| 1929 // Push function. | 2004 // Push function. |
| 1930 __ push(rax); | 2005 __ push(rax); |
| 1931 // Push global receiver. | 2006 // Push global receiver. |
| 1932 __ movq(rbx, GlobalObjectOperand()); | 2007 __ movq(rbx, GlobalObjectOperand()); |
| 1933 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); | 2008 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); |
| 1934 __ bind(&call); | 2009 __ bind(&call); |
| 1935 } | |
| 1936 } | 2010 } |
| 1937 | 2011 |
| 1938 EmitCallWithStub(expr); | 2012 EmitCallWithStub(expr); |
| 1939 | |
| 1940 } else if (fun->AsProperty() != NULL) { | 2013 } else if (fun->AsProperty() != NULL) { |
| 1941 // Call to an object property. | 2014 // Call to an object property. |
| 1942 Property* prop = fun->AsProperty(); | 2015 Property* prop = fun->AsProperty(); |
| 1943 Literal* key = prop->key()->AsLiteral(); | 2016 Literal* key = prop->key()->AsLiteral(); |
| 1944 if (key != NULL && key->handle()->IsSymbol()) { | 2017 if (key != NULL && key->handle()->IsSymbol()) { |
| 1945 // Call to a named property, use call IC. | 2018 // Call to a named property, use call IC. |
| 1946 { PreservePositionScope scope(masm()->positions_recorder()); | 2019 { PreservePositionScope scope(masm()->positions_recorder()); |
| 1947 VisitForStackValue(prop->obj()); | 2020 VisitForStackValue(prop->obj()); |
| 1948 } | 2021 } |
| 1949 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2022 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 1950 } else { | 2023 } else { |
| 1951 // Call to a keyed property. | 2024 // Call to a keyed property. |
| 1952 // For a synthetic property use keyed load IC followed by function call, | 2025 // For a synthetic property use keyed load IC followed by function call, |
| 1953 // for a regular property use KeyedCallIC. | 2026 // for a regular property use keyed EmitCallIC. |
| 1954 { PreservePositionScope scope(masm()->positions_recorder()); | 2027 { PreservePositionScope scope(masm()->positions_recorder()); |
| 1955 VisitForStackValue(prop->obj()); | 2028 VisitForStackValue(prop->obj()); |
| 1956 } | 2029 } |
| 1957 if (prop->is_synthetic()) { | 2030 if (prop->is_synthetic()) { |
| 1958 { PreservePositionScope scope(masm()->positions_recorder()); | 2031 { PreservePositionScope scope(masm()->positions_recorder()); |
| 1959 VisitForAccumulatorValue(prop->key()); | 2032 VisitForAccumulatorValue(prop->key()); |
| 1960 __ movq(rdx, Operand(rsp, 0)); | |
| 1961 } | 2033 } |
| 1962 // Record source code position for IC call. | 2034 // Record source code position for IC call. |
| 1963 SetSourcePosition(prop->position()); | 2035 SetSourcePosition(prop->position()); |
| 2036 __ pop(rdx); // We do not need to keep the receiver. |
| 2037 |
| 1964 Handle<Code> ic(isolate()->builtins()->builtin( | 2038 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1965 Builtins::KeyedLoadIC_Initialize)); | 2039 Builtins::KeyedLoadIC_Initialize)); |
| 1966 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 2040 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1967 // Pop receiver. | |
| 1968 __ pop(rbx); | |
| 1969 // Push result (function). | 2041 // Push result (function). |
| 1970 __ push(rax); | 2042 __ push(rax); |
| 1971 // Push receiver object on stack. | 2043 // Push Global receiver. |
| 1972 __ movq(rcx, GlobalObjectOperand()); | 2044 __ movq(rcx, GlobalObjectOperand()); |
| 1973 __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); | 2045 __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); |
| 1974 EmitCallWithStub(expr); | 2046 EmitCallWithStub(expr); |
| 1975 } else { | 2047 } else { |
| 1976 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); | 2048 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); |
| 1977 } | 2049 } |
| 1978 } | 2050 } |
| 1979 } else { | 2051 } else { |
| 1980 // Call to some other expression. If the expression is an anonymous | 2052 // Call to some other expression. If the expression is an anonymous |
| 1981 // function literal not called in a loop, mark it as one that should | 2053 // function literal not called in a loop, mark it as one that should |
| 1982 // also use the fast code generator. | 2054 // also use the full code generator. |
| 1983 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 2055 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
| 1984 if (lit != NULL && | 2056 if (lit != NULL && |
| 1985 lit->name()->Equals(isolate()->heap()->empty_string()) && | 2057 lit->name()->Equals(isolate()->heap()->empty_string()) && |
| 1986 loop_depth() == 0) { | 2058 loop_depth() == 0) { |
| 1987 lit->set_try_full_codegen(true); | 2059 lit->set_try_full_codegen(true); |
| 1988 } | 2060 } |
| 1989 { PreservePositionScope scope(masm()->positions_recorder()); | 2061 { PreservePositionScope scope(masm()->positions_recorder()); |
| 1990 VisitForStackValue(fun); | 2062 VisitForStackValue(fun); |
| 1991 } | 2063 } |
| 1992 // Load global receiver object. | 2064 // Load global receiver object. |
| 1993 __ movq(rbx, GlobalObjectOperand()); | 2065 __ movq(rbx, GlobalObjectOperand()); |
| 1994 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); | 2066 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); |
| 1995 // Emit function call. | 2067 // Emit function call. |
| 1996 EmitCallWithStub(expr); | 2068 EmitCallWithStub(expr); |
| 1997 } | 2069 } |
| 2070 |
| 2071 #ifdef DEBUG |
| 2072 // RecordJSReturnSite should have been called. |
| 2073 ASSERT(expr->return_is_recorded_); |
| 2074 #endif |
| 1998 } | 2075 } |
| 1999 | 2076 |
| 2000 | 2077 |
| 2001 void FullCodeGenerator::VisitCallNew(CallNew* expr) { | 2078 void FullCodeGenerator::VisitCallNew(CallNew* expr) { |
| 2002 Comment cmnt(masm_, "[ CallNew"); | 2079 Comment cmnt(masm_, "[ CallNew"); |
| 2003 // According to ECMA-262, section 11.2.2, page 44, the function | 2080 // According to ECMA-262, section 11.2.2, page 44, the function |
| 2004 // expression in new calls must be evaluated before the | 2081 // expression in new calls must be evaluated before the |
| 2005 // arguments. | 2082 // arguments. |
| 2006 | 2083 |
| 2007 // Push constructor on the stack. If it's not a function it's used as | 2084 // Push constructor on the stack. If it's not a function it's used as |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2036 | 2113 |
| 2037 VisitForAccumulatorValue(args->at(0)); | 2114 VisitForAccumulatorValue(args->at(0)); |
| 2038 | 2115 |
| 2039 Label materialize_true, materialize_false; | 2116 Label materialize_true, materialize_false; |
| 2040 Label* if_true = NULL; | 2117 Label* if_true = NULL; |
| 2041 Label* if_false = NULL; | 2118 Label* if_false = NULL; |
| 2042 Label* fall_through = NULL; | 2119 Label* fall_through = NULL; |
| 2043 context()->PrepareTest(&materialize_true, &materialize_false, | 2120 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2044 &if_true, &if_false, &fall_through); | 2121 &if_true, &if_false, &fall_through); |
| 2045 | 2122 |
| 2123 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2046 __ JumpIfSmi(rax, if_true); | 2124 __ JumpIfSmi(rax, if_true); |
| 2047 __ jmp(if_false); | 2125 __ jmp(if_false); |
| 2048 | 2126 |
| 2049 context()->Plug(if_true, if_false); | 2127 context()->Plug(if_true, if_false); |
| 2050 } | 2128 } |
| 2051 | 2129 |
| 2052 | 2130 |
| 2053 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { | 2131 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 2054 ASSERT(args->length() == 1); | 2132 ASSERT(args->length() == 1); |
| 2055 | 2133 |
| 2056 VisitForAccumulatorValue(args->at(0)); | 2134 VisitForAccumulatorValue(args->at(0)); |
| 2057 | 2135 |
| 2058 Label materialize_true, materialize_false; | 2136 Label materialize_true, materialize_false; |
| 2059 Label* if_true = NULL; | 2137 Label* if_true = NULL; |
| 2060 Label* if_false = NULL; | 2138 Label* if_false = NULL; |
| 2061 Label* fall_through = NULL; | 2139 Label* fall_through = NULL; |
| 2062 context()->PrepareTest(&materialize_true, &materialize_false, | 2140 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2063 &if_true, &if_false, &fall_through); | 2141 &if_true, &if_false, &fall_through); |
| 2064 | 2142 |
| 2143 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2065 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax); | 2144 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax); |
| 2066 Split(non_negative_smi, if_true, if_false, fall_through); | 2145 Split(non_negative_smi, if_true, if_false, fall_through); |
| 2067 | 2146 |
| 2068 context()->Plug(if_true, if_false); | 2147 context()->Plug(if_true, if_false); |
| 2069 } | 2148 } |
| 2070 | 2149 |
| 2071 | 2150 |
| 2072 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { | 2151 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { |
| 2073 ASSERT(args->length() == 1); | 2152 ASSERT(args->length() == 1); |
| 2074 | 2153 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2086 __ j(equal, if_true); | 2165 __ j(equal, if_true); |
| 2087 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 2166 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 2088 // Undetectable objects behave like undefined when tested with typeof. | 2167 // Undetectable objects behave like undefined when tested with typeof. |
| 2089 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2168 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 2090 Immediate(1 << Map::kIsUndetectable)); | 2169 Immediate(1 << Map::kIsUndetectable)); |
| 2091 __ j(not_zero, if_false); | 2170 __ j(not_zero, if_false); |
| 2092 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 2171 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 2093 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE)); | 2172 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE)); |
| 2094 __ j(below, if_false); | 2173 __ j(below, if_false); |
| 2095 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE)); | 2174 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE)); |
| 2175 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2096 Split(below_equal, if_true, if_false, fall_through); | 2176 Split(below_equal, if_true, if_false, fall_through); |
| 2097 | 2177 |
| 2098 context()->Plug(if_true, if_false); | 2178 context()->Plug(if_true, if_false); |
| 2099 } | 2179 } |
| 2100 | 2180 |
| 2101 | 2181 |
| 2102 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { | 2182 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { |
| 2103 ASSERT(args->length() == 1); | 2183 ASSERT(args->length() == 1); |
| 2104 | 2184 |
| 2105 VisitForAccumulatorValue(args->at(0)); | 2185 VisitForAccumulatorValue(args->at(0)); |
| 2106 | 2186 |
| 2107 Label materialize_true, materialize_false; | 2187 Label materialize_true, materialize_false; |
| 2108 Label* if_true = NULL; | 2188 Label* if_true = NULL; |
| 2109 Label* if_false = NULL; | 2189 Label* if_false = NULL; |
| 2110 Label* fall_through = NULL; | 2190 Label* fall_through = NULL; |
| 2111 context()->PrepareTest(&materialize_true, &materialize_false, | 2191 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2112 &if_true, &if_false, &fall_through); | 2192 &if_true, &if_false, &fall_through); |
| 2113 | 2193 |
| 2114 __ JumpIfSmi(rax, if_false); | 2194 __ JumpIfSmi(rax, if_false); |
| 2115 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | 2195 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); |
| 2196 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2116 Split(above_equal, if_true, if_false, fall_through); | 2197 Split(above_equal, if_true, if_false, fall_through); |
| 2117 | 2198 |
| 2118 context()->Plug(if_true, if_false); | 2199 context()->Plug(if_true, if_false); |
| 2119 } | 2200 } |
| 2120 | 2201 |
| 2121 | 2202 |
| 2122 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { | 2203 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { |
| 2123 ASSERT(args->length() == 1); | 2204 ASSERT(args->length() == 1); |
| 2124 | 2205 |
| 2125 VisitForAccumulatorValue(args->at(0)); | 2206 VisitForAccumulatorValue(args->at(0)); |
| 2126 | 2207 |
| 2127 Label materialize_true, materialize_false; | 2208 Label materialize_true, materialize_false; |
| 2128 Label* if_true = NULL; | 2209 Label* if_true = NULL; |
| 2129 Label* if_false = NULL; | 2210 Label* if_false = NULL; |
| 2130 Label* fall_through = NULL; | 2211 Label* fall_through = NULL; |
| 2131 context()->PrepareTest(&materialize_true, &materialize_false, | 2212 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2132 &if_true, &if_false, &fall_through); | 2213 &if_true, &if_false, &fall_through); |
| 2133 | 2214 |
| 2134 __ JumpIfSmi(rax, if_false); | 2215 __ JumpIfSmi(rax, if_false); |
| 2135 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 2216 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 2136 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2217 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 2137 Immediate(1 << Map::kIsUndetectable)); | 2218 Immediate(1 << Map::kIsUndetectable)); |
| 2219 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2138 Split(not_zero, if_true, if_false, fall_through); | 2220 Split(not_zero, if_true, if_false, fall_through); |
| 2139 | 2221 |
| 2140 context()->Plug(if_true, if_false); | 2222 context()->Plug(if_true, if_false); |
| 2141 } | 2223 } |
| 2142 | 2224 |
| 2143 | 2225 |
| 2144 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( | 2226 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( |
| 2145 ZoneList<Expression*>* args) { | 2227 ZoneList<Expression*>* args) { |
| 2146 ASSERT(args->length() == 1); | 2228 ASSERT(args->length() == 1); |
| 2147 | 2229 |
| 2148 VisitForAccumulatorValue(args->at(0)); | 2230 VisitForAccumulatorValue(args->at(0)); |
| 2149 | 2231 |
| 2150 Label materialize_true, materialize_false; | 2232 Label materialize_true, materialize_false; |
| 2151 Label* if_true = NULL; | 2233 Label* if_true = NULL; |
| 2152 Label* if_false = NULL; | 2234 Label* if_false = NULL; |
| 2153 Label* fall_through = NULL; | 2235 Label* fall_through = NULL; |
| 2154 context()->PrepareTest(&materialize_true, &materialize_false, | 2236 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2155 &if_true, &if_false, &fall_through); | 2237 &if_true, &if_false, &fall_through); |
| 2156 | 2238 |
| 2157 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only | 2239 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only |
| 2158 // used in a few functions in runtime.js which should not normally be hit by | 2240 // used in a few functions in runtime.js which should not normally be hit by |
| 2159 // this compiler. | 2241 // this compiler. |
| 2242 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2160 __ jmp(if_false); | 2243 __ jmp(if_false); |
| 2161 context()->Plug(if_true, if_false); | 2244 context()->Plug(if_true, if_false); |
| 2162 } | 2245 } |
| 2163 | 2246 |
| 2164 | 2247 |
| 2165 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { | 2248 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { |
| 2166 ASSERT(args->length() == 1); | 2249 ASSERT(args->length() == 1); |
| 2167 | 2250 |
| 2168 VisitForAccumulatorValue(args->at(0)); | 2251 VisitForAccumulatorValue(args->at(0)); |
| 2169 | 2252 |
| 2170 Label materialize_true, materialize_false; | 2253 Label materialize_true, materialize_false; |
| 2171 Label* if_true = NULL; | 2254 Label* if_true = NULL; |
| 2172 Label* if_false = NULL; | 2255 Label* if_false = NULL; |
| 2173 Label* fall_through = NULL; | 2256 Label* fall_through = NULL; |
| 2174 context()->PrepareTest(&materialize_true, &materialize_false, | 2257 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2175 &if_true, &if_false, &fall_through); | 2258 &if_true, &if_false, &fall_through); |
| 2176 | 2259 |
| 2177 __ JumpIfSmi(rax, if_false); | 2260 __ JumpIfSmi(rax, if_false); |
| 2178 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); | 2261 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); |
| 2262 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2179 Split(equal, if_true, if_false, fall_through); | 2263 Split(equal, if_true, if_false, fall_through); |
| 2180 | 2264 |
| 2181 context()->Plug(if_true, if_false); | 2265 context()->Plug(if_true, if_false); |
| 2182 } | 2266 } |
| 2183 | 2267 |
| 2184 | 2268 |
| 2185 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { | 2269 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { |
| 2186 ASSERT(args->length() == 1); | 2270 ASSERT(args->length() == 1); |
| 2187 | 2271 |
| 2188 VisitForAccumulatorValue(args->at(0)); | 2272 VisitForAccumulatorValue(args->at(0)); |
| 2189 | 2273 |
| 2190 Label materialize_true, materialize_false; | 2274 Label materialize_true, materialize_false; |
| 2191 Label* if_true = NULL; | 2275 Label* if_true = NULL; |
| 2192 Label* if_false = NULL; | 2276 Label* if_false = NULL; |
| 2193 Label* fall_through = NULL; | 2277 Label* fall_through = NULL; |
| 2194 context()->PrepareTest(&materialize_true, &materialize_false, | 2278 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2195 &if_true, &if_false, &fall_through); | 2279 &if_true, &if_false, &fall_through); |
| 2196 | 2280 |
| 2197 __ JumpIfSmi(rax, if_false); | 2281 __ JumpIfSmi(rax, if_false); |
| 2198 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx); | 2282 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx); |
| 2283 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2199 Split(equal, if_true, if_false, fall_through); | 2284 Split(equal, if_true, if_false, fall_through); |
| 2200 | 2285 |
| 2201 context()->Plug(if_true, if_false); | 2286 context()->Plug(if_true, if_false); |
| 2202 } | 2287 } |
| 2203 | 2288 |
| 2204 | 2289 |
| 2205 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { | 2290 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { |
| 2206 ASSERT(args->length() == 1); | 2291 ASSERT(args->length() == 1); |
| 2207 | 2292 |
| 2208 VisitForAccumulatorValue(args->at(0)); | 2293 VisitForAccumulatorValue(args->at(0)); |
| 2209 | 2294 |
| 2210 Label materialize_true, materialize_false; | 2295 Label materialize_true, materialize_false; |
| 2211 Label* if_true = NULL; | 2296 Label* if_true = NULL; |
| 2212 Label* if_false = NULL; | 2297 Label* if_false = NULL; |
| 2213 Label* fall_through = NULL; | 2298 Label* fall_through = NULL; |
| 2214 context()->PrepareTest(&materialize_true, &materialize_false, | 2299 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2215 &if_true, &if_false, &fall_through); | 2300 &if_true, &if_false, &fall_through); |
| 2216 | 2301 |
| 2217 __ JumpIfSmi(rax, if_false); | 2302 __ JumpIfSmi(rax, if_false); |
| 2218 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx); | 2303 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx); |
| 2304 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2219 Split(equal, if_true, if_false, fall_through); | 2305 Split(equal, if_true, if_false, fall_through); |
| 2220 | 2306 |
| 2221 context()->Plug(if_true, if_false); | 2307 context()->Plug(if_true, if_false); |
| 2222 } | 2308 } |
| 2223 | 2309 |
| 2224 | 2310 |
| 2225 | 2311 |
| 2226 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { | 2312 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { |
| 2227 ASSERT(args->length() == 0); | 2313 ASSERT(args->length() == 0); |
| 2228 | 2314 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2240 Label check_frame_marker; | 2326 Label check_frame_marker; |
| 2241 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), | 2327 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), |
| 2242 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2328 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2243 __ j(not_equal, &check_frame_marker); | 2329 __ j(not_equal, &check_frame_marker); |
| 2244 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); | 2330 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); |
| 2245 | 2331 |
| 2246 // Check the marker in the calling frame. | 2332 // Check the marker in the calling frame. |
| 2247 __ bind(&check_frame_marker); | 2333 __ bind(&check_frame_marker); |
| 2248 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), | 2334 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), |
| 2249 Smi::FromInt(StackFrame::CONSTRUCT)); | 2335 Smi::FromInt(StackFrame::CONSTRUCT)); |
| 2336 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2250 Split(equal, if_true, if_false, fall_through); | 2337 Split(equal, if_true, if_false, fall_through); |
| 2251 | 2338 |
| 2252 context()->Plug(if_true, if_false); | 2339 context()->Plug(if_true, if_false); |
| 2253 } | 2340 } |
| 2254 | 2341 |
| 2255 | 2342 |
| 2256 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { | 2343 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { |
| 2257 ASSERT(args->length() == 2); | 2344 ASSERT(args->length() == 2); |
| 2258 | 2345 |
| 2259 // Load the two objects into registers and perform the comparison. | 2346 // Load the two objects into registers and perform the comparison. |
| 2260 VisitForStackValue(args->at(0)); | 2347 VisitForStackValue(args->at(0)); |
| 2261 VisitForAccumulatorValue(args->at(1)); | 2348 VisitForAccumulatorValue(args->at(1)); |
| 2262 | 2349 |
| 2263 Label materialize_true, materialize_false; | 2350 Label materialize_true, materialize_false; |
| 2264 Label* if_true = NULL; | 2351 Label* if_true = NULL; |
| 2265 Label* if_false = NULL; | 2352 Label* if_false = NULL; |
| 2266 Label* fall_through = NULL; | 2353 Label* fall_through = NULL; |
| 2267 context()->PrepareTest(&materialize_true, &materialize_false, | 2354 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2268 &if_true, &if_false, &fall_through); | 2355 &if_true, &if_false, &fall_through); |
| 2269 | 2356 |
| 2270 __ pop(rbx); | 2357 __ pop(rbx); |
| 2271 __ cmpq(rax, rbx); | 2358 __ cmpq(rax, rbx); |
| 2359 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2272 Split(equal, if_true, if_false, fall_through); | 2360 Split(equal, if_true, if_false, fall_through); |
| 2273 | 2361 |
| 2274 context()->Plug(if_true, if_false); | 2362 context()->Plug(if_true, if_false); |
| 2275 } | 2363 } |
| 2276 | 2364 |
| 2277 | 2365 |
| 2278 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2366 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
| 2279 ASSERT(args->length() == 1); | 2367 ASSERT(args->length() == 1); |
| 2280 | 2368 |
| 2281 // ArgumentsAccessStub expects the key in rdx and the formal | 2369 // ArgumentsAccessStub expects the key in rdx and the formal |
| (...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2835 | 2923 |
| 2836 Label materialize_true, materialize_false; | 2924 Label materialize_true, materialize_false; |
| 2837 Label* if_true = NULL; | 2925 Label* if_true = NULL; |
| 2838 Label* if_false = NULL; | 2926 Label* if_false = NULL; |
| 2839 Label* fall_through = NULL; | 2927 Label* fall_through = NULL; |
| 2840 context()->PrepareTest(&materialize_true, &materialize_false, | 2928 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2841 &if_true, &if_false, &fall_through); | 2929 &if_true, &if_false, &fall_through); |
| 2842 | 2930 |
| 2843 __ testl(FieldOperand(rax, String::kHashFieldOffset), | 2931 __ testl(FieldOperand(rax, String::kHashFieldOffset), |
| 2844 Immediate(String::kContainsCachedArrayIndexMask)); | 2932 Immediate(String::kContainsCachedArrayIndexMask)); |
| 2933 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2845 __ j(zero, if_true); | 2934 __ j(zero, if_true); |
| 2846 __ jmp(if_false); | 2935 __ jmp(if_false); |
| 2847 | 2936 |
| 2848 context()->Plug(if_true, if_false); | 2937 context()->Plug(if_true, if_false); |
| 2849 } | 2938 } |
| 2850 | 2939 |
| 2851 | 2940 |
| 2852 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { | 2941 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { |
| 2853 ASSERT(args->length() == 1); | 2942 ASSERT(args->length() == 1); |
| 2854 | 2943 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2957 | 3046 |
| 2958 case Token::NOT: { | 3047 case Token::NOT: { |
| 2959 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 3048 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
| 2960 Label materialize_true, materialize_false; | 3049 Label materialize_true, materialize_false; |
| 2961 Label* if_true = NULL; | 3050 Label* if_true = NULL; |
| 2962 Label* if_false = NULL; | 3051 Label* if_false = NULL; |
| 2963 Label* fall_through = NULL; | 3052 Label* fall_through = NULL; |
| 2964 // Notice that the labels are swapped. | 3053 // Notice that the labels are swapped. |
| 2965 context()->PrepareTest(&materialize_true, &materialize_false, | 3054 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2966 &if_false, &if_true, &fall_through); | 3055 &if_false, &if_true, &fall_through); |
| 3056 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 2967 VisitForControl(expr->expression(), if_true, if_false, fall_through); | 3057 VisitForControl(expr->expression(), if_true, if_false, fall_through); |
| 2968 context()->Plug(if_false, if_true); // Labels swapped. | 3058 context()->Plug(if_false, if_true); // Labels swapped. |
| 2969 break; | 3059 break; |
| 2970 } | 3060 } |
| 2971 | 3061 |
| 2972 case Token::TYPEOF: { | 3062 case Token::TYPEOF: { |
| 2973 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 3063 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
| 2974 { StackValueContext context(this); | 3064 { StackValueContext context(this); |
| 2975 VisitForTypeofValue(expr->expression()); | 3065 VisitForTypeofValue(expr->expression()); |
| 2976 } | 3066 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3070 } else { | 3160 } else { |
| 3071 // Reserve space for result of postfix operation. | 3161 // Reserve space for result of postfix operation. |
| 3072 if (expr->is_postfix() && !context()->IsEffect()) { | 3162 if (expr->is_postfix() && !context()->IsEffect()) { |
| 3073 __ Push(Smi::FromInt(0)); | 3163 __ Push(Smi::FromInt(0)); |
| 3074 } | 3164 } |
| 3075 if (assign_type == NAMED_PROPERTY) { | 3165 if (assign_type == NAMED_PROPERTY) { |
| 3076 VisitForAccumulatorValue(prop->obj()); | 3166 VisitForAccumulatorValue(prop->obj()); |
| 3077 __ push(rax); // Copy of receiver, needed for later store. | 3167 __ push(rax); // Copy of receiver, needed for later store. |
| 3078 EmitNamedPropertyLoad(prop); | 3168 EmitNamedPropertyLoad(prop); |
| 3079 } else { | 3169 } else { |
| 3080 VisitForStackValue(prop->obj()); | 3170 if (prop->is_arguments_access()) { |
| 3081 VisitForAccumulatorValue(prop->key()); | 3171 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); |
| 3172 MemOperand slot_operand = |
| 3173 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); |
| 3174 __ push(slot_operand); |
| 3175 __ Move(rax, prop->key()->AsLiteral()->handle()); |
| 3176 } else { |
| 3177 VisitForStackValue(prop->obj()); |
| 3178 VisitForAccumulatorValue(prop->key()); |
| 3179 } |
| 3082 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack | 3180 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack |
| 3083 __ push(rax); // Copy of key, needed for later store. | 3181 __ push(rax); // Copy of key, needed for later store. |
| 3084 EmitKeyedPropertyLoad(prop); | 3182 EmitKeyedPropertyLoad(prop); |
| 3085 } | 3183 } |
| 3086 } | 3184 } |
| 3087 | 3185 |
| 3186 // We need a second deoptimization point after loading the value |
| 3187 // in case evaluating the property load my have a side effect. |
| 3188 PrepareForBailout(expr->increment(), TOS_REG); |
| 3189 |
| 3088 // Call ToNumber only if operand is not a smi. | 3190 // Call ToNumber only if operand is not a smi. |
| 3089 NearLabel no_conversion; | 3191 NearLabel no_conversion; |
| 3090 Condition is_smi; | 3192 Condition is_smi; |
| 3091 is_smi = masm_->CheckSmi(rax); | 3193 is_smi = masm_->CheckSmi(rax); |
| 3092 __ j(is_smi, &no_conversion); | 3194 __ j(is_smi, &no_conversion); |
| 3093 __ push(rax); | 3195 __ push(rax); |
| 3094 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 3196 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
| 3095 __ bind(&no_conversion); | 3197 __ bind(&no_conversion); |
| 3096 | 3198 |
| 3097 // Save result for postfix expressions. | 3199 // Save result for postfix expressions. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3147 __ bind(&done); | 3249 __ bind(&done); |
| 3148 | 3250 |
| 3149 // Store the value returned in rax. | 3251 // Store the value returned in rax. |
| 3150 switch (assign_type) { | 3252 switch (assign_type) { |
| 3151 case VARIABLE: | 3253 case VARIABLE: |
| 3152 if (expr->is_postfix()) { | 3254 if (expr->is_postfix()) { |
| 3153 // Perform the assignment as if via '='. | 3255 // Perform the assignment as if via '='. |
| 3154 { EffectContext context(this); | 3256 { EffectContext context(this); |
| 3155 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3257 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3156 Token::ASSIGN); | 3258 Token::ASSIGN); |
| 3259 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3157 context.Plug(rax); | 3260 context.Plug(rax); |
| 3158 } | 3261 } |
| 3159 // For all contexts except kEffect: We have the result on | 3262 // For all contexts except kEffect: We have the result on |
| 3160 // top of the stack. | 3263 // top of the stack. |
| 3161 if (!context()->IsEffect()) { | 3264 if (!context()->IsEffect()) { |
| 3162 context()->PlugTOS(); | 3265 context()->PlugTOS(); |
| 3163 } | 3266 } |
| 3164 } else { | 3267 } else { |
| 3165 // Perform the assignment as if via '='. | 3268 // Perform the assignment as if via '='. |
| 3166 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3269 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3167 Token::ASSIGN); | 3270 Token::ASSIGN); |
| 3271 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3168 context()->Plug(rax); | 3272 context()->Plug(rax); |
| 3169 } | 3273 } |
| 3170 break; | 3274 break; |
| 3171 case NAMED_PROPERTY: { | 3275 case NAMED_PROPERTY: { |
| 3172 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 3276 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 3173 __ pop(rdx); | 3277 __ pop(rdx); |
| 3174 Handle<Code> ic(isolate()->builtins()->builtin( | 3278 Handle<Code> ic(isolate()->builtins()->builtin( |
| 3175 Builtins::StoreIC_Initialize)); | 3279 Builtins::StoreIC_Initialize)); |
| 3176 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3280 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3281 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3177 if (expr->is_postfix()) { | 3282 if (expr->is_postfix()) { |
| 3178 if (!context()->IsEffect()) { | 3283 if (!context()->IsEffect()) { |
| 3179 context()->PlugTOS(); | 3284 context()->PlugTOS(); |
| 3180 } | 3285 } |
| 3181 } else { | 3286 } else { |
| 3182 context()->Plug(rax); | 3287 context()->Plug(rax); |
| 3183 } | 3288 } |
| 3184 break; | 3289 break; |
| 3185 } | 3290 } |
| 3186 case KEYED_PROPERTY: { | 3291 case KEYED_PROPERTY: { |
| 3187 __ pop(rcx); | 3292 __ pop(rcx); |
| 3188 __ pop(rdx); | 3293 __ pop(rdx); |
| 3189 Handle<Code> ic(isolate()->builtins()->builtin( | 3294 Handle<Code> ic(isolate()->builtins()->builtin( |
| 3190 Builtins::KeyedStoreIC_Initialize)); | 3295 Builtins::KeyedStoreIC_Initialize)); |
| 3191 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3296 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3297 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3192 if (expr->is_postfix()) { | 3298 if (expr->is_postfix()) { |
| 3193 if (!context()->IsEffect()) { | 3299 if (!context()->IsEffect()) { |
| 3194 context()->PlugTOS(); | 3300 context()->PlugTOS(); |
| 3195 } | 3301 } |
| 3196 } else { | 3302 } else { |
| 3197 context()->Plug(rax); | 3303 context()->Plug(rax); |
| 3198 } | 3304 } |
| 3199 break; | 3305 break; |
| 3200 } | 3306 } |
| 3201 } | 3307 } |
| 3202 } | 3308 } |
| 3203 | 3309 |
| 3204 | 3310 |
| 3205 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 3311 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 3206 VariableProxy* proxy = expr->AsVariableProxy(); | 3312 VariableProxy* proxy = expr->AsVariableProxy(); |
| 3207 ASSERT(!context()->IsEffect()); | 3313 ASSERT(!context()->IsEffect()); |
| 3208 ASSERT(!context()->IsTest()); | 3314 ASSERT(!context()->IsTest()); |
| 3209 | 3315 |
| 3210 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3316 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
| 3211 Comment cmnt(masm_, "Global variable"); | 3317 Comment cmnt(masm_, "Global variable"); |
| 3212 __ Move(rcx, proxy->name()); | 3318 __ Move(rcx, proxy->name()); |
| 3213 __ movq(rax, GlobalObjectOperand()); | 3319 __ movq(rax, GlobalObjectOperand()); |
| 3214 Handle<Code> ic(isolate()->builtins()->builtin( | 3320 Handle<Code> ic(isolate()->builtins()->builtin( |
| 3215 Builtins::LoadIC_Initialize)); | 3321 Builtins::LoadIC_Initialize)); |
| 3216 // Use a regular load, not a contextual load, to avoid a reference | 3322 // Use a regular load, not a contextual load, to avoid a reference |
| 3217 // error. | 3323 // error. |
| 3218 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3324 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3325 PrepareForBailout(expr, TOS_REG); |
| 3219 context()->Plug(rax); | 3326 context()->Plug(rax); |
| 3220 } else if (proxy != NULL && | 3327 } else if (proxy != NULL && |
| 3221 proxy->var()->AsSlot() != NULL && | 3328 proxy->var()->AsSlot() != NULL && |
| 3222 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { | 3329 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { |
| 3223 Label done, slow; | 3330 Label done, slow; |
| 3224 | 3331 |
| 3225 // Generate code for loading from variables potentially shadowed | 3332 // Generate code for loading from variables potentially shadowed |
| 3226 // by eval-introduced variables. | 3333 // by eval-introduced variables. |
| 3227 Slot* slot = proxy->var()->AsSlot(); | 3334 Slot* slot = proxy->var()->AsSlot(); |
| 3228 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); | 3335 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); |
| 3229 | 3336 |
| 3230 __ bind(&slow); | 3337 __ bind(&slow); |
| 3231 __ push(rsi); | 3338 __ push(rsi); |
| 3232 __ Push(proxy->name()); | 3339 __ Push(proxy->name()); |
| 3233 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3340 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 3341 PrepareForBailout(expr, TOS_REG); |
| 3234 __ bind(&done); | 3342 __ bind(&done); |
| 3235 | 3343 |
| 3236 context()->Plug(rax); | 3344 context()->Plug(rax); |
| 3237 } else { | 3345 } else { |
| 3238 // This expression cannot throw a reference error at the top level. | 3346 // This expression cannot throw a reference error at the top level. |
| 3239 Visit(expr); | 3347 context()->HandleExpression(expr); |
| 3240 } | 3348 } |
| 3241 } | 3349 } |
| 3242 | 3350 |
| 3243 | 3351 |
| 3244 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, | 3352 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, |
| 3245 Expression* left, | 3353 Expression* left, |
| 3246 Expression* right, | 3354 Expression* right, |
| 3247 Label* if_true, | 3355 Label* if_true, |
| 3248 Label* if_false, | 3356 Label* if_false, |
| 3249 Label* fall_through) { | 3357 Label* fall_through) { |
| 3250 if (op != Token::EQ && op != Token::EQ_STRICT) return false; | 3358 if (op != Token::EQ && op != Token::EQ_STRICT) return false; |
| 3251 | 3359 |
| 3252 // Check for the pattern: typeof <expression> == <string literal>. | 3360 // Check for the pattern: typeof <expression> == <string literal>. |
| 3253 Literal* right_literal = right->AsLiteral(); | 3361 Literal* right_literal = right->AsLiteral(); |
| 3254 if (right_literal == NULL) return false; | 3362 if (right_literal == NULL) return false; |
| 3255 Handle<Object> right_literal_value = right_literal->handle(); | 3363 Handle<Object> right_literal_value = right_literal->handle(); |
| 3256 if (!right_literal_value->IsString()) return false; | 3364 if (!right_literal_value->IsString()) return false; |
| 3257 UnaryOperation* left_unary = left->AsUnaryOperation(); | 3365 UnaryOperation* left_unary = left->AsUnaryOperation(); |
| 3258 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | 3366 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; |
| 3259 Handle<String> check = Handle<String>::cast(right_literal_value); | 3367 Handle<String> check = Handle<String>::cast(right_literal_value); |
| 3260 | 3368 |
| 3261 { AccumulatorValueContext context(this); | 3369 { AccumulatorValueContext context(this); |
| 3262 VisitForTypeofValue(left_unary->expression()); | 3370 VisitForTypeofValue(left_unary->expression()); |
| 3263 } | 3371 } |
| 3372 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3264 | 3373 |
| 3265 if (check->Equals(isolate()->heap()->number_symbol())) { | 3374 if (check->Equals(isolate()->heap()->number_symbol())) { |
| 3266 Condition is_smi = masm_->CheckSmi(rax); | 3375 Condition is_smi = masm_->CheckSmi(rax); |
| 3267 __ j(is_smi, if_true); | 3376 __ j(is_smi, if_true); |
| 3268 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); | 3377 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
| 3269 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); | 3378 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); |
| 3270 Split(equal, if_true, if_false, fall_through); | 3379 Split(equal, if_true, if_false, fall_through); |
| 3271 } else if (check->Equals(isolate()->heap()->string_symbol())) { | 3380 } else if (check->Equals(isolate()->heap()->string_symbol())) { |
| 3272 Condition is_smi = masm_->CheckSmi(rax); | 3381 Condition is_smi = masm_->CheckSmi(rax); |
| 3273 __ j(is_smi, if_false); | 3382 __ j(is_smi, if_false); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3347 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { | 3456 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { |
| 3348 context()->Plug(if_true, if_false); | 3457 context()->Plug(if_true, if_false); |
| 3349 return; | 3458 return; |
| 3350 } | 3459 } |
| 3351 | 3460 |
| 3352 VisitForStackValue(expr->left()); | 3461 VisitForStackValue(expr->left()); |
| 3353 switch (op) { | 3462 switch (op) { |
| 3354 case Token::IN: | 3463 case Token::IN: |
| 3355 VisitForStackValue(expr->right()); | 3464 VisitForStackValue(expr->right()); |
| 3356 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 3465 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 3466 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 3357 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 3467 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 3358 Split(equal, if_true, if_false, fall_through); | 3468 Split(equal, if_true, if_false, fall_through); |
| 3359 break; | 3469 break; |
| 3360 | 3470 |
| 3361 case Token::INSTANCEOF: { | 3471 case Token::INSTANCEOF: { |
| 3362 VisitForStackValue(expr->right()); | 3472 VisitForStackValue(expr->right()); |
| 3363 InstanceofStub stub(InstanceofStub::kNoFlags); | 3473 InstanceofStub stub(InstanceofStub::kNoFlags); |
| 3364 __ CallStub(&stub); | 3474 __ CallStub(&stub); |
| 3475 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3365 __ testq(rax, rax); | 3476 __ testq(rax, rax); |
| 3366 // The stub returns 0 for true. | 3477 // The stub returns 0 for true. |
| 3367 Split(zero, if_true, if_false, fall_through); | 3478 Split(zero, if_true, if_false, fall_through); |
| 3368 break; | 3479 break; |
| 3369 } | 3480 } |
| 3370 | 3481 |
| 3371 default: { | 3482 default: { |
| 3372 VisitForAccumulatorValue(expr->right()); | 3483 VisitForAccumulatorValue(expr->right()); |
| 3373 Condition cc = no_condition; | 3484 Condition cc = no_condition; |
| 3374 bool strict = false; | 3485 bool strict = false; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3413 __ SmiCompare(rdx, rax); | 3524 __ SmiCompare(rdx, rax); |
| 3414 Split(cc, if_true, if_false, NULL); | 3525 Split(cc, if_true, if_false, NULL); |
| 3415 __ bind(&slow_case); | 3526 __ bind(&slow_case); |
| 3416 } | 3527 } |
| 3417 | 3528 |
| 3418 CompareFlags flags = inline_smi_code | 3529 CompareFlags flags = inline_smi_code |
| 3419 ? NO_SMI_COMPARE_IN_STUB | 3530 ? NO_SMI_COMPARE_IN_STUB |
| 3420 : NO_COMPARE_FLAGS; | 3531 : NO_COMPARE_FLAGS; |
| 3421 CompareStub stub(cc, strict, flags); | 3532 CompareStub stub(cc, strict, flags); |
| 3422 __ CallStub(&stub); | 3533 __ CallStub(&stub); |
| 3534 |
| 3535 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3423 __ testq(rax, rax); | 3536 __ testq(rax, rax); |
| 3424 Split(cc, if_true, if_false, fall_through); | 3537 Split(cc, if_true, if_false, fall_through); |
| 3425 } | 3538 } |
| 3426 } | 3539 } |
| 3427 | 3540 |
| 3428 // Convert the result of the comparison into one expected for this | 3541 // Convert the result of the comparison into one expected for this |
| 3429 // expression's context. | 3542 // expression's context. |
| 3430 context()->Plug(if_true, if_false); | 3543 context()->Plug(if_true, if_false); |
| 3431 } | 3544 } |
| 3432 | 3545 |
| 3433 | 3546 |
| 3434 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { | 3547 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { |
| 3435 Comment cmnt(masm_, "[ CompareToNull"); | 3548 Comment cmnt(masm_, "[ CompareToNull"); |
| 3436 Label materialize_true, materialize_false; | 3549 Label materialize_true, materialize_false; |
| 3437 Label* if_true = NULL; | 3550 Label* if_true = NULL; |
| 3438 Label* if_false = NULL; | 3551 Label* if_false = NULL; |
| 3439 Label* fall_through = NULL; | 3552 Label* fall_through = NULL; |
| 3440 context()->PrepareTest(&materialize_true, &materialize_false, | 3553 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3441 &if_true, &if_false, &fall_through); | 3554 &if_true, &if_false, &fall_through); |
| 3442 | 3555 |
| 3443 VisitForAccumulatorValue(expr->expression()); | 3556 VisitForAccumulatorValue(expr->expression()); |
| 3557 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3444 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 3558 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 3445 if (expr->is_strict()) { | 3559 if (expr->is_strict()) { |
| 3446 Split(equal, if_true, if_false, fall_through); | 3560 Split(equal, if_true, if_false, fall_through); |
| 3447 } else { | 3561 } else { |
| 3448 __ j(equal, if_true); | 3562 __ j(equal, if_true); |
| 3449 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 3563 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 3450 __ j(equal, if_true); | 3564 __ j(equal, if_true); |
| 3451 Condition is_smi = masm_->CheckSmi(rax); | 3565 Condition is_smi = masm_->CheckSmi(rax); |
| 3452 __ j(is_smi, if_false); | 3566 __ j(is_smi, if_false); |
| 3453 // It can be an undetectable object. | 3567 // It can be an undetectable object. |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3545 __ ret(0); | 3659 __ ret(0); |
| 3546 } | 3660 } |
| 3547 | 3661 |
| 3548 | 3662 |
| 3549 #undef __ | 3663 #undef __ |
| 3550 | 3664 |
| 3551 | 3665 |
| 3552 } } // namespace v8::internal | 3666 } } // namespace v8::internal |
| 3553 | 3667 |
| 3554 #endif // V8_TARGET_ARCH_X64 | 3668 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |