Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 137 Comment cmnt(masm_, "[ ExpressionStatement"); | 137 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 138 SetStatementPosition(stmt); | 138 SetStatementPosition(stmt); |
| 139 Visit(stmt->expression()); | 139 Visit(stmt->expression()); |
| 140 } | 140 } |
| 141 | 141 |
| 142 | 142 |
| 143 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 143 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
| 144 Comment cmnt(masm_, "[ ReturnStatement"); | 144 Comment cmnt(masm_, "[ ReturnStatement"); |
| 145 SetStatementPosition(stmt); | 145 SetStatementPosition(stmt); |
| 146 Expression* expr = stmt->expression(); | 146 Expression* expr = stmt->expression(); |
| 147 Visit(expr); | 147 // Complete the statement based on the type of the subexpression. |
| 148 if (expr->AsLiteral() != NULL) { | |
| 149 __ Move(rax, expr->AsLiteral()->handle()); | |
| 150 } else { | |
| 151 Visit(expr); | |
| 152 ASSERT(expr->location().is_temporary()); | |
| 153 __ pop(rax); | |
| 154 } | |
| 148 | 155 |
| 149 // Complete the statement based on the location of the subexpression. | |
| 150 Location source = expr->location(); | |
| 151 ASSERT(!source.is_nowhere()); | |
| 152 if (source.is_temporary()) { | |
| 153 __ pop(rax); | |
| 154 } else { | |
| 155 ASSERT(source.is_constant()); | |
| 156 ASSERT(expr->AsLiteral() != NULL); | |
| 157 __ Move(rax, expr->AsLiteral()->handle()); | |
| 158 } | |
| 159 if (FLAG_trace) { | 156 if (FLAG_trace) { |
| 160 __ push(rax); | 157 __ push(rax); |
| 161 __ CallRuntime(Runtime::kTraceExit, 1); | 158 __ CallRuntime(Runtime::kTraceExit, 1); |
| 162 } | 159 } |
| 163 | 160 |
| 164 __ RecordJSReturn(); | 161 __ RecordJSReturn(); |
| 165 // Do not use the leave instruction here because it is too short to | 162 // Do not use the leave instruction here because it is too short to |
| 166 // patch with the code required by the debugger. | 163 // patch with the code required by the debugger. |
| 167 __ movq(rsp, rbp); | 164 __ movq(rsp, rbp); |
| 168 __ pop(rbp); | 165 __ pop(rbp); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 ASSERT(slot != NULL); | 227 ASSERT(slot != NULL); |
| 231 if (expr->location().is_temporary()) { | 228 if (expr->location().is_temporary()) { |
| 232 __ push(Operand(rbp, SlotOffset(slot))); | 229 __ push(Operand(rbp, SlotOffset(slot))); |
| 233 } else { | 230 } else { |
| 234 ASSERT(expr->location().is_nowhere()); | 231 ASSERT(expr->location().is_nowhere()); |
| 235 } | 232 } |
| 236 } | 233 } |
| 237 } | 234 } |
| 238 | 235 |
| 239 | 236 |
| 237 void FastCodeGenerator::VisitLiteral(Literal* expr) { | |
| 238 if (expr->location().is_temporary()) { | |
| 239 __ Push(expr->handle()); | |
| 240 } else { | |
| 241 ASSERT(expr->location().is_nowhere()); | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 | |
| 240 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 246 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
| 241 Comment cmnt(masm_, "[ ObjectLiteral"); | 247 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 242 Label boilerplate_exists; | 248 Label boilerplate_exists; |
| 243 | 249 |
| 244 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 250 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 245 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 251 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
| 246 int literal_offset = | 252 int literal_offset = |
| 247 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 253 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
| 248 __ movq(rax, FieldOperand(rbx, literal_offset)); | 254 __ movq(rax, FieldOperand(rbx, literal_offset)); |
| 249 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 255 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 294 __ Move(rcx, key->handle()); | 300 __ Move(rcx, key->handle()); |
| 295 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 301 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 296 __ call(ic, RelocInfo::CODE_TARGET); | 302 __ call(ic, RelocInfo::CODE_TARGET); |
| 297 // StoreIC leaves the receiver on the stack. | 303 // StoreIC leaves the receiver on the stack. |
| 298 break; | 304 break; |
| 299 } | 305 } |
| 300 // fall through | 306 // fall through |
| 301 case ObjectLiteral::Property::PROTOTYPE: | 307 case ObjectLiteral::Property::PROTOTYPE: |
| 302 __ push(rax); | 308 __ push(rax); |
| 303 Visit(key); | 309 Visit(key); |
| 304 if (key->location().is_constant()) { | 310 ASSERT(key->location().is_temporary()); |
| 305 __ Push(key->handle()); | |
| 306 } | |
| 307 Visit(value); | 311 Visit(value); |
| 308 ASSERT(value->location().is_temporary()); | 312 ASSERT(value->location().is_temporary()); |
| 309 __ CallRuntime(Runtime::kSetProperty, 3); | 313 __ CallRuntime(Runtime::kSetProperty, 3); |
| 310 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | 314 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. |
| 311 break; | 315 break; |
| 312 case ObjectLiteral::Property::SETTER: // fall through | 316 case ObjectLiteral::Property::SETTER: // fall through |
| 313 case ObjectLiteral::Property::GETTER: | 317 case ObjectLiteral::Property::GETTER: |
| 314 __ push(rax); | 318 __ push(rax); |
| 315 Visit(key); | 319 Visit(key); |
| 316 if (key->location().is_constant()) { | 320 ASSERT(key->location.is_temporary()); |
| 317 __ Push(key->handle()); | |
| 318 } | |
| 319 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? | 321 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? |
| 320 Smi::FromInt(1) : | 322 Smi::FromInt(1) : |
| 321 Smi::FromInt(0)); | 323 Smi::FromInt(0)); |
| 322 Visit(value); | 324 Visit(value); |
| 323 ASSERT(value->location().is_temporary()); | 325 ASSERT(value->location().is_temporary()); |
| 324 __ CallRuntime(Runtime::kDefineAccessor, 4); | 326 __ CallRuntime(Runtime::kDefineAccessor, 4); |
| 325 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | 327 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. |
| 326 break; | 328 break; |
| 327 default: UNREACHABLE(); | 329 default: UNREACHABLE(); |
| 328 } | 330 } |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 432 __ addq(rsp, Immediate(kPointerSize)); | 434 __ addq(rsp, Immediate(kPointerSize)); |
| 433 } else if (destination.is_temporary() && !result_saved) { | 435 } else if (destination.is_temporary() && !result_saved) { |
| 434 __ push(rax); | 436 __ push(rax); |
| 435 } | 437 } |
| 436 } | 438 } |
| 437 | 439 |
| 438 | 440 |
| 439 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 441 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
| 440 Comment cmnt(masm_, "[ Assignment"); | 442 Comment cmnt(masm_, "[ Assignment"); |
| 441 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 443 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
| 442 Expression* rhs = expr->value(); | |
| 443 Visit(rhs); | |
| 444 | 444 |
| 445 // Left-hand side can only be a global or a (parameter or local) slot. | 445 // Left-hand side can only be a global or a (parameter or local) slot. |
| 446 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 446 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
| 447 ASSERT(var != NULL); | 447 ASSERT(var != NULL); |
| 448 ASSERT(var->is_global() || var->slot() != NULL); | 448 ASSERT(var->is_global() || var->slot() != NULL); |
| 449 | 449 |
| 450 // Complete the assignment based on the location of the right-hand-side | 450 Expression* rhs = expr->value(); |
| 451 // value and the desired location of the assignment value. | |
| 452 Location destination = expr->location(); | 451 Location destination = expr->location(); |
| 453 Location source = rhs->location(); | |
| 454 ASSERT(!destination.is_constant()); | |
| 455 ASSERT(!source.is_nowhere()); | |
| 456 | |
| 457 if (var->is_global()) { | 452 if (var->is_global()) { |
| 458 // Assignment to a global variable, use inline caching. Right-hand-side | 453 // Assignment to a global variable, use inline caching. Right-hand-side |
| 459 // value is passed in rax, variable name in rcx, and the global object | 454 // value is passed in rax, variable name in rcx, and the global object |
| 460 // on the stack. | 455 // on the stack. |
| 461 if (source.is_temporary()) { | 456 |
| 457 // Code for the right-hand-side expression depends on its type. | |
| 458 if (rhs->AsLiteral() != NULL) { | |
| 459 __ Move(rax, rhs->AsLiteral()->handle()); | |
| 460 } else { | |
| 461 ASSERT(rhs->location().is_temporary()); | |
| 462 Visit(rhs); | |
| 462 __ pop(rax); | 463 __ pop(rax); |
| 463 } else { | |
| 464 ASSERT(source.is_constant()); | |
| 465 ASSERT(rhs->AsLiteral() != NULL); | |
| 466 __ Move(rax, rhs->AsLiteral()->handle()); | |
| 467 } | 464 } |
| 468 __ Move(rcx, var->name()); | 465 __ Move(rcx, var->name()); |
| 469 __ push(CodeGenerator::GlobalObject()); | 466 __ push(CodeGenerator::GlobalObject()); |
| 470 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 467 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 471 __ Call(ic, RelocInfo::CODE_TARGET); | 468 __ Call(ic, RelocInfo::CODE_TARGET); |
| 472 // Overwrite the global object on the stack with the result if needed. | 469 // Overwrite the global object on the stack with the result if needed. |
| 473 if (destination.is_temporary()) { | 470 if (destination.is_temporary()) { |
| 474 __ movq(Operand(rsp, 0), rax); | 471 __ movq(Operand(rsp, 0), rax); |
| 475 } else { | 472 } else { |
| 476 __ addq(rsp, Immediate(kPointerSize)); | 473 __ addq(rsp, Immediate(kPointerSize)); |
| 477 } | 474 } |
| 478 } else { | 475 } else { |
| 479 if (source.is_temporary()) { | 476 // Local or parameter assignment. |
| 477 | |
| 478 // Code for the right-hand-side expression depends on its type. | |
| 479 if (rhs->AsLiteral() != NULL) { | |
| 480 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a | |
| 481 // discarded result. Always perform the assignment. | |
| 482 __ Move(kScratchRegister, rhs->AsLiteral()->handle()); | |
| 483 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); | |
| 484 if (destination.is_temporary()) { | |
| 485 // Case 'temp <- (var = constant)'. Save result. | |
| 486 __ push(kScratchRegister); | |
| 487 } | |
|
fschneider
2009/10/26 17:57:20
Add an assert here to be consistent with the rest
| |
| 488 } else { | |
| 489 ASSERT(rhs->location().is_temporary()); | |
| 490 Visit(rhs); | |
| 480 if (destination.is_temporary()) { | 491 if (destination.is_temporary()) { |
| 481 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side temporary | 492 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side temporary |
| 482 // on the stack. | 493 // on the stack. |
| 483 __ movq(kScratchRegister, Operand(rsp, 0)); | 494 __ movq(kScratchRegister, Operand(rsp, 0)); |
| 484 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); | 495 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); |
| 485 } else { | 496 } else { |
| 486 ASSERT(destination.is_nowhere()); | 497 ASSERT(destination.is_nowhere()); |
| 487 // Case 'var = temp'. Discard right-hand-side temporary. | 498 // Case 'var = temp'. Discard right-hand-side temporary. |
| 488 __ pop(Operand(rbp, SlotOffset(var->slot()))); | 499 __ pop(Operand(rbp, SlotOffset(var->slot()))); |
| 489 } | 500 } |
| 490 } else { | |
| 491 ASSERT(source.is_constant()); | |
| 492 ASSERT(rhs->AsLiteral() != NULL); | |
| 493 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a | |
| 494 // discarded result. Always perform the assignment. | |
| 495 __ Move(kScratchRegister, rhs->AsLiteral()->handle()); | |
| 496 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); | |
| 497 if (destination.is_temporary()) { | |
| 498 // Case 'temp <- (var = constant)'. Save result. | |
| 499 __ push(kScratchRegister); | |
| 500 } | |
| 501 } | 501 } |
| 502 } | 502 } |
| 503 } | 503 } |
| 504 | 504 |
| 505 | 505 |
| 506 void FastCodeGenerator::VisitCall(Call* expr) { | 506 void FastCodeGenerator::VisitCall(Call* expr) { |
| 507 Expression* fun = expr->expression(); | 507 Expression* fun = expr->expression(); |
| 508 ZoneList<Expression*>* args = expr->arguments(); | 508 ZoneList<Expression*>* args = expr->arguments(); |
| 509 Variable* var = fun->AsVariableProxy()->AsVariable(); | 509 Variable* var = fun->AsVariableProxy()->AsVariable(); |
| 510 ASSERT(var != NULL && !var->is_this() && var->is_global()); | 510 ASSERT(var != NULL && !var->is_this() && var->is_global()); |
| 511 ASSERT(!var->is_possibly_eval()); | 511 ASSERT(!var->is_possibly_eval()); |
| 512 | 512 |
| 513 __ Push(var->name()); | 513 __ Push(var->name()); |
| 514 // Push global object (receiver). | 514 // Push global object (receiver). |
| 515 __ push(CodeGenerator::GlobalObject()); | 515 __ push(CodeGenerator::GlobalObject()); |
| 516 int arg_count = args->length(); | 516 int arg_count = args->length(); |
| 517 for (int i = 0; i < arg_count; i++) { | 517 for (int i = 0; i < arg_count; i++) { |
| 518 Visit(args->at(i)); | 518 Visit(args->at(i)); |
| 519 ASSERT(!args->at(i)->location().is_nowhere()); | 519 ASSERT(args->at(i)->location().is_temporary()); |
| 520 if (args->at(i)->location().is_constant()) { | |
| 521 ASSERT(args->at(i)->AsLiteral() != NULL); | |
| 522 __ Push(args->at(i)->AsLiteral()->handle()); | |
| 523 } | |
| 524 } | 520 } |
| 525 // Record source position for debugger | 521 // Record source position for debugger |
| 526 SetSourcePosition(expr->position()); | 522 SetSourcePosition(expr->position()); |
| 527 // Call the IC initialization code. | 523 // Call the IC initialization code. |
| 528 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 524 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
| 529 NOT_IN_LOOP); | 525 NOT_IN_LOOP); |
| 530 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 526 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 531 // Restore context register. | 527 // Restore context register. |
| 532 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 528 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 533 // Discard the function left on TOS. | 529 // Discard the function left on TOS. |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 544 Comment cmnt(masm_, "[ CallRuntime"); | 540 Comment cmnt(masm_, "[ CallRuntime"); |
| 545 ZoneList<Expression*>* args = expr->arguments(); | 541 ZoneList<Expression*>* args = expr->arguments(); |
| 546 Runtime::Function* function = expr->function(); | 542 Runtime::Function* function = expr->function(); |
| 547 | 543 |
| 548 ASSERT(function != NULL); | 544 ASSERT(function != NULL); |
| 549 | 545 |
| 550 // Push the arguments ("left-to-right"). | 546 // Push the arguments ("left-to-right"). |
| 551 int arg_count = args->length(); | 547 int arg_count = args->length(); |
| 552 for (int i = 0; i < arg_count; i++) { | 548 for (int i = 0; i < arg_count; i++) { |
| 553 Visit(args->at(i)); | 549 Visit(args->at(i)); |
| 554 ASSERT(!args->at(i)->location().is_nowhere()); | 550 ASSERT(args->at(i)->location().is_temporary()); |
| 555 if (args->at(i)->location().is_constant()) { | |
| 556 ASSERT(args->at(i)->AsLiteral() != NULL); | |
| 557 __ Push(args->at(i)->AsLiteral()->handle()); | |
| 558 } else { | |
| 559 ASSERT(args->at(i)->location().is_temporary()); | |
| 560 // If location is temporary, it is already on the stack, | |
| 561 // so nothing to do here. | |
| 562 } | |
| 563 } | 551 } |
| 564 | 552 |
| 565 __ CallRuntime(function, arg_count); | 553 __ CallRuntime(function, arg_count); |
| 566 if (expr->location().is_temporary()) { | 554 if (expr->location().is_temporary()) { |
| 567 __ push(rax); | 555 __ push(rax); |
| 568 } else { | 556 } else { |
| 569 ASSERT(expr->location().is_nowhere()); | 557 ASSERT(expr->location().is_nowhere()); |
| 570 } | 558 } |
| 571 } | 559 } |
| 572 | 560 |
| 573 | 561 |
| 574 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 562 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
| 575 // Compile a short-circuited boolean or operation in a non-test | 563 // Compile a short-circuited boolean or operation in a non-test |
| 576 // context. | 564 // context. |
| 577 ASSERT(expr->op() == Token::OR); | 565 ASSERT(expr->op() == Token::OR); |
| 578 // Compile (e0 || e1) as if it were | 566 // Compile (e0 || e1) as if it were |
| 579 // (let (temp = e0) temp ? temp : e1). | 567 // (let (temp = e0) temp ? temp : e1). |
| 580 | 568 |
| 581 Label eval_right, done; | 569 Label eval_right, done; |
| 582 Location destination = expr->location(); | 570 Location destination = expr->location(); |
| 583 ASSERT(!destination.is_constant()); | 571 Expression* left = expr->left(); |
| 572 Expression* right = expr->right(); | |
| 584 | 573 |
| 585 Expression* left = expr->left(); | |
| 586 Location left_source = left->location(); | |
| 587 ASSERT(!left_source.is_nowhere()); | |
| 588 | |
| 589 Expression* right = expr->right(); | |
| 590 Location right_source = right->location(); | |
| 591 ASSERT(!right_source.is_nowhere()); | |
| 592 | |
| 593 Visit(left); | |
| 594 // Use the shared ToBoolean stub to find the boolean value of the | 574 // Use the shared ToBoolean stub to find the boolean value of the |
| 595 // left-hand subexpression. Load the value into rax to perform some | 575 // left-hand subexpression. Load the value into rax to perform some |
| 596 // inlined checks assumed by the stub. | 576 // inlined checks assumed by the stub. |
| 597 if (left_source.is_temporary()) { | 577 |
| 578 // Compile the left-hand value into rax. Put it on the stack if we may | |
| 579 // need it as the value of the whole expression. | |
| 580 if (left->AsLiteral() != NULL) { | |
| 581 __ Move(rax, left->AsLiteral()->handle()); | |
| 582 if (destination.is_temporary()) __ push(rax); | |
|
fschneider
2009/10/26 17:57:20
May want to add an assert here to be consistent wi
| |
| 583 } else { | |
| 584 Visit(left); | |
| 585 ASSERT(left->location().is_temporary()); | |
| 598 if (destination.is_temporary()) { | 586 if (destination.is_temporary()) { |
| 599 // Copy the left-hand value into rax because we may need it as the | 587 // Copy the left-hand value into rax because we may need it as the |
| 600 // final result. | 588 // final result. |
| 601 __ movq(rax, Operand(rsp, 0)); | 589 __ movq(rax, Operand(rsp, 0)); |
| 602 } else { | 590 } else { |
| 603 // Pop the left-hand value into rax because we will not need it as the | 591 // Pop the left-hand value into rax because we will not need it as the |
| 604 // final result. | 592 // final result. |
| 605 __ pop(rax); | 593 __ pop(rax); |
|
fschneider
2009/10/26 17:57:20
Adding an assert to be consistent on all platforms
| |
| 606 } | 594 } |
| 607 } else { | |
| 608 // Load the left-hand value into rax. Put it on the stack if we may | |
| 609 // need it. | |
| 610 ASSERT(left->AsLiteral() != NULL); | |
| 611 __ Move(rax, left->AsLiteral()->handle()); | |
| 612 if (destination.is_temporary()) __ push(rax); | |
| 613 } | 595 } |
| 614 // The left-hand value is in rax. It is also on the stack iff the | 596 // The left-hand value is in rax. It is also on the stack iff the |
| 615 // destination location is temporary. | 597 // destination location is temporary. |
| 616 | 598 |
| 617 // Perform fast checks assumed by the stub. | 599 // Perform fast checks assumed by the stub. |
| 618 // The undefined value is false. | 600 // The undefined value is false. |
| 619 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 601 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 620 __ j(equal, &eval_right); | 602 __ j(equal, &eval_right); |
| 621 __ CompareRoot(rax, Heap::kTrueValueRootIndex); // True is true. | 603 __ CompareRoot(rax, Heap::kTrueValueRootIndex); // True is true. |
| 622 __ j(equal, &done); | 604 __ j(equal, &done); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 633 ToBooleanStub stub; | 615 ToBooleanStub stub; |
| 634 __ CallStub(&stub); | 616 __ CallStub(&stub); |
| 635 __ testq(rax, rax); // The stub returns nonzero for true. | 617 __ testq(rax, rax); // The stub returns nonzero for true. |
| 636 __ j(not_zero, &done); | 618 __ j(not_zero, &done); |
| 637 | 619 |
| 638 __ bind(&eval_right); | 620 __ bind(&eval_right); |
| 639 // Discard the left-hand value if present on the stack. | 621 // Discard the left-hand value if present on the stack. |
| 640 if (destination.is_temporary()) { | 622 if (destination.is_temporary()) { |
| 641 __ addq(rsp, Immediate(kPointerSize)); | 623 __ addq(rsp, Immediate(kPointerSize)); |
| 642 } | 624 } |
| 643 Visit(right); | |
| 644 | |
| 645 // Save or discard the right-hand value as needed. | 625 // Save or discard the right-hand value as needed. |
| 646 if (destination.is_temporary() && right_source.is_constant()) { | 626 if (right->AsLiteral() != NULL) { |
| 647 ASSERT(right->AsLiteral() != NULL); | 627 if (destination.is_temporary()) { |
| 648 __ Push(right->AsLiteral()->handle()); | 628 __ Push(right->AsLiteral()->handle()); |
| 649 } else if (destination.is_nowhere() && right_source.is_temporary()) { | 629 } else { |
| 650 __ addq(rsp, Immediate(kPointerSize)); | 630 ASSERT(destination.is_nowhere()); |
| 631 } | |
| 632 } else { | |
| 633 Visit(right); | |
| 634 ASSERT(right->location().is_temporary()); | |
| 635 if (destination.is_nowhere()) { | |
| 636 __ addq(rsp, Immediate(kPointerSize)); | |
| 637 } else { | |
| 638 ASSERT(destination.is_temporary()); | |
| 639 } | |
| 651 } | 640 } |
| 652 | 641 |
| 653 __ bind(&done); | 642 __ bind(&done); |
| 654 } | 643 } |
| 655 | 644 |
| 656 | 645 |
| 657 } } // namespace v8::internal | 646 } } // namespace v8::internal |
| OLD | NEW |