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 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 129 Comment cmnt(masm_, "[ ExpressionStatement"); | 129 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 130 SetStatementPosition(stmt); | 130 SetStatementPosition(stmt); |
| 131 Visit(stmt->expression()); | 131 Visit(stmt->expression()); |
| 132 } | 132 } |
| 133 | 133 |
| 134 | 134 |
| 135 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 135 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
| 136 Comment cmnt(masm_, "[ ReturnStatement"); | 136 Comment cmnt(masm_, "[ ReturnStatement"); |
| 137 SetStatementPosition(stmt); | 137 SetStatementPosition(stmt); |
| 138 Expression* expr = stmt->expression(); | 138 Expression* expr = stmt->expression(); |
| 139 Visit(expr); | 139 // Complete the statement based on the type of the subexpression. |
| 140 if (expr->AsLiteral() != NULL) { | |
| 141 __ mov(eax, expr->AsLiteral()->handle()); | |
| 142 } else { | |
| 143 Visit(expr); | |
| 144 ASSERT(expr->location().is_temporary()); | |
| 145 __ pop(eax); | |
| 146 } | |
| 140 | 147 |
| 141 // Complete the statement based on the location of the subexpression. | |
| 142 Location source = expr->location(); | |
| 143 ASSERT(!source.is_nowhere()); | |
| 144 if (source.is_temporary()) { | |
| 145 __ pop(eax); | |
| 146 } else { | |
| 147 ASSERT(source.is_constant()); | |
| 148 ASSERT(expr->AsLiteral() != NULL); | |
| 149 __ mov(eax, expr->AsLiteral()->handle()); | |
| 150 } | |
| 151 if (FLAG_trace) { | 148 if (FLAG_trace) { |
| 152 __ push(eax); | 149 __ push(eax); |
| 153 __ CallRuntime(Runtime::kTraceExit, 1); | 150 __ CallRuntime(Runtime::kTraceExit, 1); |
| 154 } | 151 } |
| 155 __ RecordJSReturn(); | 152 __ RecordJSReturn(); |
| 156 | 153 |
| 157 // Do not use the leave instruction here because it is too short to | 154 // Do not use the leave instruction here because it is too short to |
| 158 // patch with the code required by the debugger. | 155 // patch with the code required by the debugger. |
| 159 __ mov(esp, ebp); | 156 __ mov(esp, ebp); |
| 160 __ pop(ebp); | 157 __ pop(ebp); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 214 ASSERT(slot != NULL); | 211 ASSERT(slot != NULL); |
| 215 if (expr->location().is_temporary()) { | 212 if (expr->location().is_temporary()) { |
| 216 __ push(Operand(ebp, SlotOffset(slot))); | 213 __ push(Operand(ebp, SlotOffset(slot))); |
| 217 } else { | 214 } else { |
| 218 ASSERT(expr->location().is_nowhere()); | 215 ASSERT(expr->location().is_nowhere()); |
| 219 } | 216 } |
| 220 } | 217 } |
| 221 } | 218 } |
| 222 | 219 |
| 223 | 220 |
| 221 void FastCodeGenerator::VisitLiteral(Literal* expr) { | |
| 222 if (expr->location().is_temporary()) { | |
| 223 __ push(Immediate(expr->handle())); | |
| 224 } else { | |
| 225 ASSERT(expr->location().is_nowhere()); | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 | |
| 224 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 230 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
| 225 Comment cmnt(masm_, "[ ObjectLiteral"); | 231 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 226 Label exists; | 232 Label exists; |
| 227 // Registers will be used as follows: | 233 // Registers will be used as follows: |
| 228 // edi = JS function. | 234 // edi = JS function. |
| 229 // ebx = literals array. | 235 // ebx = literals array. |
| 230 // eax = boilerplate | 236 // eax = boilerplate |
| 231 | 237 |
| 232 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 238 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 233 __ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset)); | 239 __ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset)); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 282 __ mov(ecx, Immediate(key->handle())); | 288 __ mov(ecx, Immediate(key->handle())); |
| 283 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 289 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 284 __ call(ic, RelocInfo::CODE_TARGET); | 290 __ call(ic, RelocInfo::CODE_TARGET); |
| 285 // StoreIC leaves the receiver on the stack. | 291 // StoreIC leaves the receiver on the stack. |
| 286 break; | 292 break; |
| 287 } | 293 } |
| 288 // fall through | 294 // fall through |
| 289 case ObjectLiteral::Property::PROTOTYPE: | 295 case ObjectLiteral::Property::PROTOTYPE: |
| 290 __ push(eax); | 296 __ push(eax); |
| 291 Visit(key); | 297 Visit(key); |
| 292 if (key->location().is_constant()) { | 298 ASSERT(key->location().is_temporary()); |
| 293 __ push(Immediate(key->handle())); | |
| 294 } | |
| 295 Visit(value); | 299 Visit(value); |
| 296 ASSERT(value->location().is_temporary()); | 300 ASSERT(value->location().is_temporary()); |
| 297 __ CallRuntime(Runtime::kSetProperty, 3); | 301 __ CallRuntime(Runtime::kSetProperty, 3); |
| 298 __ mov(eax, Operand(esp, 0)); // Restore result into eax. | 302 __ mov(eax, Operand(esp, 0)); // Restore result into eax. |
| 299 break; | 303 break; |
| 300 case ObjectLiteral::Property::SETTER: // fall through | 304 case ObjectLiteral::Property::SETTER: // fall through |
| 301 case ObjectLiteral::Property::GETTER: | 305 case ObjectLiteral::Property::GETTER: |
| 302 __ push(eax); | 306 __ push(eax); |
| 303 Visit(key); | 307 Visit(key); |
| 304 if (key->location().is_constant()) { | 308 ASSERT(key->location().is_temporary()); |
| 305 __ push(Immediate(key->handle())); | |
| 306 } | |
| 307 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? | 309 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? |
| 308 Smi::FromInt(1) : | 310 Smi::FromInt(1) : |
| 309 Smi::FromInt(0))); | 311 Smi::FromInt(0))); |
| 310 Visit(value); | 312 Visit(value); |
| 311 ASSERT(value->location().is_temporary()); | 313 ASSERT(value->location().is_temporary()); |
| 312 __ CallRuntime(Runtime::kDefineAccessor, 4); | 314 __ CallRuntime(Runtime::kDefineAccessor, 4); |
| 313 __ mov(eax, Operand(esp, 0)); // Restore result into eax. | 315 __ mov(eax, Operand(esp, 0)); // Restore result into eax. |
| 314 break; | 316 break; |
| 315 default: UNREACHABLE(); | 317 default: UNREACHABLE(); |
| 316 } | 318 } |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 420 __ add(Operand(esp), Immediate(kPointerSize)); | 422 __ add(Operand(esp), Immediate(kPointerSize)); |
| 421 } else if (destination.is_temporary() && !result_saved) { | 423 } else if (destination.is_temporary() && !result_saved) { |
| 422 __ push(eax); | 424 __ push(eax); |
| 423 } | 425 } |
| 424 } | 426 } |
| 425 | 427 |
| 426 | 428 |
| 427 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 429 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
| 428 Comment cmnt(masm_, "[ Assignment"); | 430 Comment cmnt(masm_, "[ Assignment"); |
| 429 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 431 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
| 430 Expression* rhs = expr->value(); | |
| 431 Visit(rhs); | |
| 432 | 432 |
| 433 // Left-hand side can only be a global or a (parameter or local) slot. | 433 // Left-hand side can only be a global or a (parameter or local) slot. |
| 434 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 434 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
| 435 ASSERT(var != NULL); | 435 ASSERT(var != NULL); |
| 436 ASSERT(var->is_global() || var->slot() != NULL); | 436 ASSERT(var->is_global() || var->slot() != NULL); |
| 437 | 437 |
| 438 // Complete the assignment based on the location of the right-hand-side | 438 Expression* rhs = expr->value(); |
| 439 // value and the desired location of the assignment value. | |
| 440 Location destination = expr->location(); | 439 Location destination = expr->location(); |
| 441 Location source = rhs->location(); | |
| 442 ASSERT(!destination.is_constant()); | |
| 443 ASSERT(!source.is_nowhere()); | |
| 444 | |
| 445 if (var->is_global()) { | 440 if (var->is_global()) { |
| 446 // Assignment to a global variable, use inline caching. Right-hand-side | 441 // Assignment to a global variable, use inline caching. Right-hand-side |
| 447 // value is passed in eax, variable name in ecx, and the global object | 442 // value is passed in eax, variable name in ecx, and the global object |
| 448 // on the stack. | 443 // on the stack. |
| 449 if (source.is_temporary()) { | 444 |
| 445 // Code for the right-hand-side expression depends on its type. | |
| 446 if (rhs->AsLiteral() != NULL) { | |
| 447 __ mov(eax, rhs->AsLiteral()->handle()); | |
| 448 } else { | |
| 449 ASSERT(rhs->location().is_temporary()); | |
| 450 Visit(rhs); | |
| 450 __ pop(eax); | 451 __ pop(eax); |
| 451 } else { | |
| 452 ASSERT(source.is_constant()); | |
| 453 ASSERT(rhs->AsLiteral() != NULL); | |
| 454 __ mov(eax, rhs->AsLiteral()->handle()); | |
| 455 } | 452 } |
| 456 __ mov(ecx, var->name()); | 453 __ mov(ecx, var->name()); |
| 457 __ push(CodeGenerator::GlobalObject()); | 454 __ push(CodeGenerator::GlobalObject()); |
| 458 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 455 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 459 __ call(ic, RelocInfo::CODE_TARGET); | 456 __ call(ic, RelocInfo::CODE_TARGET); |
| 460 // Overwrite the global object on the stack with the result if needed. | 457 // Overwrite the global object on the stack with the result if needed. |
| 461 if (destination.is_temporary()) { | 458 if (destination.is_temporary()) { |
| 462 __ mov(Operand(esp, 0), eax); | 459 __ mov(Operand(esp, 0), eax); |
| 463 } else { | 460 } else { |
| 464 ASSERT(destination.is_nowhere()); | 461 ASSERT(destination.is_nowhere()); |
| 465 __ add(Operand(esp), Immediate(kPointerSize)); | 462 __ add(Operand(esp), Immediate(kPointerSize)); |
| 466 } | 463 } |
| 467 | |
| 468 } else { | 464 } else { |
| 469 // Local or parameter assignment. | 465 // Local or parameter assignment. |
| 470 if (source.is_temporary()) { | 466 |
| 467 // Code for the right-hand side expression depends on its type. | |
| 468 if (rhs->AsLiteral() != NULL) { | |
| 469 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a | |
| 470 // discarded result. Always perform the assignment. | |
| 471 __ mov(eax, rhs->AsLiteral()->handle()); | |
| 472 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | |
| 473 if (destination.is_temporary()) { | |
| 474 // Case 'temp <- (var = constant)'. Save result. | |
| 475 __ push(eax); | |
|
fschneider
2009/10/26 17:57:20
Add an assert here to be consistent with the rest
| |
| 476 } | |
| 477 } else { | |
| 478 ASSERT(rhs->location().is_temporary()); | |
| 479 Visit(rhs); | |
| 471 if (destination.is_temporary()) { | 480 if (destination.is_temporary()) { |
| 472 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side | 481 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side |
| 473 // temporary on the stack. | 482 // temporary on the stack. |
| 474 __ mov(eax, Operand(esp, 0)); | 483 __ mov(eax, Operand(esp, 0)); |
| 475 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | 484 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
| 476 } else { | 485 } else { |
| 477 ASSERT(destination.is_nowhere()); | 486 ASSERT(destination.is_nowhere()); |
| 478 // Case 'var = temp'. Discard right-hand-side temporary. | 487 // Case 'var = temp'. Discard right-hand-side temporary. |
| 479 __ pop(Operand(ebp, SlotOffset(var->slot()))); | 488 __ pop(Operand(ebp, SlotOffset(var->slot()))); |
| 480 } | 489 } |
| 481 } else { | |
| 482 ASSERT(source.is_constant()); | |
| 483 ASSERT(rhs->AsLiteral() != NULL); | |
| 484 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a | |
| 485 // discarded result. Always perform the assignment. | |
| 486 __ mov(eax, rhs->AsLiteral()->handle()); | |
| 487 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | |
| 488 if (destination.is_temporary()) { | |
| 489 // Case 'temp <- (var = constant)'. Save result. | |
| 490 __ push(eax); | |
| 491 } | |
| 492 } | 490 } |
| 493 } | 491 } |
| 494 } | 492 } |
| 495 | 493 |
| 496 | 494 |
| 497 void FastCodeGenerator::VisitCall(Call* expr) { | 495 void FastCodeGenerator::VisitCall(Call* expr) { |
| 498 Expression* fun = expr->expression(); | 496 Expression* fun = expr->expression(); |
| 499 ZoneList<Expression*>* args = expr->arguments(); | 497 ZoneList<Expression*>* args = expr->arguments(); |
| 500 Variable* var = fun->AsVariableProxy()->AsVariable(); | 498 Variable* var = fun->AsVariableProxy()->AsVariable(); |
| 501 ASSERT(var != NULL && !var->is_this() && var->is_global()); | 499 ASSERT(var != NULL && !var->is_this() && var->is_global()); |
| 502 ASSERT(!var->is_possibly_eval()); | 500 ASSERT(!var->is_possibly_eval()); |
| 503 | 501 |
| 504 __ push(Immediate(var->name())); | 502 __ push(Immediate(var->name())); |
| 505 // Push global object (receiver). | 503 // Push global object (receiver). |
| 506 __ push(CodeGenerator::GlobalObject()); | 504 __ push(CodeGenerator::GlobalObject()); |
| 507 int arg_count = args->length(); | 505 int arg_count = args->length(); |
| 508 for (int i = 0; i < arg_count; i++) { | 506 for (int i = 0; i < arg_count; i++) { |
| 509 Visit(args->at(i)); | 507 Visit(args->at(i)); |
| 510 ASSERT(!args->at(i)->location().is_nowhere()); | 508 ASSERT(args->at(i)->location().is_temporary()); |
| 511 if (args->at(i)->location().is_constant()) { | |
| 512 ASSERT(args->at(i)->AsLiteral() != NULL); | |
| 513 __ push(Immediate(args->at(i)->AsLiteral()->handle())); | |
| 514 } | |
| 515 } | 509 } |
| 516 // Record source position for debugger | 510 // Record source position for debugger |
| 517 SetSourcePosition(expr->position()); | 511 SetSourcePosition(expr->position()); |
| 518 // Call the IC initialization code. | 512 // Call the IC initialization code. |
| 519 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 513 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
| 520 NOT_IN_LOOP); | 514 NOT_IN_LOOP); |
| 521 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 515 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 522 // Restore context register. | 516 // Restore context register. |
| 523 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 517 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 524 // Discard the function left on TOS. | 518 // Discard the function left on TOS. |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 535 Comment cmnt(masm_, "[ CallRuntime"); | 529 Comment cmnt(masm_, "[ CallRuntime"); |
| 536 ZoneList<Expression*>* args = expr->arguments(); | 530 ZoneList<Expression*>* args = expr->arguments(); |
| 537 Runtime::Function* function = expr->function(); | 531 Runtime::Function* function = expr->function(); |
| 538 | 532 |
| 539 ASSERT(function != NULL); | 533 ASSERT(function != NULL); |
| 540 | 534 |
| 541 // Push the arguments ("left-to-right"). | 535 // Push the arguments ("left-to-right"). |
| 542 int arg_count = args->length(); | 536 int arg_count = args->length(); |
| 543 for (int i = 0; i < arg_count; i++) { | 537 for (int i = 0; i < arg_count; i++) { |
| 544 Visit(args->at(i)); | 538 Visit(args->at(i)); |
| 545 ASSERT(!args->at(i)->location().is_nowhere()); | 539 ASSERT(args->at(i)->location().is_temporary()); |
| 546 if (args->at(i)->location().is_constant()) { | |
| 547 ASSERT(args->at(i)->AsLiteral() != NULL); | |
| 548 __ push(Immediate(args->at(i)->AsLiteral()->handle())); | |
| 549 } else { | |
| 550 ASSERT(args->at(i)->location().is_temporary()); | |
| 551 // If location is temporary, it is already on the stack, | |
| 552 // so nothing to do here. | |
| 553 } | |
| 554 } | 540 } |
| 555 | 541 |
| 556 __ CallRuntime(function, arg_count); | 542 __ CallRuntime(function, arg_count); |
| 557 if (expr->location().is_temporary()) { | 543 if (expr->location().is_temporary()) { |
| 558 __ push(eax); | 544 __ push(eax); |
| 559 } else { | 545 } else { |
| 560 ASSERT(expr->location().is_nowhere()); | 546 ASSERT(expr->location().is_nowhere()); |
| 561 } | 547 } |
| 562 } | 548 } |
| 563 | 549 |
| 564 | 550 |
| 565 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 551 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
| 566 // Compile a short-circuited boolean or operation in a non-test | 552 // Compile a short-circuited boolean or operation in a non-test |
| 567 // context. | 553 // context. |
| 568 ASSERT(expr->op() == Token::OR); | 554 ASSERT(expr->op() == Token::OR); |
| 569 // Compile (e0 || e1) as if it were | 555 // Compile (e0 || e1) as if it were |
| 570 // (let (temp = e0) temp ? temp : e1). | 556 // (let (temp = e0) temp ? temp : e1). |
| 571 | 557 |
| 572 Label eval_right, done; | 558 Label eval_right, done; |
| 573 Location destination = expr->location(); | 559 Location destination = expr->location(); |
| 574 ASSERT(!destination.is_constant()); | 560 Expression* left = expr->left(); |
| 561 Expression* right = expr->right(); | |
| 575 | 562 |
| 576 Expression* left = expr->left(); | |
| 577 Location left_source = left->location(); | |
| 578 ASSERT(!left_source.is_nowhere()); | |
| 579 | |
| 580 Expression* right = expr->right(); | |
| 581 Location right_source = right->location(); | |
| 582 ASSERT(!right_source.is_nowhere()); | |
| 583 | |
| 584 Visit(left); | |
| 585 // Use the shared ToBoolean stub to find the boolean value of the | 563 // Use the shared ToBoolean stub to find the boolean value of the |
| 586 // left-hand subexpression. Load the value into eax to perform some | 564 // left-hand subexpression. Load the value into eax to perform some |
| 587 // inlined checks assumed by the stub. | 565 // inlined checks assumed by the stub. |
| 588 if (left_source.is_temporary()) { | 566 |
| 567 // Compile the left-hand value into eax. Put it on the stack if we may | |
| 568 // need it as the value of the whole expression. | |
| 569 if (left->AsLiteral() != NULL) { | |
| 570 __ mov(eax, left->AsLiteral()->handle()); | |
| 571 if (destination.is_temporary()) __ push(eax); | |
|
fschneider
2009/10/26 17:57:20
May want to add an assert here to be consistent wi
| |
| 572 } else { | |
| 573 Visit(left); | |
| 574 ASSERT(left->location().is_temporary()); | |
| 589 if (destination.is_temporary()) { | 575 if (destination.is_temporary()) { |
| 590 // Copy the left-hand value into eax because we may need it as the | 576 // Copy the left-hand value into eax because we may need it as the |
| 591 // final result. | 577 // final result. |
| 592 __ mov(eax, Operand(esp, 0)); | 578 __ mov(eax, Operand(esp, 0)); |
| 593 } else { | 579 } else { |
| 594 // Pop the left-hand value into eax because we will not need it as the | 580 // Pop the left-hand value into eax because we will not need it as the |
| 595 // final result. | 581 // final result. |
| 596 __ pop(eax); | 582 __ pop(eax); |
|
fschneider
2009/10/26 17:57:20
Adding an assert to be consistent on all platforms
| |
| 597 } | 583 } |
| 598 } else { | |
| 599 // Load the left-hand value into eax. Put it on the stack if we may | |
| 600 // need it. | |
| 601 ASSERT(left->AsLiteral() != NULL); | |
| 602 __ mov(eax, left->AsLiteral()->handle()); | |
| 603 if (destination.is_temporary()) __ push(eax); | |
| 604 } | 584 } |
| 605 // The left-hand value is in eax. It is also on the stack iff the | 585 // The left-hand value is in eax. It is also on the stack iff the |
| 606 // destination location is temporary. | 586 // destination location is temporary. |
| 607 | 587 |
| 608 // Perform fast checks assumed by the stub. | 588 // Perform fast checks assumed by the stub. |
| 609 __ cmp(eax, Factory::undefined_value()); // The undefined value is false. | 589 __ cmp(eax, Factory::undefined_value()); // The undefined value is false. |
| 610 __ j(equal, &eval_right); | 590 __ j(equal, &eval_right); |
| 611 __ cmp(eax, Factory::true_value()); // True is true. | 591 __ cmp(eax, Factory::true_value()); // True is true. |
| 612 __ j(equal, &done); | 592 __ j(equal, &done); |
| 613 __ cmp(eax, Factory::false_value()); // False is false. | 593 __ cmp(eax, Factory::false_value()); // False is false. |
| 614 __ j(equal, &eval_right); | 594 __ j(equal, &eval_right); |
| 615 ASSERT(kSmiTag == 0); | 595 ASSERT(kSmiTag == 0); |
| 616 __ test(eax, Operand(eax)); // The smi zero is false. | 596 __ test(eax, Operand(eax)); // The smi zero is false. |
| 617 __ j(zero, &eval_right); | 597 __ j(zero, &eval_right); |
| 618 __ test(eax, Immediate(kSmiTagMask)); // All other smis are true. | 598 __ test(eax, Immediate(kSmiTagMask)); // All other smis are true. |
| 619 __ j(zero, &done); | 599 __ j(zero, &done); |
| 620 | 600 |
| 621 // Call the stub for all other cases. | 601 // Call the stub for all other cases. |
| 622 __ push(eax); | 602 __ push(eax); |
| 623 ToBooleanStub stub; | 603 ToBooleanStub stub; |
| 624 __ CallStub(&stub); | 604 __ CallStub(&stub); |
| 625 __ test(eax, Operand(eax)); // The stub returns nonzero for true. | 605 __ test(eax, Operand(eax)); // The stub returns nonzero for true. |
| 626 __ j(not_zero, &done); | 606 __ j(not_zero, &done); |
| 627 | 607 |
| 628 __ bind(&eval_right); | 608 __ bind(&eval_right); |
| 629 // Discard the left-hand value if present on the stack. | 609 // Discard the left-hand value if present on the stack. |
| 630 if (destination.is_temporary()) { | 610 if (destination.is_temporary()) { |
| 631 __ add(Operand(esp), Immediate(kPointerSize)); | 611 __ add(Operand(esp), Immediate(kPointerSize)); |
| 632 } | 612 } |
| 633 Visit(right); | |
| 634 | |
| 635 // Save or discard the right-hand value as needed. | 613 // Save or discard the right-hand value as needed. |
| 636 if (destination.is_temporary() && right_source.is_constant()) { | 614 if (right->AsLiteral() != NULL) { |
| 637 ASSERT(right->AsLiteral() != NULL); | 615 if (destination.is_temporary()) { |
| 638 __ push(Immediate(right->AsLiteral()->handle())); | 616 __ push(Immediate(right->AsLiteral()->handle())); |
| 639 } else if (destination.is_nowhere() && right_source.is_temporary()) { | 617 } else { |
| 640 __ add(Operand(esp), Immediate(kPointerSize)); | 618 ASSERT(destination.is_nowhere()); |
| 619 } | |
| 620 } else { | |
| 621 Visit(right); | |
| 622 ASSERT(right->location().is_temporary()); | |
| 623 if (destination.is_nowhere()) { | |
| 624 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 625 } else { | |
| 626 ASSERT(destination.is_temporary()); | |
| 627 } | |
| 641 } | 628 } |
| 642 | 629 |
| 643 __ bind(&done); | 630 __ bind(&done); |
| 644 } | 631 } |
| 645 | 632 |
| 646 | 633 |
| 647 } } // namespace v8::internal | 634 } } // namespace v8::internal |
| OLD | NEW |