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 |