OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 // CodeGenerator implementation | 105 // CodeGenerator implementation |
106 | 106 |
107 CodeGenerator::CodeGenerator(MacroAssembler* masm) | 107 CodeGenerator::CodeGenerator(MacroAssembler* masm) |
108 : deferred_(8), | 108 : deferred_(8), |
109 masm_(masm), | 109 masm_(masm), |
110 info_(NULL), | 110 info_(NULL), |
111 frame_(NULL), | 111 frame_(NULL), |
112 allocator_(NULL), | 112 allocator_(NULL), |
113 state_(NULL), | 113 state_(NULL), |
114 loop_nesting_(0), | 114 loop_nesting_(0), |
| 115 in_safe_int32_mode_(false), |
| 116 safe_int32_mode_enabled_(true), |
115 function_return_is_shadowed_(false), | 117 function_return_is_shadowed_(false), |
116 in_spilled_code_(false) { | 118 in_spilled_code_(false) { |
117 } | 119 } |
118 | 120 |
119 | 121 |
120 // Calling conventions: | 122 // Calling conventions: |
121 // ebp: caller's frame pointer | 123 // ebp: caller's frame pointer |
122 // esp: stack pointer | 124 // esp: stack pointer |
123 // edi: called JS function | 125 // edi: called JS function |
124 // esi: callee's context | 126 // esi: callee's context |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 slow->Branch(not_equal, not_taken); | 432 slow->Branch(not_equal, not_taken); |
431 __ mov(tmp.reg(), ContextOperand(context, Context::FCONTEXT_INDEX)); | 433 __ mov(tmp.reg(), ContextOperand(context, Context::FCONTEXT_INDEX)); |
432 return ContextOperand(tmp.reg(), slot->index()); | 434 return ContextOperand(tmp.reg(), slot->index()); |
433 } | 435 } |
434 | 436 |
435 | 437 |
436 // Emit code to load the value of an expression to the top of the | 438 // Emit code to load the value of an expression to the top of the |
437 // frame. If the expression is boolean-valued it may be compiled (or | 439 // frame. If the expression is boolean-valued it may be compiled (or |
438 // partially compiled) into control flow to the control destination. | 440 // partially compiled) into control flow to the control destination. |
439 // If force_control is true, control flow is forced. | 441 // If force_control is true, control flow is forced. |
440 void CodeGenerator::LoadCondition(Expression* x, | 442 void CodeGenerator::LoadCondition(Expression* expr, |
441 ControlDestination* dest, | 443 ControlDestination* dest, |
442 bool force_control) { | 444 bool force_control) { |
443 ASSERT(!in_spilled_code()); | 445 ASSERT(!in_spilled_code()); |
444 int original_height = frame_->height(); | 446 int original_height = frame_->height(); |
445 | 447 |
446 { CodeGenState new_state(this, dest); | 448 { CodeGenState new_state(this, dest); |
447 Visit(x); | 449 Visit(expr); |
448 | 450 |
449 // If we hit a stack overflow, we may not have actually visited | 451 // If we hit a stack overflow, we may not have actually visited |
450 // the expression. In that case, we ensure that we have a | 452 // the expression. In that case, we ensure that we have a |
451 // valid-looking frame state because we will continue to generate | 453 // valid-looking frame state because we will continue to generate |
452 // code as we unwind the C++ stack. | 454 // code as we unwind the C++ stack. |
453 // | 455 // |
454 // It's possible to have both a stack overflow and a valid frame | 456 // It's possible to have both a stack overflow and a valid frame |
455 // state (eg, a subexpression overflowed, visiting it returned | 457 // state (eg, a subexpression overflowed, visiting it returned |
456 // with a dummied frame state, and visiting this expression | 458 // with a dummied frame state, and visiting this expression |
457 // returned with a normal-looking state). | 459 // returned with a normal-looking state). |
(...skipping 16 matching lines...) Expand all Loading... |
474 | 476 |
475 void CodeGenerator::LoadAndSpill(Expression* expression) { | 477 void CodeGenerator::LoadAndSpill(Expression* expression) { |
476 ASSERT(in_spilled_code()); | 478 ASSERT(in_spilled_code()); |
477 set_in_spilled_code(false); | 479 set_in_spilled_code(false); |
478 Load(expression); | 480 Load(expression); |
479 frame_->SpillAll(); | 481 frame_->SpillAll(); |
480 set_in_spilled_code(true); | 482 set_in_spilled_code(true); |
481 } | 483 } |
482 | 484 |
483 | 485 |
| 486 void CodeGenerator::LoadInSafeInt32Mode(Expression* expr, |
| 487 BreakTarget* unsafe_bailout) { |
| 488 set_unsafe_bailout(unsafe_bailout); |
| 489 set_in_safe_int32_mode(true); |
| 490 Load(expr); |
| 491 Result value = frame_->Pop(); |
| 492 ASSERT(frame_->HasNoUntaggedInt32Elements()); |
| 493 ConvertInt32ResultToNumber(&value); |
| 494 set_in_safe_int32_mode(false); |
| 495 set_unsafe_bailout(NULL); |
| 496 frame_->Push(&value); |
| 497 } |
| 498 |
| 499 |
| 500 void CodeGenerator::LoadWithSafeInt32ModeDisabled(Expression* expr) { |
| 501 set_safe_int32_mode_enabled(false); |
| 502 Load(expr); |
| 503 set_safe_int32_mode_enabled(true); |
| 504 } |
| 505 |
| 506 |
| 507 void CodeGenerator::ConvertInt32ResultToNumber(Result* value) { |
| 508 ASSERT(value->is_untagged_int32()); |
| 509 if (value->is_register()) { |
| 510 Register val = value->reg(); |
| 511 JumpTarget done; |
| 512 __ add(val, Operand(val)); |
| 513 done.Branch(no_overflow, value); |
| 514 __ sar(val, 1); |
| 515 // If there was an overflow, bits 30 and 31 of the original number disagree. |
| 516 __ xor_(val, 0x80000000u); |
| 517 if (CpuFeatures::IsSupported(SSE2)) { |
| 518 CpuFeatures::Scope fscope(SSE2); |
| 519 __ cvtsi2sd(xmm0, Operand(val)); |
| 520 } else { |
| 521 // Move val to ST[0] in the FPU |
| 522 // Push and pop are safe with respect to the virtual frame because |
| 523 // all synced elements are below the actual stack pointer. |
| 524 __ push(val); |
| 525 __ fild_s(Operand(esp, 0)); |
| 526 __ pop(val); |
| 527 } |
| 528 Result scratch = allocator_->Allocate(); |
| 529 ASSERT(scratch.is_register()); |
| 530 Label allocation_failed; |
| 531 __ AllocateHeapNumber(val, scratch.reg(), |
| 532 no_reg, &allocation_failed); |
| 533 VirtualFrame* clone = new VirtualFrame(frame_); |
| 534 scratch.Unuse(); |
| 535 if (CpuFeatures::IsSupported(SSE2)) { |
| 536 CpuFeatures::Scope fscope(SSE2); |
| 537 __ movdbl(FieldOperand(val, HeapNumber::kValueOffset), xmm0); |
| 538 } else { |
| 539 __ fstp_d(FieldOperand(val, HeapNumber::kValueOffset)); |
| 540 } |
| 541 done.Jump(value); |
| 542 |
| 543 // Establish the virtual frame, cloned from where AllocateHeapNumber |
| 544 // jumped to allocation_failed. |
| 545 RegisterFile empty_regs; |
| 546 SetFrame(clone, &empty_regs); |
| 547 __ bind(&allocation_failed); |
| 548 unsafe_bailout_->Jump(); |
| 549 |
| 550 done.Bind(value); |
| 551 } else { |
| 552 ASSERT(value->is_constant()); |
| 553 } |
| 554 value->set_untagged_int32(false); |
| 555 } |
| 556 |
| 557 |
484 void CodeGenerator::Load(Expression* expr) { | 558 void CodeGenerator::Load(Expression* expr) { |
485 #ifdef DEBUG | 559 #ifdef DEBUG |
486 int original_height = frame_->height(); | 560 int original_height = frame_->height(); |
487 #endif | 561 #endif |
488 ASSERT(!in_spilled_code()); | 562 ASSERT(!in_spilled_code()); |
489 JumpTarget true_target; | 563 JumpTarget done; |
490 JumpTarget false_target; | |
491 ControlDestination dest(&true_target, &false_target, true); | |
492 LoadCondition(expr, &dest, false); | |
493 | 564 |
494 if (dest.false_was_fall_through()) { | 565 // If the expression should be a side-effect-free 32-bit int computation, |
495 // The false target was just bound. | 566 // compile that SafeInt32 path, and a bailout path. |
496 JumpTarget loaded; | 567 if (!in_safe_int32_mode() && |
497 frame_->Push(Factory::false_value()); | 568 safe_int32_mode_enabled() && |
498 // There may be dangling jumps to the true target. | 569 expr->side_effect_free() && |
499 if (true_target.is_linked()) { | 570 expr->num_bit_ops() > 2 && |
500 loaded.Jump(); | 571 CpuFeatures::IsSupported(SSE2)) { |
501 true_target.Bind(); | 572 BreakTarget unsafe_bailout; |
502 frame_->Push(Factory::true_value()); | 573 unsafe_bailout.set_expected_height(frame_->height()); |
503 loaded.Bind(); | 574 LoadInSafeInt32Mode(expr, &unsafe_bailout); |
| 575 done.Jump(); |
| 576 |
| 577 if (unsafe_bailout.is_linked()) { |
| 578 unsafe_bailout.Bind(); |
| 579 LoadWithSafeInt32ModeDisabled(expr); |
504 } | 580 } |
| 581 } else { |
| 582 JumpTarget true_target; |
| 583 JumpTarget false_target; |
505 | 584 |
506 } else if (dest.is_used()) { | 585 ControlDestination dest(&true_target, &false_target, true); |
507 // There is true, and possibly false, control flow (with true as | 586 LoadCondition(expr, &dest, false); |
508 // the fall through). | 587 |
509 JumpTarget loaded; | 588 if (dest.false_was_fall_through()) { |
510 frame_->Push(Factory::true_value()); | 589 // The false target was just bound. |
511 if (false_target.is_linked()) { | 590 JumpTarget loaded; |
512 loaded.Jump(); | |
513 false_target.Bind(); | |
514 frame_->Push(Factory::false_value()); | 591 frame_->Push(Factory::false_value()); |
515 loaded.Bind(); | 592 // There may be dangling jumps to the true target. |
516 } | |
517 | |
518 } else { | |
519 // We have a valid value on top of the frame, but we still may | |
520 // have dangling jumps to the true and false targets from nested | |
521 // subexpressions (eg, the left subexpressions of the | |
522 // short-circuited boolean operators). | |
523 ASSERT(has_valid_frame()); | |
524 if (true_target.is_linked() || false_target.is_linked()) { | |
525 JumpTarget loaded; | |
526 loaded.Jump(); // Don't lose the current TOS. | |
527 if (true_target.is_linked()) { | 593 if (true_target.is_linked()) { |
| 594 loaded.Jump(); |
528 true_target.Bind(); | 595 true_target.Bind(); |
529 frame_->Push(Factory::true_value()); | 596 frame_->Push(Factory::true_value()); |
530 if (false_target.is_linked()) { | 597 loaded.Bind(); |
531 loaded.Jump(); | |
532 } | |
533 } | 598 } |
| 599 |
| 600 } else if (dest.is_used()) { |
| 601 // There is true, and possibly false, control flow (with true as |
| 602 // the fall through). |
| 603 JumpTarget loaded; |
| 604 frame_->Push(Factory::true_value()); |
534 if (false_target.is_linked()) { | 605 if (false_target.is_linked()) { |
| 606 loaded.Jump(); |
535 false_target.Bind(); | 607 false_target.Bind(); |
536 frame_->Push(Factory::false_value()); | 608 frame_->Push(Factory::false_value()); |
| 609 loaded.Bind(); |
537 } | 610 } |
538 loaded.Bind(); | 611 |
| 612 } else { |
| 613 // We have a valid value on top of the frame, but we still may |
| 614 // have dangling jumps to the true and false targets from nested |
| 615 // subexpressions (eg, the left subexpressions of the |
| 616 // short-circuited boolean operators). |
| 617 ASSERT(has_valid_frame()); |
| 618 if (true_target.is_linked() || false_target.is_linked()) { |
| 619 JumpTarget loaded; |
| 620 loaded.Jump(); // Don't lose the current TOS. |
| 621 if (true_target.is_linked()) { |
| 622 true_target.Bind(); |
| 623 frame_->Push(Factory::true_value()); |
| 624 if (false_target.is_linked()) { |
| 625 loaded.Jump(); |
| 626 } |
| 627 } |
| 628 if (false_target.is_linked()) { |
| 629 false_target.Bind(); |
| 630 frame_->Push(Factory::false_value()); |
| 631 } |
| 632 loaded.Bind(); |
| 633 } |
539 } | 634 } |
540 } | 635 } |
541 | 636 done.Bind(); |
542 ASSERT(has_valid_frame()); | 637 ASSERT(has_valid_frame()); |
543 ASSERT(frame_->height() == original_height + 1); | 638 ASSERT(frame_->height() == original_height + 1); |
544 } | 639 } |
545 | 640 |
546 | 641 |
547 void CodeGenerator::LoadGlobal() { | 642 void CodeGenerator::LoadGlobal() { |
548 if (in_spilled_code()) { | 643 if (in_spilled_code()) { |
549 frame_->EmitPush(GlobalObject()); | 644 frame_->EmitPush(GlobalObject()); |
550 } else { | 645 } else { |
551 Result temp = allocator_->Allocate(); | 646 Result temp = allocator_->Allocate(); |
(...skipping 3753 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4305 // object. | 4400 // object. |
4306 frame()->EmitPush(esi); | 4401 frame()->EmitPush(esi); |
4307 frame()->EmitPush(Immediate(boilerplate)); | 4402 frame()->EmitPush(Immediate(boilerplate)); |
4308 return frame()->CallRuntime(Runtime::kNewClosure, 2); | 4403 return frame()->CallRuntime(Runtime::kNewClosure, 2); |
4309 } | 4404 } |
4310 } | 4405 } |
4311 | 4406 |
4312 | 4407 |
4313 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 4408 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
4314 Comment cmnt(masm_, "[ FunctionLiteral"); | 4409 Comment cmnt(masm_, "[ FunctionLiteral"); |
4315 | 4410 ASSERT(!in_safe_int32_mode()); |
4316 // Build the function boilerplate and instantiate it. | 4411 // Build the function boilerplate and instantiate it. |
4317 Handle<JSFunction> boilerplate = | 4412 Handle<JSFunction> boilerplate = |
4318 Compiler::BuildBoilerplate(node, script(), this); | 4413 Compiler::BuildBoilerplate(node, script(), this); |
4319 // Check for stack-overflow exception. | 4414 // Check for stack-overflow exception. |
4320 if (HasStackOverflow()) return; | 4415 if (HasStackOverflow()) return; |
4321 Result result = InstantiateBoilerplate(boilerplate); | 4416 Result result = InstantiateBoilerplate(boilerplate); |
4322 frame()->Push(&result); | 4417 frame()->Push(&result); |
4323 } | 4418 } |
4324 | 4419 |
4325 | 4420 |
4326 void CodeGenerator::VisitFunctionBoilerplateLiteral( | 4421 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
4327 FunctionBoilerplateLiteral* node) { | 4422 FunctionBoilerplateLiteral* node) { |
| 4423 ASSERT(!in_safe_int32_mode()); |
4328 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 4424 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
4329 Result result = InstantiateBoilerplate(node->boilerplate()); | 4425 Result result = InstantiateBoilerplate(node->boilerplate()); |
4330 frame()->Push(&result); | 4426 frame()->Push(&result); |
4331 } | 4427 } |
4332 | 4428 |
4333 | 4429 |
4334 void CodeGenerator::VisitConditional(Conditional* node) { | 4430 void CodeGenerator::VisitConditional(Conditional* node) { |
4335 Comment cmnt(masm_, "[ Conditional"); | 4431 Comment cmnt(masm_, "[ Conditional"); |
| 4432 ASSERT(!in_safe_int32_mode()); |
4336 JumpTarget then; | 4433 JumpTarget then; |
4337 JumpTarget else_; | 4434 JumpTarget else_; |
4338 JumpTarget exit; | 4435 JumpTarget exit; |
4339 ControlDestination dest(&then, &else_, true); | 4436 ControlDestination dest(&then, &else_, true); |
4340 LoadCondition(node->condition(), &dest, true); | 4437 LoadCondition(node->condition(), &dest, true); |
4341 | 4438 |
4342 if (dest.false_was_fall_through()) { | 4439 if (dest.false_was_fall_through()) { |
4343 // The else target was bound, so we compile the else part first. | 4440 // The else target was bound, so we compile the else part first. |
4344 Load(node->else_expression()); | 4441 Load(node->else_expression()); |
4345 | 4442 |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4496 result = StoreArgumentsObject(false); | 4593 result = StoreArgumentsObject(false); |
4497 exit.Bind(&result); | 4594 exit.Bind(&result); |
4498 return result; | 4595 return result; |
4499 } | 4596 } |
4500 | 4597 |
4501 | 4598 |
4502 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( | 4599 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( |
4503 Slot* slot, | 4600 Slot* slot, |
4504 TypeofState typeof_state, | 4601 TypeofState typeof_state, |
4505 JumpTarget* slow) { | 4602 JumpTarget* slow) { |
| 4603 ASSERT(!in_safe_int32_mode()); |
4506 // Check that no extension objects have been created by calls to | 4604 // Check that no extension objects have been created by calls to |
4507 // eval from the current scope to the global scope. | 4605 // eval from the current scope to the global scope. |
4508 Register context = esi; | 4606 Register context = esi; |
4509 Result tmp = allocator_->Allocate(); | 4607 Result tmp = allocator_->Allocate(); |
4510 ASSERT(tmp.is_valid()); // All non-reserved registers were available. | 4608 ASSERT(tmp.is_valid()); // All non-reserved registers were available. |
4511 | 4609 |
4512 Scope* s = scope(); | 4610 Scope* s = scope(); |
4513 while (s != NULL) { | 4611 while (s != NULL) { |
4514 if (s->num_heap_slots() > 0) { | 4612 if (s->num_heap_slots() > 0) { |
4515 if (s->calls_eval()) { | 4613 if (s->calls_eval()) { |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4664 __ RecordWrite(start.reg(), offset, value.reg(), temp.reg()); | 4762 __ RecordWrite(start.reg(), offset, value.reg(), temp.reg()); |
4665 // The results start, value, and temp are unused by going out of | 4763 // The results start, value, and temp are unused by going out of |
4666 // scope. | 4764 // scope. |
4667 } | 4765 } |
4668 | 4766 |
4669 exit.Bind(); | 4767 exit.Bind(); |
4670 } | 4768 } |
4671 } | 4769 } |
4672 | 4770 |
4673 | 4771 |
4674 void CodeGenerator::VisitSlot(Slot* node) { | 4772 void CodeGenerator::VisitSlot(Slot* slot) { |
4675 Comment cmnt(masm_, "[ Slot"); | 4773 Comment cmnt(masm_, "[ Slot"); |
4676 Result result = LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF); | 4774 if (in_safe_int32_mode()) { |
4677 frame()->Push(&result); | 4775 if ((slot->type() == Slot::LOCAL && !slot->is_arguments())) { |
| 4776 frame()->UntaggedPushLocalAt(slot->index()); |
| 4777 } else if (slot->type() == Slot::PARAMETER) { |
| 4778 frame()->UntaggedPushParameterAt(slot->index()); |
| 4779 } else { |
| 4780 UNREACHABLE(); |
| 4781 } |
| 4782 } else { |
| 4783 Result result = LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); |
| 4784 frame()->Push(&result); |
| 4785 } |
4678 } | 4786 } |
4679 | 4787 |
4680 | 4788 |
4681 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 4789 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
4682 Comment cmnt(masm_, "[ VariableProxy"); | 4790 Comment cmnt(masm_, "[ VariableProxy"); |
4683 Variable* var = node->var(); | 4791 Variable* var = node->var(); |
4684 Expression* expr = var->rewrite(); | 4792 Expression* expr = var->rewrite(); |
4685 if (expr != NULL) { | 4793 if (expr != NULL) { |
4686 Visit(expr); | 4794 Visit(expr); |
4687 } else { | 4795 } else { |
4688 ASSERT(var->is_global()); | 4796 ASSERT(var->is_global()); |
| 4797 ASSERT(!in_safe_int32_mode()); |
4689 Reference ref(this, node); | 4798 Reference ref(this, node); |
4690 ref.GetValue(); | 4799 ref.GetValue(); |
4691 } | 4800 } |
4692 } | 4801 } |
4693 | 4802 |
4694 | 4803 |
4695 void CodeGenerator::VisitLiteral(Literal* node) { | 4804 void CodeGenerator::VisitLiteral(Literal* node) { |
4696 Comment cmnt(masm_, "[ Literal"); | 4805 Comment cmnt(masm_, "[ Literal"); |
4697 frame_->Push(node->handle()); | 4806 if (in_safe_int32_mode()) { |
| 4807 frame_->PushUntaggedElement(node->handle()); |
| 4808 } else { |
| 4809 frame_->Push(node->handle()); |
| 4810 } |
4698 } | 4811 } |
4699 | 4812 |
4700 | 4813 |
4701 void CodeGenerator::PushUnsafeSmi(Handle<Object> value) { | 4814 void CodeGenerator::PushUnsafeSmi(Handle<Object> value) { |
4702 ASSERT(value->IsSmi()); | 4815 ASSERT(value->IsSmi()); |
4703 int bits = reinterpret_cast<int>(*value); | 4816 int bits = reinterpret_cast<int>(*value); |
4704 __ push(Immediate(bits & 0x0000FFFF)); | 4817 __ push(Immediate(bits & 0x0000FFFF)); |
4705 __ or_(Operand(esp, 0), Immediate(bits & 0xFFFF0000)); | 4818 __ or_(Operand(esp, 0), Immediate(bits & 0xFFFF0000)); |
4706 } | 4819 } |
4707 | 4820 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4761 // RegExp pattern (2). | 4874 // RegExp pattern (2). |
4762 __ push(Immediate(node_->pattern())); | 4875 __ push(Immediate(node_->pattern())); |
4763 // RegExp flags (3). | 4876 // RegExp flags (3). |
4764 __ push(Immediate(node_->flags())); | 4877 __ push(Immediate(node_->flags())); |
4765 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 4878 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
4766 if (!boilerplate_.is(eax)) __ mov(boilerplate_, eax); | 4879 if (!boilerplate_.is(eax)) __ mov(boilerplate_, eax); |
4767 } | 4880 } |
4768 | 4881 |
4769 | 4882 |
4770 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 4883 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
| 4884 ASSERT(!in_safe_int32_mode()); |
4771 Comment cmnt(masm_, "[ RegExp Literal"); | 4885 Comment cmnt(masm_, "[ RegExp Literal"); |
4772 | 4886 |
4773 // Retrieve the literals array and check the allocated entry. Begin | 4887 // Retrieve the literals array and check the allocated entry. Begin |
4774 // with a writable copy of the function of this activation in a | 4888 // with a writable copy of the function of this activation in a |
4775 // register. | 4889 // register. |
4776 frame_->PushFunction(); | 4890 frame_->PushFunction(); |
4777 Result literals = frame_->Pop(); | 4891 Result literals = frame_->Pop(); |
4778 literals.ToRegister(); | 4892 literals.ToRegister(); |
4779 frame_->Spill(literals.reg()); | 4893 frame_->Spill(literals.reg()); |
4780 | 4894 |
(...skipping 16 matching lines...) Expand all Loading... |
4797 deferred->Branch(equal); | 4911 deferred->Branch(equal); |
4798 deferred->BindExit(); | 4912 deferred->BindExit(); |
4799 literals.Unuse(); | 4913 literals.Unuse(); |
4800 | 4914 |
4801 // Push the boilerplate object. | 4915 // Push the boilerplate object. |
4802 frame_->Push(&boilerplate); | 4916 frame_->Push(&boilerplate); |
4803 } | 4917 } |
4804 | 4918 |
4805 | 4919 |
4806 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 4920 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
| 4921 ASSERT(!in_safe_int32_mode()); |
4807 Comment cmnt(masm_, "[ ObjectLiteral"); | 4922 Comment cmnt(masm_, "[ ObjectLiteral"); |
4808 | 4923 |
4809 // Load a writable copy of the function of this activation in a | 4924 // Load a writable copy of the function of this activation in a |
4810 // register. | 4925 // register. |
4811 frame_->PushFunction(); | 4926 frame_->PushFunction(); |
4812 Result literals = frame_->Pop(); | 4927 Result literals = frame_->Pop(); |
4813 literals.ToRegister(); | 4928 literals.ToRegister(); |
4814 frame_->Spill(literals.reg()); | 4929 frame_->Spill(literals.reg()); |
4815 | 4930 |
4816 // Load the literals array of the function. | 4931 // Load the literals array of the function. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4881 // Ignore the result. | 4996 // Ignore the result. |
4882 break; | 4997 break; |
4883 } | 4998 } |
4884 default: UNREACHABLE(); | 4999 default: UNREACHABLE(); |
4885 } | 5000 } |
4886 } | 5001 } |
4887 } | 5002 } |
4888 | 5003 |
4889 | 5004 |
4890 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 5005 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
| 5006 ASSERT(!in_safe_int32_mode()); |
4891 Comment cmnt(masm_, "[ ArrayLiteral"); | 5007 Comment cmnt(masm_, "[ ArrayLiteral"); |
4892 | 5008 |
4893 // Load a writable copy of the function of this activation in a | 5009 // Load a writable copy of the function of this activation in a |
4894 // register. | 5010 // register. |
4895 frame_->PushFunction(); | 5011 frame_->PushFunction(); |
4896 Result literals = frame_->Pop(); | 5012 Result literals = frame_->Pop(); |
4897 literals.ToRegister(); | 5013 literals.ToRegister(); |
4898 frame_->Spill(literals.reg()); | 5014 frame_->Spill(literals.reg()); |
4899 | 5015 |
4900 // Load the literals array of the function. | 5016 // Load the literals array of the function. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4952 // Update the write barrier for the array address. | 5068 // Update the write barrier for the array address. |
4953 frame_->Spill(prop_value.reg()); // Overwritten by the write barrier. | 5069 frame_->Spill(prop_value.reg()); // Overwritten by the write barrier. |
4954 Result scratch = allocator_->Allocate(); | 5070 Result scratch = allocator_->Allocate(); |
4955 ASSERT(scratch.is_valid()); | 5071 ASSERT(scratch.is_valid()); |
4956 __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg()); | 5072 __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg()); |
4957 } | 5073 } |
4958 } | 5074 } |
4959 | 5075 |
4960 | 5076 |
4961 void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) { | 5077 void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) { |
| 5078 ASSERT(!in_safe_int32_mode()); |
4962 ASSERT(!in_spilled_code()); | 5079 ASSERT(!in_spilled_code()); |
4963 // Call runtime routine to allocate the catch extension object and | 5080 // Call runtime routine to allocate the catch extension object and |
4964 // assign the exception value to the catch variable. | 5081 // assign the exception value to the catch variable. |
4965 Comment cmnt(masm_, "[ CatchExtensionObject"); | 5082 Comment cmnt(masm_, "[ CatchExtensionObject"); |
4966 Load(node->key()); | 5083 Load(node->key()); |
4967 Load(node->value()); | 5084 Load(node->value()); |
4968 Result result = | 5085 Result result = |
4969 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2); | 5086 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2); |
4970 frame_->Push(&result); | 5087 frame_->Push(&result); |
4971 } | 5088 } |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5171 frame()->Push(&result); | 5288 frame()->Push(&result); |
5172 frame()->Push(&receiver); | 5289 frame()->Push(&receiver); |
5173 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); | 5290 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
5174 } | 5291 } |
5175 | 5292 |
5176 ASSERT(frame()->height() == original_height + 1); | 5293 ASSERT(frame()->height() == original_height + 1); |
5177 } | 5294 } |
5178 | 5295 |
5179 | 5296 |
5180 void CodeGenerator::VisitAssignment(Assignment* node) { | 5297 void CodeGenerator::VisitAssignment(Assignment* node) { |
| 5298 ASSERT(!in_safe_int32_mode()); |
5181 #ifdef DEBUG | 5299 #ifdef DEBUG |
5182 int original_height = frame()->height(); | 5300 int original_height = frame()->height(); |
5183 #endif | 5301 #endif |
5184 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 5302 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
5185 Property* prop = node->target()->AsProperty(); | 5303 Property* prop = node->target()->AsProperty(); |
5186 | 5304 |
5187 if (var != NULL && !var->is_global()) { | 5305 if (var != NULL && !var->is_global()) { |
5188 EmitSlotAssignment(node); | 5306 EmitSlotAssignment(node); |
5189 | 5307 |
5190 } else if ((prop != NULL && prop->key()->IsPropertyName()) || | 5308 } else if ((prop != NULL && prop->key()->IsPropertyName()) || |
(...skipping 15 matching lines...) Expand all Loading... |
5206 // The runtime call doesn't actually return but the code generator will | 5324 // The runtime call doesn't actually return but the code generator will |
5207 // still generate code and expects a certain frame height. | 5325 // still generate code and expects a certain frame height. |
5208 frame()->Push(&result); | 5326 frame()->Push(&result); |
5209 } | 5327 } |
5210 | 5328 |
5211 ASSERT(frame()->height() == original_height + 1); | 5329 ASSERT(frame()->height() == original_height + 1); |
5212 } | 5330 } |
5213 | 5331 |
5214 | 5332 |
5215 void CodeGenerator::VisitThrow(Throw* node) { | 5333 void CodeGenerator::VisitThrow(Throw* node) { |
| 5334 ASSERT(!in_safe_int32_mode()); |
5216 Comment cmnt(masm_, "[ Throw"); | 5335 Comment cmnt(masm_, "[ Throw"); |
5217 Load(node->exception()); | 5336 Load(node->exception()); |
5218 Result result = frame_->CallRuntime(Runtime::kThrow, 1); | 5337 Result result = frame_->CallRuntime(Runtime::kThrow, 1); |
5219 frame_->Push(&result); | 5338 frame_->Push(&result); |
5220 } | 5339 } |
5221 | 5340 |
5222 | 5341 |
5223 void CodeGenerator::VisitProperty(Property* node) { | 5342 void CodeGenerator::VisitProperty(Property* node) { |
| 5343 ASSERT(!in_safe_int32_mode()); |
5224 Comment cmnt(masm_, "[ Property"); | 5344 Comment cmnt(masm_, "[ Property"); |
5225 Reference property(this, node); | 5345 Reference property(this, node); |
5226 property.GetValue(); | 5346 property.GetValue(); |
5227 } | 5347 } |
5228 | 5348 |
5229 | 5349 |
5230 void CodeGenerator::VisitCall(Call* node) { | 5350 void CodeGenerator::VisitCall(Call* node) { |
| 5351 ASSERT(!in_safe_int32_mode()); |
5231 Comment cmnt(masm_, "[ Call"); | 5352 Comment cmnt(masm_, "[ Call"); |
5232 | 5353 |
5233 Expression* function = node->expression(); | 5354 Expression* function = node->expression(); |
5234 ZoneList<Expression*>* args = node->arguments(); | 5355 ZoneList<Expression*>* args = node->arguments(); |
5235 | 5356 |
5236 // Check if the function is a variable or a property. | 5357 // Check if the function is a variable or a property. |
5237 Variable* var = function->AsVariableProxy()->AsVariable(); | 5358 Variable* var = function->AsVariableProxy()->AsVariable(); |
5238 Property* property = function->AsProperty(); | 5359 Property* property = function->AsProperty(); |
5239 | 5360 |
5240 // ------------------------------------------------------------------------ | 5361 // ------------------------------------------------------------------------ |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5436 // Pass the global proxy as the receiver. | 5557 // Pass the global proxy as the receiver. |
5437 LoadGlobalReceiver(); | 5558 LoadGlobalReceiver(); |
5438 | 5559 |
5439 // Call the function. | 5560 // Call the function. |
5440 CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); | 5561 CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); |
5441 } | 5562 } |
5442 } | 5563 } |
5443 | 5564 |
5444 | 5565 |
5445 void CodeGenerator::VisitCallNew(CallNew* node) { | 5566 void CodeGenerator::VisitCallNew(CallNew* node) { |
| 5567 ASSERT(!in_safe_int32_mode()); |
5446 Comment cmnt(masm_, "[ CallNew"); | 5568 Comment cmnt(masm_, "[ CallNew"); |
5447 | 5569 |
5448 // According to ECMA-262, section 11.2.2, page 44, the function | 5570 // According to ECMA-262, section 11.2.2, page 44, the function |
5449 // expression in new calls must be evaluated before the | 5571 // expression in new calls must be evaluated before the |
5450 // arguments. This is different from ordinary calls, where the | 5572 // arguments. This is different from ordinary calls, where the |
5451 // actual function to call is resolved after the arguments have been | 5573 // actual function to call is resolved after the arguments have been |
5452 // evaluated. | 5574 // evaluated. |
5453 | 5575 |
5454 // Compute function to call and use the global object as the | 5576 // Compute function to call and use the global object as the |
5455 // receiver. There is no need to use the global proxy here because | 5577 // receiver. There is no need to use the global proxy here because |
(...skipping 907 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6363 __ bind(&runtime); | 6485 __ bind(&runtime); |
6364 result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); | 6486 result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); |
6365 | 6487 |
6366 end.Bind(&result); | 6488 end.Bind(&result); |
6367 frame()->Push(&result); | 6489 frame()->Push(&result); |
6368 } | 6490 } |
6369 } | 6491 } |
6370 | 6492 |
6371 | 6493 |
6372 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 6494 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 6495 ASSERT(!in_safe_int32_mode()); |
6373 if (CheckForInlineRuntimeCall(node)) { | 6496 if (CheckForInlineRuntimeCall(node)) { |
6374 return; | 6497 return; |
6375 } | 6498 } |
6376 | 6499 |
6377 ZoneList<Expression*>* args = node->arguments(); | 6500 ZoneList<Expression*>* args = node->arguments(); |
6378 Comment cmnt(masm_, "[ CallRuntime"); | 6501 Comment cmnt(masm_, "[ CallRuntime"); |
6379 Runtime::Function* function = node->function(); | 6502 Runtime::Function* function = node->function(); |
6380 | 6503 |
6381 if (function == NULL) { | 6504 if (function == NULL) { |
6382 // Push the builtins object found in the current global object. | 6505 // Push the builtins object found in the current global object. |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6489 expression->AsLiteral()->IsNull())) { | 6612 expression->AsLiteral()->IsNull())) { |
6490 // Omit evaluating the value of the primitive literal. | 6613 // Omit evaluating the value of the primitive literal. |
6491 // It will be discarded anyway, and can have no side effect. | 6614 // It will be discarded anyway, and can have no side effect. |
6492 frame_->Push(Factory::undefined_value()); | 6615 frame_->Push(Factory::undefined_value()); |
6493 } else { | 6616 } else { |
6494 Load(node->expression()); | 6617 Load(node->expression()); |
6495 frame_->SetElementAt(0, Factory::undefined_value()); | 6618 frame_->SetElementAt(0, Factory::undefined_value()); |
6496 } | 6619 } |
6497 | 6620 |
6498 } else { | 6621 } else { |
6499 Load(node->expression()); | 6622 if (in_safe_int32_mode()) { |
6500 bool overwrite = | 6623 Visit(node->expression()); |
6501 (node->expression()->AsBinaryOperation() != NULL && | 6624 Result value = frame_->Pop(); |
6502 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); | 6625 ASSERT(value.is_untagged_int32()); |
6503 switch (op) { | 6626 // Registers containing an int32 value are not multiply used. |
6504 case Token::SUB: { | 6627 ASSERT(!value.is_register() || !frame_->is_used(value.reg())); |
6505 GenericUnaryOpStub stub(Token::SUB, overwrite); | 6628 value.ToRegister(); |
6506 Result operand = frame_->Pop(); | 6629 switch (op) { |
6507 Result answer = frame_->CallStub(&stub, &operand); | 6630 case Token::SUB: { |
6508 frame_->Push(&answer); | 6631 __ neg(value.reg()); |
6509 break; | 6632 if (node->no_negative_zero()) { |
| 6633 // -MIN_INT is MIN_INT with the overflow flag set. |
| 6634 unsafe_bailout_->Branch(overflow); |
| 6635 } else { |
| 6636 // MIN_INT and 0 both have bad negations. They both have 31 zeros. |
| 6637 __ test(value.reg(), Immediate(0x7FFFFFFF)); |
| 6638 unsafe_bailout_->Branch(zero); |
| 6639 } |
| 6640 break; |
| 6641 } |
| 6642 case Token::BIT_NOT: { |
| 6643 __ not_(value.reg()); |
| 6644 break; |
| 6645 } |
| 6646 case Token::ADD: { |
| 6647 // Unary plus has no effect on int32 values. |
| 6648 break; |
| 6649 } |
| 6650 default: |
| 6651 UNREACHABLE(); |
| 6652 break; |
6510 } | 6653 } |
| 6654 frame_->Push(&value); |
6511 | 6655 |
6512 case Token::BIT_NOT: { | 6656 } else { |
6513 // Smi check. | 6657 Load(node->expression()); |
6514 JumpTarget smi_label; | 6658 bool overwrite = |
6515 JumpTarget continue_label; | 6659 (node->expression()->AsBinaryOperation() != NULL && |
6516 Result operand = frame_->Pop(); | 6660 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); |
6517 operand.ToRegister(); | 6661 switch (op) { |
6518 __ test(operand.reg(), Immediate(kSmiTagMask)); | 6662 case Token::SUB: { |
6519 smi_label.Branch(zero, &operand, taken); | 6663 GenericUnaryOpStub stub(Token::SUB, overwrite); |
| 6664 Result operand = frame_->Pop(); |
| 6665 Result answer = frame_->CallStub(&stub, &operand); |
| 6666 frame_->Push(&answer); |
| 6667 break; |
| 6668 } |
6520 | 6669 |
6521 GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); | 6670 case Token::BIT_NOT: { |
6522 Result answer = frame_->CallStub(&stub, &operand); | 6671 // Smi check. |
6523 continue_label.Jump(&answer); | 6672 JumpTarget smi_label; |
| 6673 JumpTarget continue_label; |
| 6674 Result operand = frame_->Pop(); |
| 6675 operand.ToRegister(); |
| 6676 __ test(operand.reg(), Immediate(kSmiTagMask)); |
| 6677 smi_label.Branch(zero, &operand, taken); |
6524 | 6678 |
6525 smi_label.Bind(&answer); | 6679 GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); |
6526 answer.ToRegister(); | 6680 Result answer = frame_->CallStub(&stub, &operand); |
6527 frame_->Spill(answer.reg()); | 6681 continue_label.Jump(&answer); |
6528 __ not_(answer.reg()); | |
6529 __ and_(answer.reg(), ~kSmiTagMask); // Remove inverted smi-tag. | |
6530 | 6682 |
6531 continue_label.Bind(&answer); | 6683 smi_label.Bind(&answer); |
6532 frame_->Push(&answer); | 6684 answer.ToRegister(); |
6533 break; | 6685 frame_->Spill(answer.reg()); |
6534 } | 6686 __ not_(answer.reg()); |
| 6687 __ and_(answer.reg(), ~kSmiTagMask); // Remove inverted smi-tag. |
6535 | 6688 |
6536 case Token::ADD: { | 6689 continue_label.Bind(&answer); |
6537 // Smi check. | 6690 frame_->Push(&answer); |
6538 JumpTarget continue_label; | 6691 break; |
6539 Result operand = frame_->Pop(); | 6692 } |
6540 operand.ToRegister(); | |
6541 __ test(operand.reg(), Immediate(kSmiTagMask)); | |
6542 continue_label.Branch(zero, &operand, taken); | |
6543 | 6693 |
6544 frame_->Push(&operand); | 6694 case Token::ADD: { |
6545 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, | 6695 // Smi check. |
| 6696 JumpTarget continue_label; |
| 6697 Result operand = frame_->Pop(); |
| 6698 operand.ToRegister(); |
| 6699 __ test(operand.reg(), Immediate(kSmiTagMask)); |
| 6700 continue_label.Branch(zero, &operand, taken); |
| 6701 |
| 6702 frame_->Push(&operand); |
| 6703 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, |
6546 CALL_FUNCTION, 1); | 6704 CALL_FUNCTION, 1); |
6547 | 6705 |
6548 continue_label.Bind(&answer); | 6706 continue_label.Bind(&answer); |
6549 frame_->Push(&answer); | 6707 frame_->Push(&answer); |
6550 break; | 6708 break; |
| 6709 } |
| 6710 |
| 6711 default: |
| 6712 // NOT, DELETE, TYPEOF, and VOID are handled outside the |
| 6713 // switch. |
| 6714 UNREACHABLE(); |
6551 } | 6715 } |
6552 | |
6553 default: | |
6554 // NOT, DELETE, TYPEOF, and VOID are handled outside the | |
6555 // switch. | |
6556 UNREACHABLE(); | |
6557 } | 6716 } |
6558 } | 6717 } |
6559 } | 6718 } |
6560 | 6719 |
6561 | 6720 |
6562 // The value in dst was optimistically incremented or decremented. The | 6721 // The value in dst was optimistically incremented or decremented. The |
6563 // result overflowed or was not smi tagged. Undo the operation, call | 6722 // result overflowed or was not smi tagged. Undo the operation, call |
6564 // into the runtime to convert the argument to a number, and call the | 6723 // into the runtime to convert the argument to a number, and call the |
6565 // specialized add or subtract stub. The result is left in dst. | 6724 // specialized add or subtract stub. The result is left in dst. |
6566 class DeferredPrefixCountOperation: public DeferredCode { | 6725 class DeferredPrefixCountOperation: public DeferredCode { |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6639 __ CallRuntime(Runtime::kNumberAdd, 2); | 6798 __ CallRuntime(Runtime::kNumberAdd, 2); |
6640 } else { | 6799 } else { |
6641 __ CallRuntime(Runtime::kNumberSub, 2); | 6800 __ CallRuntime(Runtime::kNumberSub, 2); |
6642 } | 6801 } |
6643 if (!dst_.is(eax)) __ mov(dst_, eax); | 6802 if (!dst_.is(eax)) __ mov(dst_, eax); |
6644 __ pop(old_); | 6803 __ pop(old_); |
6645 } | 6804 } |
6646 | 6805 |
6647 | 6806 |
6648 void CodeGenerator::VisitCountOperation(CountOperation* node) { | 6807 void CodeGenerator::VisitCountOperation(CountOperation* node) { |
| 6808 ASSERT(!in_safe_int32_mode()); |
6649 Comment cmnt(masm_, "[ CountOperation"); | 6809 Comment cmnt(masm_, "[ CountOperation"); |
6650 | 6810 |
6651 bool is_postfix = node->is_postfix(); | 6811 bool is_postfix = node->is_postfix(); |
6652 bool is_increment = node->op() == Token::INC; | 6812 bool is_increment = node->op() == Token::INC; |
6653 | 6813 |
6654 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 6814 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
6655 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 6815 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
6656 | 6816 |
6657 // Postfix operations need a stack slot under the reference to hold | 6817 // Postfix operations need a stack slot under the reference to hold |
6658 // the old value while the new value is being stored. This is so that | 6818 // the old value while the new value is being stored. This is so that |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6752 frame_->Push(&new_value); | 6912 frame_->Push(&new_value); |
6753 // Non-constant: update the reference. | 6913 // Non-constant: update the reference. |
6754 if (!is_const) target.SetValue(NOT_CONST_INIT); | 6914 if (!is_const) target.SetValue(NOT_CONST_INIT); |
6755 } | 6915 } |
6756 | 6916 |
6757 // Postfix: drop the new value and use the old. | 6917 // Postfix: drop the new value and use the old. |
6758 if (is_postfix) frame_->Drop(); | 6918 if (is_postfix) frame_->Drop(); |
6759 } | 6919 } |
6760 | 6920 |
6761 | 6921 |
| 6922 void CodeGenerator::Int32BinaryOperation(BinaryOperation* node) { |
| 6923 Token::Value op = node->op(); |
| 6924 Comment cmnt(masm_, "[ Int32BinaryOperation"); |
| 6925 ASSERT(in_safe_int32_mode()); |
| 6926 ASSERT(safe_int32_mode_enabled()); |
| 6927 ASSERT(FLAG_safe_int32_compiler); |
| 6928 |
| 6929 if (op == Token::COMMA) { |
| 6930 // Discard left value. |
| 6931 frame_->Nip(1); |
| 6932 return; |
| 6933 } |
| 6934 |
| 6935 Result right = frame_->Pop(); |
| 6936 Result left = frame_->Pop(); |
| 6937 |
| 6938 ASSERT(right.is_untagged_int32()); |
| 6939 ASSERT(left.is_untagged_int32()); |
| 6940 // Registers containing an int32 value are not multiply used. |
| 6941 ASSERT(!left.is_register() || !frame_->is_used(left.reg())); |
| 6942 ASSERT(!right.is_register() || !frame_->is_used(right.reg())); |
| 6943 |
| 6944 switch (op) { |
| 6945 case Token::COMMA: |
| 6946 case Token::OR: |
| 6947 case Token::AND: |
| 6948 UNREACHABLE(); |
| 6949 break; |
| 6950 case Token::BIT_OR: |
| 6951 case Token::BIT_XOR: |
| 6952 case Token::BIT_AND: |
| 6953 left.ToRegister(); |
| 6954 right.ToRegister(); |
| 6955 if (op == Token::BIT_OR) { |
| 6956 __ or_(left.reg(), Operand(right.reg())); |
| 6957 } else if (op == Token::BIT_XOR) { |
| 6958 __ xor_(left.reg(), Operand(right.reg())); |
| 6959 } else { |
| 6960 ASSERT(op == Token::BIT_AND); |
| 6961 __ and_(left.reg(), Operand(right.reg())); |
| 6962 } |
| 6963 frame_->Push(&left); |
| 6964 right.Unuse(); |
| 6965 break; |
| 6966 case Token::SAR: |
| 6967 case Token::SHL: |
| 6968 case Token::SHR: { |
| 6969 bool test_shr_overflow = false; |
| 6970 left.ToRegister(); |
| 6971 if (right.is_constant()) { |
| 6972 ASSERT(right.handle()->IsSmi() || right.handle()->IsHeapNumber()); |
| 6973 int shift_amount = NumberToInt32(*right.handle()) & 0x1F; |
| 6974 if (op == Token::SAR) { |
| 6975 __ sar(left.reg(), shift_amount); |
| 6976 } else if (op == Token::SHL) { |
| 6977 __ shl(left.reg(), shift_amount); |
| 6978 } else { |
| 6979 ASSERT(op == Token::SHR); |
| 6980 __ shr(left.reg(), shift_amount); |
| 6981 if (shift_amount == 0) test_shr_overflow = true; |
| 6982 } |
| 6983 } else { |
| 6984 // Move right to ecx |
| 6985 if (left.is_register() && left.reg().is(ecx)) { |
| 6986 right.ToRegister(); |
| 6987 __ xchg(left.reg(), right.reg()); |
| 6988 left = right; // Left is unused here, copy of right unused by Push. |
| 6989 } else { |
| 6990 right.ToRegister(ecx); |
| 6991 left.ToRegister(); |
| 6992 } |
| 6993 if (op == Token::SAR) { |
| 6994 __ sar_cl(left.reg()); |
| 6995 } else if (op == Token::SHL) { |
| 6996 __ shl_cl(left.reg()); |
| 6997 } else { |
| 6998 ASSERT(op == Token::SHR); |
| 6999 __ shr_cl(left.reg()); |
| 7000 test_shr_overflow = true; |
| 7001 } |
| 7002 } |
| 7003 { |
| 7004 Register left_reg = left.reg(); |
| 7005 frame_->Push(&left); |
| 7006 right.Unuse(); |
| 7007 if (test_shr_overflow && !node->to_int32()) { |
| 7008 // Uint32 results with top bit set are not Int32 values. |
| 7009 // If they will be forced to Int32, skip the test. |
| 7010 // Test is needed because shr with shift amount 0 does not set flags. |
| 7011 __ test(left_reg, Operand(left_reg)); |
| 7012 unsafe_bailout_->Branch(sign); |
| 7013 } |
| 7014 } |
| 7015 break; |
| 7016 } |
| 7017 case Token::ADD: |
| 7018 case Token::SUB: |
| 7019 case Token::MUL: |
| 7020 left.ToRegister(); |
| 7021 right.ToRegister(); |
| 7022 if (op == Token::ADD) { |
| 7023 __ add(left.reg(), Operand(right.reg())); |
| 7024 } else if (op == Token::SUB) { |
| 7025 __ sub(left.reg(), Operand(right.reg())); |
| 7026 } else { |
| 7027 ASSERT(op == Token::MUL); |
| 7028 // We have statically verified that a negative zero can be ignored. |
| 7029 __ imul(left.reg(), Operand(right.reg())); |
| 7030 } |
| 7031 right.Unuse(); |
| 7032 frame_->Push(&left); |
| 7033 if (!node->to_int32()) { |
| 7034 // If ToInt32 is called on the result of ADD, SUB, or MUL, we don't |
| 7035 // care about overflows. |
| 7036 unsafe_bailout_->Branch(overflow); |
| 7037 } |
| 7038 break; |
| 7039 case Token::DIV: |
| 7040 case Token::MOD: { |
| 7041 if (right.is_register() && (right.reg().is(eax) || right.reg().is(edx))) { |
| 7042 if (left.is_register() && left.reg().is(edi)) { |
| 7043 right.ToRegister(ebx); |
| 7044 } else { |
| 7045 right.ToRegister(edi); |
| 7046 } |
| 7047 } |
| 7048 left.ToRegister(eax); |
| 7049 Result edx_reg = allocator_->Allocate(edx); |
| 7050 right.ToRegister(); |
| 7051 // The results are unused here because BreakTarget::Branch cannot handle |
| 7052 // live results. |
| 7053 Register right_reg = right.reg(); |
| 7054 left.Unuse(); |
| 7055 right.Unuse(); |
| 7056 edx_reg.Unuse(); |
| 7057 __ cmp(right_reg, 0); |
| 7058 // Ensure divisor is positive: no chance of non-int32 or -0 result. |
| 7059 unsafe_bailout_->Branch(less_equal); |
| 7060 __ cdq(); // Sign-extend eax into edx:eax |
| 7061 __ idiv(right_reg); |
| 7062 if (op == Token::MOD) { |
| 7063 Result edx_result(edx, NumberInfo::Integer32()); |
| 7064 edx_result.set_untagged_int32(true); |
| 7065 frame_->Push(&edx_result); |
| 7066 } else { |
| 7067 ASSERT(op == Token::DIV); |
| 7068 __ test(edx, Operand(edx)); |
| 7069 unsafe_bailout_->Branch(not_equal); |
| 7070 Result eax_result(eax, NumberInfo::Integer32()); |
| 7071 eax_result.set_untagged_int32(true); |
| 7072 frame_->Push(&eax_result); |
| 7073 } |
| 7074 break; |
| 7075 } |
| 7076 default: |
| 7077 UNREACHABLE(); |
| 7078 break; |
| 7079 } |
| 7080 } |
| 7081 |
6762 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 7082 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
6763 Comment cmnt(masm_, "[ BinaryOperation"); | 7083 Comment cmnt(masm_, "[ BinaryOperation"); |
6764 Token::Value op = node->op(); | 7084 Token::Value op = node->op(); |
6765 | 7085 |
6766 // According to ECMA-262 section 11.11, page 58, the binary logical | 7086 // According to ECMA-262 section 11.11, page 58, the binary logical |
6767 // operators must yield the result of one of the two expressions | 7087 // operators must yield the result of one of the two expressions |
6768 // before any ToBoolean() conversions. This means that the value | 7088 // before any ToBoolean() conversions. This means that the value |
6769 // produced by a && or || operator is not necessarily a boolean. | 7089 // produced by a && or || operator is not necessarily a boolean. |
6770 | 7090 |
6771 // NOTE: If the left hand side produces a materialized value (not | 7091 // NOTE: If the left hand side produces a materialized value (not |
6772 // control flow), we force the right hand side to do the same. This | 7092 // control flow), we force the right hand side to do the same. This |
6773 // is necessary because we assume that if we get control flow on the | 7093 // is necessary because we assume that if we get control flow on the |
6774 // last path out of an expression we got it on all paths. | 7094 // last path out of an expression we got it on all paths. |
6775 if (op == Token::AND) { | 7095 if (op == Token::AND) { |
| 7096 ASSERT(!in_safe_int32_mode()); |
6776 JumpTarget is_true; | 7097 JumpTarget is_true; |
6777 ControlDestination dest(&is_true, destination()->false_target(), true); | 7098 ControlDestination dest(&is_true, destination()->false_target(), true); |
6778 LoadCondition(node->left(), &dest, false); | 7099 LoadCondition(node->left(), &dest, false); |
6779 | 7100 |
6780 if (dest.false_was_fall_through()) { | 7101 if (dest.false_was_fall_through()) { |
6781 // The current false target was used as the fall-through. If | 7102 // The current false target was used as the fall-through. If |
6782 // there are no dangling jumps to is_true then the left | 7103 // there are no dangling jumps to is_true then the left |
6783 // subexpression was unconditionally false. Otherwise we have | 7104 // subexpression was unconditionally false. Otherwise we have |
6784 // paths where we do have to evaluate the right subexpression. | 7105 // paths where we do have to evaluate the right subexpression. |
6785 if (is_true.is_linked()) { | 7106 if (is_true.is_linked()) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6829 | 7150 |
6830 // Compile right side expression. | 7151 // Compile right side expression. |
6831 is_true.Bind(); | 7152 is_true.Bind(); |
6832 Load(node->right()); | 7153 Load(node->right()); |
6833 | 7154 |
6834 // Exit (always with a materialized value). | 7155 // Exit (always with a materialized value). |
6835 exit.Bind(); | 7156 exit.Bind(); |
6836 } | 7157 } |
6837 | 7158 |
6838 } else if (op == Token::OR) { | 7159 } else if (op == Token::OR) { |
| 7160 ASSERT(!in_safe_int32_mode()); |
6839 JumpTarget is_false; | 7161 JumpTarget is_false; |
6840 ControlDestination dest(destination()->true_target(), &is_false, false); | 7162 ControlDestination dest(destination()->true_target(), &is_false, false); |
6841 LoadCondition(node->left(), &dest, false); | 7163 LoadCondition(node->left(), &dest, false); |
6842 | 7164 |
6843 if (dest.true_was_fall_through()) { | 7165 if (dest.true_was_fall_through()) { |
6844 // The current true target was used as the fall-through. If | 7166 // The current true target was used as the fall-through. If |
6845 // there are no dangling jumps to is_false then the left | 7167 // there are no dangling jumps to is_false then the left |
6846 // subexpression was unconditionally true. Otherwise we have | 7168 // subexpression was unconditionally true. Otherwise we have |
6847 // paths where we do have to evaluate the right subexpression. | 7169 // paths where we do have to evaluate the right subexpression. |
6848 if (is_false.is_linked()) { | 7170 if (is_false.is_linked()) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6890 frame_->Drop(); | 7212 frame_->Drop(); |
6891 | 7213 |
6892 // Compile right side expression. | 7214 // Compile right side expression. |
6893 is_false.Bind(); | 7215 is_false.Bind(); |
6894 Load(node->right()); | 7216 Load(node->right()); |
6895 | 7217 |
6896 // Exit (always with a materialized value). | 7218 // Exit (always with a materialized value). |
6897 exit.Bind(); | 7219 exit.Bind(); |
6898 } | 7220 } |
6899 | 7221 |
| 7222 } else if (in_safe_int32_mode()) { |
| 7223 Visit(node->left()); |
| 7224 Visit(node->right()); |
| 7225 Int32BinaryOperation(node); |
6900 } else { | 7226 } else { |
6901 // NOTE: The code below assumes that the slow cases (calls to runtime) | 7227 // NOTE: The code below assumes that the slow cases (calls to runtime) |
6902 // never return a constant/immutable object. | 7228 // never return a constant/immutable object. |
6903 OverwriteMode overwrite_mode = NO_OVERWRITE; | 7229 OverwriteMode overwrite_mode = NO_OVERWRITE; |
6904 if (node->left()->AsBinaryOperation() != NULL && | 7230 if (node->left()->AsBinaryOperation() != NULL && |
6905 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { | 7231 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { |
6906 overwrite_mode = OVERWRITE_LEFT; | 7232 overwrite_mode = OVERWRITE_LEFT; |
6907 } else if (node->right()->AsBinaryOperation() != NULL && | 7233 } else if (node->right()->AsBinaryOperation() != NULL && |
6908 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) { | 7234 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) { |
6909 overwrite_mode = OVERWRITE_RIGHT; | 7235 overwrite_mode = OVERWRITE_RIGHT; |
6910 } | 7236 } |
6911 | 7237 |
6912 if (node->left()->IsTrivial()) { | 7238 if (node->left()->IsTrivial()) { |
6913 Load(node->right()); | 7239 Load(node->right()); |
6914 Result right = frame_->Pop(); | 7240 Result right = frame_->Pop(); |
6915 frame_->Push(node->left()); | 7241 frame_->Push(node->left()); |
6916 frame_->Push(&right); | 7242 frame_->Push(&right); |
6917 } else { | 7243 } else { |
6918 Load(node->left()); | 7244 Load(node->left()); |
6919 Load(node->right()); | 7245 Load(node->right()); |
6920 } | 7246 } |
6921 GenericBinaryOperation(node->op(), node->type(), | 7247 GenericBinaryOperation(node->op(), node->type(), |
6922 overwrite_mode, node->no_negative_zero()); | 7248 overwrite_mode, node->no_negative_zero()); |
6923 } | 7249 } |
6924 } | 7250 } |
6925 | 7251 |
6926 | 7252 |
6927 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 7253 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 7254 ASSERT(!in_safe_int32_mode()); |
6928 frame_->PushFunction(); | 7255 frame_->PushFunction(); |
6929 } | 7256 } |
6930 | 7257 |
6931 | 7258 |
6932 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 7259 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| 7260 ASSERT(!in_safe_int32_mode()); |
6933 Comment cmnt(masm_, "[ CompareOperation"); | 7261 Comment cmnt(masm_, "[ CompareOperation"); |
6934 | 7262 |
6935 bool left_already_loaded = false; | 7263 bool left_already_loaded = false; |
6936 | 7264 |
6937 // Get the expressions from the node. | 7265 // Get the expressions from the node. |
6938 Expression* left = node->left(); | 7266 Expression* left = node->left(); |
6939 Expression* right = node->right(); | 7267 Expression* right = node->right(); |
6940 Token::Value op = node->op(); | 7268 Token::Value op = node->op(); |
6941 // To make typeof testing for natives implemented in JavaScript really | 7269 // To make typeof testing for natives implemented in JavaScript really |
6942 // efficient, we generate special code for expressions of the form: | 7270 // efficient, we generate special code for expressions of the form: |
(...skipping 4922 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11865 | 12193 |
11866 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 12194 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
11867 // tagged as a small integer. | 12195 // tagged as a small integer. |
11868 __ bind(&runtime); | 12196 __ bind(&runtime); |
11869 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 12197 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
11870 } | 12198 } |
11871 | 12199 |
11872 #undef __ | 12200 #undef __ |
11873 | 12201 |
11874 } } // namespace v8::internal | 12202 } } // namespace v8::internal |
OLD | NEW |