 Chromium Code Reviews
 Chromium Code Reviews Issue 2828004:
  ARM: Remove a bunch of spilled scopes.  Still a lot to go.  (Closed) 
  Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
    
  
    Issue 2828004:
  ARM: Remove a bunch of spilled scopes.  Still a lot to go.  (Closed) 
  Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/| 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 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 CodeGenerator::CodeGenerator(MacroAssembler* masm) | 150 CodeGenerator::CodeGenerator(MacroAssembler* masm) | 
| 151 : deferred_(8), | 151 : deferred_(8), | 
| 152 masm_(masm), | 152 masm_(masm), | 
| 153 info_(NULL), | 153 info_(NULL), | 
| 154 frame_(NULL), | 154 frame_(NULL), | 
| 155 allocator_(NULL), | 155 allocator_(NULL), | 
| 156 cc_reg_(al), | 156 cc_reg_(al), | 
| 157 state_(NULL), | 157 state_(NULL), | 
| 158 loop_nesting_(0), | 158 loop_nesting_(0), | 
| 159 type_info_(NULL), | 159 type_info_(NULL), | 
| 160 function_return_(JumpTarget::BIDIRECTIONAL), | |
| 160 function_return_is_shadowed_(false) { | 161 function_return_is_shadowed_(false) { | 
| 161 } | 162 } | 
| 162 | 163 | 
| 163 | 164 | 
| 164 // Calling conventions: | 165 // Calling conventions: | 
| 165 // fp: caller's frame pointer | 166 // fp: caller's frame pointer | 
| 166 // sp: stack pointer | 167 // sp: stack pointer | 
| 167 // r1: called JS function | 168 // r1: called JS function | 
| 168 // cp: callee's context | 169 // cp: callee's context | 
| 169 | 170 | 
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 211 #endif | 212 #endif | 
| 212 | 213 | 
| 213 if (info->mode() == CompilationInfo::PRIMARY) { | 214 if (info->mode() == CompilationInfo::PRIMARY) { | 
| 214 frame_->Enter(); | 215 frame_->Enter(); | 
| 215 // tos: code slot | 216 // tos: code slot | 
| 216 | 217 | 
| 217 // Allocate space for locals and initialize them. This also checks | 218 // Allocate space for locals and initialize them. This also checks | 
| 218 // for stack overflow. | 219 // for stack overflow. | 
| 219 frame_->AllocateStackSlots(); | 220 frame_->AllocateStackSlots(); | 
| 220 | 221 | 
| 221 VirtualFrame::SpilledScope spilled_scope(frame_); | 222 frame_->AssertIsSpilled(); | 
| 222 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 223 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 
| 223 if (heap_slots > 0) { | 224 if (heap_slots > 0) { | 
| 224 // Allocate local context. | 225 // Allocate local context. | 
| 225 // Get outer context and create a new context based on it. | 226 // Get outer context and create a new context based on it. | 
| 226 __ ldr(r0, frame_->Function()); | 227 __ ldr(r0, frame_->Function()); | 
| 227 frame_->EmitPush(r0); | 228 frame_->EmitPush(r0); | 
| 228 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 229 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 
| 229 FastNewContextStub stub(heap_slots); | 230 FastNewContextStub stub(heap_slots); | 
| 230 frame_->CallStub(&stub, 1); | 231 frame_->CallStub(&stub, 1); | 
| 231 } else { | 232 } else { | 
| (...skipping 18 matching lines...) Expand all Loading... | |
| 250 { | 251 { | 
| 251 Comment cmnt2(masm_, "[ copy context parameters into .context"); | 252 Comment cmnt2(masm_, "[ copy context parameters into .context"); | 
| 252 // Note that iteration order is relevant here! If we have the same | 253 // Note that iteration order is relevant here! If we have the same | 
| 253 // parameter twice (e.g., function (x, y, x)), and that parameter | 254 // parameter twice (e.g., function (x, y, x)), and that parameter | 
| 254 // needs to be copied into the context, it must be the last argument | 255 // needs to be copied into the context, it must be the last argument | 
| 255 // passed to the parameter that needs to be copied. This is a rare | 256 // passed to the parameter that needs to be copied. This is a rare | 
| 256 // case so we don't check for it, instead we rely on the copying | 257 // case so we don't check for it, instead we rely on the copying | 
| 257 // order: such a parameter is copied repeatedly into the same | 258 // order: such a parameter is copied repeatedly into the same | 
| 258 // context location and thus the last value is what is seen inside | 259 // context location and thus the last value is what is seen inside | 
| 259 // the function. | 260 // the function. | 
| 261 frame_->AssertIsSpilled(); | |
| 260 for (int i = 0; i < scope()->num_parameters(); i++) { | 262 for (int i = 0; i < scope()->num_parameters(); i++) { | 
| 261 Variable* par = scope()->parameter(i); | 263 Variable* par = scope()->parameter(i); | 
| 262 Slot* slot = par->slot(); | 264 Slot* slot = par->slot(); | 
| 263 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 265 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 
| 264 ASSERT(!scope()->is_global_scope()); // No params in global scope. | 266 ASSERT(!scope()->is_global_scope()); // No params in global scope. | 
| 265 __ ldr(r1, frame_->ParameterAt(i)); | 267 __ ldr(r1, frame_->ParameterAt(i)); | 
| 266 // Loads r2 with context; used below in RecordWrite. | 268 // Loads r2 with context; used below in RecordWrite. | 
| 267 __ str(r1, SlotOperand(slot, r2)); | 269 __ str(r1, SlotOperand(slot, r2)); | 
| 268 // Load the offset into r3. | 270 // Load the offset into r3. | 
| 269 int slot_offset = | 271 int slot_offset = | 
| 270 FixedArray::kHeaderSize + slot->index() * kPointerSize; | 272 FixedArray::kHeaderSize + slot->index() * kPointerSize; | 
| 271 __ mov(r3, Operand(slot_offset)); | 273 __ mov(r3, Operand(slot_offset)); | 
| 272 __ RecordWrite(r2, r3, r1); | 274 __ RecordWrite(r2, r3, r1); | 
| 273 } | 275 } | 
| 274 } | 276 } | 
| 275 } | 277 } | 
| 276 | 278 | 
| 277 // Store the arguments object. This must happen after context | 279 // Store the arguments object. This must happen after context | 
| 278 // initialization because the arguments object may be stored in | 280 // initialization because the arguments object may be stored in | 
| 279 // the context. | 281 // the context. | 
| 280 if (ArgumentsMode() != NO_ARGUMENTS_ALLOCATION) { | 282 if (ArgumentsMode() != NO_ARGUMENTS_ALLOCATION) { | 
| 281 StoreArgumentsObject(true); | 283 StoreArgumentsObject(true); | 
| 282 } | 284 } | 
| 283 | 285 | 
| 284 // Initialize ThisFunction reference if present. | 286 // Initialize ThisFunction reference if present. | 
| 285 if (scope()->is_function_scope() && scope()->function() != NULL) { | 287 if (scope()->is_function_scope() && scope()->function() != NULL) { | 
| 286 __ mov(ip, Operand(Factory::the_hole_value())); | 288 frame_->EmitPushRoot(Heap::kTheHoleValueRootIndex); | 
| 287 frame_->EmitPush(ip); | |
| 288 StoreToSlot(scope()->function()->slot(), NOT_CONST_INIT); | 289 StoreToSlot(scope()->function()->slot(), NOT_CONST_INIT); | 
| 289 } | 290 } | 
| 290 } else { | 291 } else { | 
| 291 // When used as the secondary compiler for splitting, r1, cp, | 292 // When used as the secondary compiler for splitting, r1, cp, | 
| 292 // fp, and lr have been pushed on the stack. Adjust the virtual | 293 // fp, and lr have been pushed on the stack. Adjust the virtual | 
| 293 // frame to match this state. | 294 // frame to match this state. | 
| 294 frame_->Adjust(4); | 295 frame_->Adjust(4); | 
| 295 | 296 | 
| 296 // Bind all the bailout labels to the beginning of the function. | 297 // Bind all the bailout labels to the beginning of the function. | 
| 297 List<CompilationInfo::Bailout*>* bailouts = info->bailouts(); | 298 List<CompilationInfo::Bailout*>* bailouts = info->bailouts(); | 
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 504 // code as we unwind the C++ stack. | 505 // code as we unwind the C++ stack. | 
| 505 // | 506 // | 
| 506 // It's possible to have both a stack overflow and a valid frame | 507 // It's possible to have both a stack overflow and a valid frame | 
| 507 // state (eg, a subexpression overflowed, visiting it returned | 508 // state (eg, a subexpression overflowed, visiting it returned | 
| 508 // with a dummied frame state, and visiting this expression | 509 // with a dummied frame state, and visiting this expression | 
| 509 // returned with a normal-looking state). | 510 // returned with a normal-looking state). | 
| 510 if (HasStackOverflow() && | 511 if (HasStackOverflow() && | 
| 511 has_valid_frame() && | 512 has_valid_frame() && | 
| 512 !has_cc() && | 513 !has_cc() && | 
| 513 frame_->height() == original_height) { | 514 frame_->height() == original_height) { | 
| 514 frame_->SpillAll(); | |
| 515 true_target->Jump(); | 515 true_target->Jump(); | 
| 516 } | 516 } | 
| 517 } | 517 } | 
| 518 if (force_cc && frame_ != NULL && !has_cc()) { | 518 if (force_cc && frame_ != NULL && !has_cc()) { | 
| 519 // Convert the TOS value to a boolean in the condition code register. | 519 // Convert the TOS value to a boolean in the condition code register. | 
| 520 ToBoolean(true_target, false_target); | 520 ToBoolean(true_target, false_target); | 
| 521 } | 521 } | 
| 522 ASSERT(!force_cc || !has_valid_frame() || has_cc()); | 522 ASSERT(!force_cc || !has_valid_frame() || has_cc()); | 
| 523 ASSERT(!has_valid_frame() || | 523 ASSERT(!has_valid_frame() || | 
| 524 (has_cc() && frame_->height() == original_height) || | 524 (has_cc() && frame_->height() == original_height) || | 
| 525 (!has_cc() && frame_->height() == original_height + 1)); | 525 (!has_cc() && frame_->height() == original_height + 1)); | 
| 526 } | 526 } | 
| 527 | 527 | 
| 528 | 528 | 
| 529 void CodeGenerator::Load(Expression* expr) { | 529 void CodeGenerator::Load(Expression* expr) { | 
| 530 #ifdef DEBUG | 530 #ifdef DEBUG | 
| 531 int original_height = frame_->height(); | 531 int original_height = frame_->height(); | 
| 532 #endif | 532 #endif | 
| 533 JumpTarget true_target; | 533 JumpTarget true_target; | 
| 534 JumpTarget false_target; | 534 JumpTarget false_target; | 
| 535 LoadCondition(expr, &true_target, &false_target, false); | 535 LoadCondition(expr, &true_target, &false_target, false); | 
| 536 | 536 | 
| 537 if (has_cc()) { | 537 if (has_cc()) { | 
| 538 // Convert cc_reg_ into a boolean value. | 538 // Convert cc_reg_ into a boolean value. | 
| 539 VirtualFrame::SpilledScope scope(frame_); | |
| 540 JumpTarget loaded; | 539 JumpTarget loaded; | 
| 541 JumpTarget materialize_true; | 540 JumpTarget materialize_true; | 
| 542 materialize_true.Branch(cc_reg_); | 541 materialize_true.Branch(cc_reg_); | 
| 543 __ LoadRoot(r0, Heap::kFalseValueRootIndex); | 542 __ LoadRoot(r0, Heap::kFalseValueRootIndex); | 
| 544 frame_->EmitPush(r0); | 543 frame_->EmitPushRoot(Heap::kFalseValueRootIndex); | 
| 545 loaded.Jump(); | 544 loaded.Jump(); | 
| 546 materialize_true.Bind(); | 545 materialize_true.Bind(); | 
| 547 __ LoadRoot(r0, Heap::kTrueValueRootIndex); | 546 frame_->EmitPushRoot(Heap::kTrueValueRootIndex); | 
| 548 frame_->EmitPush(r0); | |
| 549 loaded.Bind(); | 547 loaded.Bind(); | 
| 550 cc_reg_ = al; | 548 cc_reg_ = al; | 
| 551 } | 549 } | 
| 552 | 550 | 
| 553 if (true_target.is_linked() || false_target.is_linked()) { | 551 if (true_target.is_linked() || false_target.is_linked()) { | 
| 554 VirtualFrame::SpilledScope scope(frame_); | |
| 555 // We have at least one condition value that has been "translated" | 552 // We have at least one condition value that has been "translated" | 
| 556 // into a branch, thus it needs to be loaded explicitly. | 553 // into a branch, thus it needs to be loaded explicitly. | 
| 557 JumpTarget loaded; | 554 JumpTarget loaded; | 
| 558 if (frame_ != NULL) { | 555 if (frame_ != NULL) { | 
| 559 loaded.Jump(); // Don't lose the current TOS. | 556 loaded.Jump(); // Don't lose the current TOS. | 
| 560 } | 557 } | 
| 561 bool both = true_target.is_linked() && false_target.is_linked(); | 558 bool both = true_target.is_linked() && false_target.is_linked(); | 
| 562 // Load "true" if necessary. | 559 // Load "true" if necessary. | 
| 563 if (true_target.is_linked()) { | 560 if (true_target.is_linked()) { | 
| 564 true_target.Bind(); | 561 true_target.Bind(); | 
| 565 __ LoadRoot(r0, Heap::kTrueValueRootIndex); | 562 frame_->EmitPushRoot(Heap::kTrueValueRootIndex); | 
| 566 frame_->EmitPush(r0); | |
| 567 } | 563 } | 
| 568 // If both "true" and "false" need to be loaded jump across the code for | 564 // If both "true" and "false" need to be loaded jump across the code for | 
| 569 // "false". | 565 // "false". | 
| 570 if (both) { | 566 if (both) { | 
| 571 loaded.Jump(); | 567 loaded.Jump(); | 
| 572 } | 568 } | 
| 573 // Load "false" if necessary. | 569 // Load "false" if necessary. | 
| 574 if (false_target.is_linked()) { | 570 if (false_target.is_linked()) { | 
| 575 false_target.Bind(); | 571 false_target.Bind(); | 
| 576 __ LoadRoot(r0, Heap::kFalseValueRootIndex); | 572 frame_->EmitPushRoot(Heap::kFalseValueRootIndex); | 
| 577 frame_->EmitPush(r0); | |
| 578 } | 573 } | 
| 579 // A value is loaded on all paths reaching this point. | 574 // A value is loaded on all paths reaching this point. | 
| 580 loaded.Bind(); | 575 loaded.Bind(); | 
| 581 } | 576 } | 
| 582 ASSERT(has_valid_frame()); | 577 ASSERT(has_valid_frame()); | 
| 583 ASSERT(!has_cc()); | 578 ASSERT(!has_cc()); | 
| 584 ASSERT_EQ(original_height + 1, frame_->height()); | 579 ASSERT_EQ(original_height + 1, frame_->height()); | 
| 585 } | 580 } | 
| 586 | 581 | 
| 587 | 582 | 
| 588 void CodeGenerator::LoadGlobal() { | 583 void CodeGenerator::LoadGlobal() { | 
| 589 Register reg = frame_->GetTOSRegister(); | 584 Register reg = frame_->GetTOSRegister(); | 
| 590 __ ldr(reg, GlobalObject()); | 585 __ ldr(reg, GlobalObject()); | 
| 591 frame_->EmitPush(reg); | 586 frame_->EmitPush(reg); | 
| 592 } | 587 } | 
| 593 | 588 | 
| 594 | 589 | 
| 595 void CodeGenerator::LoadGlobalReceiver(Register scratch) { | 590 void CodeGenerator::LoadGlobalReceiver(Register scratch) { | 
| 
Søren Thygesen Gjesse
2010/06/15 10:29:56
scratch is not used anymore.
 | |
| 596 VirtualFrame::SpilledScope spilled_scope(frame_); | 591 Register reg = frame_->GetTOSRegister(); | 
| 597 __ ldr(scratch, ContextOperand(cp, Context::GLOBAL_INDEX)); | 592 __ ldr(reg, ContextOperand(cp, Context::GLOBAL_INDEX)); | 
| 598 __ ldr(scratch, | 593 __ ldr(reg, | 
| 599 FieldMemOperand(scratch, GlobalObject::kGlobalReceiverOffset)); | 594 FieldMemOperand(reg, GlobalObject::kGlobalReceiverOffset)); | 
| 600 frame_->EmitPush(scratch); | 595 frame_->EmitPush(reg); | 
| 601 } | 596 } | 
| 602 | 597 | 
| 603 | 598 | 
| 604 ArgumentsAllocationMode CodeGenerator::ArgumentsMode() { | 599 ArgumentsAllocationMode CodeGenerator::ArgumentsMode() { | 
| 605 if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; | 600 if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; | 
| 606 ASSERT(scope()->arguments_shadow() != NULL); | 601 ASSERT(scope()->arguments_shadow() != NULL); | 
| 607 // We don't want to do lazy arguments allocation for functions that | 602 // We don't want to do lazy arguments allocation for functions that | 
| 608 // have heap-allocated contexts, because it interfers with the | 603 // have heap-allocated contexts, because it interfers with the | 
| 609 // uninitialized const tracking in the context objects. | 604 // uninitialized const tracking in the context objects. | 
| 610 return (scope()->num_heap_slots() > 0) | 605 return (scope()->num_heap_slots() > 0) | 
| 611 ? EAGER_ARGUMENTS_ALLOCATION | 606 ? EAGER_ARGUMENTS_ALLOCATION | 
| 612 : LAZY_ARGUMENTS_ALLOCATION; | 607 : LAZY_ARGUMENTS_ALLOCATION; | 
| 613 } | 608 } | 
| 614 | 609 | 
| 615 | 610 | 
| 616 void CodeGenerator::StoreArgumentsObject(bool initial) { | 611 void CodeGenerator::StoreArgumentsObject(bool initial) { | 
| 617 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 618 | |
| 619 ArgumentsAllocationMode mode = ArgumentsMode(); | 612 ArgumentsAllocationMode mode = ArgumentsMode(); | 
| 620 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); | 613 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); | 
| 621 | 614 | 
| 622 Comment cmnt(masm_, "[ store arguments object"); | 615 Comment cmnt(masm_, "[ store arguments object"); | 
| 623 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { | 616 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { | 
| 624 // When using lazy arguments allocation, we store the hole value | 617 // When using lazy arguments allocation, we store the hole value | 
| 625 // as a sentinel indicating that the arguments object hasn't been | 618 // as a sentinel indicating that the arguments object hasn't been | 
| 626 // allocated yet. | 619 // allocated yet. | 
| 627 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 620 frame_->EmitPushRoot(Heap::kTheHoleValueRootIndex); | 
| 628 frame_->EmitPush(ip); | |
| 629 } else { | 621 } else { | 
| 622 frame_->SpillAll(); | |
| 630 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 623 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 
| 631 __ ldr(r2, frame_->Function()); | 624 __ ldr(r2, frame_->Function()); | 
| 632 // The receiver is below the arguments, the return address, and the | 625 // The receiver is below the arguments, the return address, and the | 
| 633 // frame pointer on the stack. | 626 // frame pointer on the stack. | 
| 634 const int kReceiverDisplacement = 2 + scope()->num_parameters(); | 627 const int kReceiverDisplacement = 2 + scope()->num_parameters(); | 
| 635 __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize)); | 628 __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize)); | 
| 636 __ mov(r0, Operand(Smi::FromInt(scope()->num_parameters()))); | 629 __ mov(r0, Operand(Smi::FromInt(scope()->num_parameters()))); | 
| 637 frame_->Adjust(3); | 630 frame_->Adjust(3); | 
| 638 __ Push(r2, r1, r0); | 631 __ Push(r2, r1, r0); | 
| 639 frame_->CallStub(&stub, 3); | 632 frame_->CallStub(&stub, 3); | 
| 640 frame_->EmitPush(r0); | 633 frame_->EmitPush(r0); | 
| 641 } | 634 } | 
| 642 | 635 | 
| 643 Variable* arguments = scope()->arguments()->var(); | 636 Variable* arguments = scope()->arguments()->var(); | 
| 644 Variable* shadow = scope()->arguments_shadow()->var(); | 637 Variable* shadow = scope()->arguments_shadow()->var(); | 
| 645 ASSERT(arguments != NULL && arguments->slot() != NULL); | 638 ASSERT(arguments != NULL && arguments->slot() != NULL); | 
| 646 ASSERT(shadow != NULL && shadow->slot() != NULL); | 639 ASSERT(shadow != NULL && shadow->slot() != NULL); | 
| 647 JumpTarget done; | 640 JumpTarget done; | 
| 648 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { | 641 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { | 
| 649 // We have to skip storing into the arguments slot if it has | 642 // We have to skip storing into the arguments slot if it has | 
| 650 // already been written to. This can happen if the a function | 643 // already been written to. This can happen if the a function | 
| 651 // has a local variable named 'arguments'. | 644 // has a local variable named 'arguments'. | 
| 652 LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); | 645 LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); | 
| 653 frame_->EmitPop(r0); | 646 Register arguments = frame_->PopToRegister(); | 
| 654 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 647 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 
| 655 __ cmp(r0, ip); | 648 __ cmp(arguments, ip); | 
| 656 done.Branch(ne); | 649 done.Branch(ne); | 
| 657 } | 650 } | 
| 658 StoreToSlot(arguments->slot(), NOT_CONST_INIT); | 651 StoreToSlot(arguments->slot(), NOT_CONST_INIT); | 
| 659 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); | 652 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); | 
| 660 StoreToSlot(shadow->slot(), NOT_CONST_INIT); | 653 StoreToSlot(shadow->slot(), NOT_CONST_INIT); | 
| 661 } | 654 } | 
| 662 | 655 | 
| 663 | 656 | 
| 664 void CodeGenerator::LoadTypeofExpression(Expression* expr) { | 657 void CodeGenerator::LoadTypeofExpression(Expression* expr) { | 
| 665 // Special handling of identifiers as subexpressions of typeof. | 658 // Special handling of identifiers as subexpressions of typeof. | 
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 748 frame_->EmitPush(tos); | 741 frame_->EmitPush(tos); | 
| 749 } | 742 } | 
| 750 } | 743 } | 
| 751 | 744 | 
| 752 | 745 | 
| 753 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given | 746 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given | 
| 754 // register to a boolean in the condition code register. The code | 747 // register to a boolean in the condition code register. The code | 
| 755 // may jump to 'false_target' in case the register converts to 'false'. | 748 // may jump to 'false_target' in case the register converts to 'false'. | 
| 756 void CodeGenerator::ToBoolean(JumpTarget* true_target, | 749 void CodeGenerator::ToBoolean(JumpTarget* true_target, | 
| 757 JumpTarget* false_target) { | 750 JumpTarget* false_target) { | 
| 758 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 759 // Note: The generated code snippet does not change stack variables. | 751 // Note: The generated code snippet does not change stack variables. | 
| 760 // Only the condition code should be set. | 752 // Only the condition code should be set. | 
| 761 frame_->EmitPop(r0); | 753 Register tos = frame_->PopToRegister(); | 
| 762 | 754 | 
| 763 // Fast case checks | 755 // Fast case checks | 
| 764 | 756 | 
| 765 // Check if the value is 'false'. | 757 // Check if the value is 'false'. | 
| 766 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 758 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 
| 767 __ cmp(r0, ip); | 759 __ cmp(tos, ip); | 
| 768 false_target->Branch(eq); | 760 false_target->Branch(eq); | 
| 769 | 761 | 
| 770 // Check if the value is 'true'. | 762 // Check if the value is 'true'. | 
| 771 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 763 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 
| 772 __ cmp(r0, ip); | 764 __ cmp(tos, ip); | 
| 773 true_target->Branch(eq); | 765 true_target->Branch(eq); | 
| 774 | 766 | 
| 775 // Check if the value is 'undefined'. | 767 // Check if the value is 'undefined'. | 
| 776 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 768 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 
| 777 __ cmp(r0, ip); | 769 __ cmp(tos, ip); | 
| 778 false_target->Branch(eq); | 770 false_target->Branch(eq); | 
| 779 | 771 | 
| 780 // Check if the value is a smi. | 772 // Check if the value is a smi. | 
| 781 __ cmp(r0, Operand(Smi::FromInt(0))); | 773 __ cmp(tos, Operand(Smi::FromInt(0))); | 
| 782 false_target->Branch(eq); | 774 false_target->Branch(eq); | 
| 783 __ tst(r0, Operand(kSmiTagMask)); | 775 __ tst(tos, Operand(kSmiTagMask)); | 
| 784 true_target->Branch(eq); | 776 true_target->Branch(eq); | 
| 785 | 777 | 
| 786 // Slow case: call the runtime. | 778 // Slow case: call the runtime. | 
| 787 frame_->EmitPush(r0); | 779 frame_->EmitPush(tos); | 
| 788 frame_->CallRuntime(Runtime::kToBool, 1); | 780 frame_->CallRuntime(Runtime::kToBool, 1); | 
| 789 // Convert the result (r0) to a condition code. | 781 // Convert the result (r0) to a condition code. | 
| 790 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 782 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 
| 791 __ cmp(r0, ip); | 783 __ cmp(r0, ip); | 
| 792 | 784 | 
| 793 cc_reg_ = ne; | 785 cc_reg_ = ne; | 
| 794 } | 786 } | 
| 795 | 787 | 
| 796 | 788 | 
| 797 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 789 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 929 | 921 | 
| 930 private: | 922 private: | 
| 931 Token::Value op_; | 923 Token::Value op_; | 
| 932 int value_; | 924 int value_; | 
| 933 bool reversed_; | 925 bool reversed_; | 
| 934 OverwriteMode overwrite_mode_; | 926 OverwriteMode overwrite_mode_; | 
| 935 Register tos_register_; | 927 Register tos_register_; | 
| 936 }; | 928 }; | 
| 937 | 929 | 
| 938 | 930 | 
| 931 | |
| 932 // On entry the non-constant side of the binary operation is in tos_register_ | |
| 
Søren Thygesen Gjesse
2010/06/15 10:29:56
Doesn't tos contain the result of performing the o
 | |
| 933 // and the constant smi side is nowhere. The tos_register_ is not used by the | |
| 934 // virtual frame. On exit the answer is in the tos_register_ and the virtual | |
| 935 // frame is unchanged. | |
| 939 void DeferredInlineSmiOperation::Generate() { | 936 void DeferredInlineSmiOperation::Generate() { | 
| 937 VirtualFrame copied_frame(*frame_state()->frame()); | |
| 938 copied_frame.SpillAll(); | |
| 939 | |
| 940 Register lhs = r1; | 940 Register lhs = r1; | 
| 941 Register rhs = r0; | 941 Register rhs = r0; | 
| 942 switch (op_) { | 942 switch (op_) { | 
| 943 case Token::ADD: { | 943 case Token::ADD: { | 
| 944 // Revert optimistic add. | 944 // Revert optimistic add. | 
| 945 if (reversed_) { | 945 if (reversed_) { | 
| 946 __ sub(r0, tos_register_, Operand(Smi::FromInt(value_))); | 946 __ sub(r0, tos_register_, Operand(Smi::FromInt(value_))); | 
| 947 __ mov(r1, Operand(Smi::FromInt(value_))); | 947 __ mov(r1, Operand(Smi::FromInt(value_))); | 
| 948 } else { | 948 } else { | 
| 949 __ sub(r1, tos_register_, Operand(Smi::FromInt(value_))); | 949 __ sub(r1, tos_register_, Operand(Smi::FromInt(value_))); | 
| 
Søren Thygesen Gjesse
2010/06/15 10:29:56
Why does r0 not need to be loaded with value_?
 | |
| 950 __ mov(r0, Operand(Smi::FromInt(value_))); | 950 __ mov(r0, Operand(Smi::FromInt(value_))); | 
| 951 } | 951 } | 
| 952 break; | 952 break; | 
| 953 } | 953 } | 
| 954 | 954 | 
| 955 case Token::SUB: { | 955 case Token::SUB: { | 
| 956 // Revert optimistic sub. | 956 // Revert optimistic sub. | 
| 957 if (reversed_) { | 957 if (reversed_) { | 
| 958 __ rsb(r0, tos_register_, Operand(Smi::FromInt(value_))); | 958 __ rsb(r0, tos_register_, Operand(Smi::FromInt(value_))); | 
| 959 __ mov(r1, Operand(Smi::FromInt(value_))); | 959 __ mov(r1, Operand(Smi::FromInt(value_))); | 
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1013 } | 1013 } | 
| 1014 | 1014 | 
| 1015 default: | 1015 default: | 
| 1016 // Other cases should have been handled before this point. | 1016 // Other cases should have been handled before this point. | 
| 1017 UNREACHABLE(); | 1017 UNREACHABLE(); | 
| 1018 break; | 1018 break; | 
| 1019 } | 1019 } | 
| 1020 | 1020 | 
| 1021 GenericBinaryOpStub stub(op_, overwrite_mode_, lhs, rhs, value_); | 1021 GenericBinaryOpStub stub(op_, overwrite_mode_, lhs, rhs, value_); | 
| 1022 __ CallStub(&stub); | 1022 __ CallStub(&stub); | 
| 1023 | |
| 1023 // The generic stub returns its value in r0, but that's not | 1024 // The generic stub returns its value in r0, but that's not | 
| 1024 // necessarily what we want. We want whatever the inlined code | 1025 // necessarily what we want. We want whatever the inlined code | 
| 1025 // expected, which is that the answer is in the same register as | 1026 // expected, which is that the answer is in the same register as | 
| 1026 // the operand was. | 1027 // the operand was. | 
| 1027 __ Move(tos_register_, r0); | 1028 __ Move(tos_register_, r0); | 
| 1029 | |
| 1030 // The tos register was not in use for the virtual frame that we | |
| 1031 // came into this function with, so we can merge back to that frame | |
| 1032 // without trashing it. | |
| 1033 copied_frame.MergeTo(frame_state()->frame()); | |
| 1028 } | 1034 } | 
| 1029 | 1035 | 
| 1030 | 1036 | 
| 1031 static bool PopCountLessThanEqual2(unsigned int x) { | 1037 static bool PopCountLessThanEqual2(unsigned int x) { | 
| 1032 x &= x - 1; | 1038 x &= x - 1; | 
| 1033 return (x & (x - 1)) == 0; | 1039 return (x & (x - 1)) == 0; | 
| 1034 } | 1040 } | 
| 1035 | 1041 | 
| 1036 | 1042 | 
| 1037 // Returns the index of the lowest bit set. | 1043 // Returns the index of the lowest bit set. | 
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1118 frame_->EmitPush(lhs, TypeInfo::Smi()); | 1124 frame_->EmitPush(lhs, TypeInfo::Smi()); | 
| 1119 TypeInfo t = both_sides_are_smi ? TypeInfo::Smi() : TypeInfo::Unknown(); | 1125 TypeInfo t = both_sides_are_smi ? TypeInfo::Smi() : TypeInfo::Unknown(); | 
| 1120 frame_->EmitPush(rhs, t); | 1126 frame_->EmitPush(rhs, t); | 
| 1121 GenericBinaryOperation(op, mode, GENERATE_INLINE_SMI, kUnknownIntValue); | 1127 GenericBinaryOperation(op, mode, GENERATE_INLINE_SMI, kUnknownIntValue); | 
| 1122 } | 1128 } | 
| 1123 return; | 1129 return; | 
| 1124 } | 1130 } | 
| 1125 | 1131 | 
| 1126 // We move the top of stack to a register (normally no move is invoved). | 1132 // We move the top of stack to a register (normally no move is invoved). | 
| 1127 Register tos = frame_->PopToRegister(); | 1133 Register tos = frame_->PopToRegister(); | 
| 1128 // All other registers are spilled. The deferred code expects one argument | |
| 1129 // in a register and all other values are flushed to the stack. The | |
| 1130 // answer is returned in the same register that the top of stack argument was | |
| 1131 // in. | |
| 1132 frame_->SpillAll(); | |
| 1133 | |
| 1134 switch (op) { | 1134 switch (op) { | 
| 1135 case Token::ADD: { | 1135 case Token::ADD: { | 
| 1136 DeferredCode* deferred = | 1136 DeferredCode* deferred = | 
| 1137 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | 1137 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | 
| 1138 | 1138 | 
| 1139 __ add(tos, tos, Operand(value), SetCC); | 1139 __ add(tos, tos, Operand(value), SetCC); | 
| 1140 deferred->Branch(vs); | 1140 deferred->Branch(vs); | 
| 1141 if (!both_sides_are_smi) { | 1141 if (!both_sides_are_smi) { | 
| 1142 __ tst(tos, Operand(kSmiTagMask)); | 1142 __ tst(tos, Operand(kSmiTagMask)); | 
| 1143 deferred->Branch(ne); | 1143 deferred->Branch(ne); | 
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1442 | 1442 | 
| 1443 exit.Bind(); | 1443 exit.Bind(); | 
| 1444 cc_reg_ = cc; | 1444 cc_reg_ = cc; | 
| 1445 } | 1445 } | 
| 1446 | 1446 | 
| 1447 | 1447 | 
| 1448 // Call the function on the stack with the given arguments. | 1448 // Call the function on the stack with the given arguments. | 
| 1449 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 1449 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 
| 1450 CallFunctionFlags flags, | 1450 CallFunctionFlags flags, | 
| 1451 int position) { | 1451 int position) { | 
| 1452 frame_->AssertIsSpilled(); | |
| 1453 | |
| 1454 // Push the arguments ("left-to-right") on the stack. | 1452 // Push the arguments ("left-to-right") on the stack. | 
| 1455 int arg_count = args->length(); | 1453 int arg_count = args->length(); | 
| 1456 for (int i = 0; i < arg_count; i++) { | 1454 for (int i = 0; i < arg_count; i++) { | 
| 1457 Load(args->at(i)); | 1455 Load(args->at(i)); | 
| 1458 } | 1456 } | 
| 1459 | 1457 | 
| 1460 // Record the position for debugging purposes. | 1458 // Record the position for debugging purposes. | 
| 1461 CodeForSourcePosition(position); | 1459 CodeForSourcePosition(position); | 
| 1462 | 1460 | 
| 1463 // Use the shared code stub to call the function. | 1461 // Use the shared code stub to call the function. | 
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1476 VariableProxy* arguments, | 1474 VariableProxy* arguments, | 
| 1477 int position) { | 1475 int position) { | 
| 1478 // An optimized implementation of expressions of the form | 1476 // An optimized implementation of expressions of the form | 
| 1479 // x.apply(y, arguments). | 1477 // x.apply(y, arguments). | 
| 1480 // If the arguments object of the scope has not been allocated, | 1478 // If the arguments object of the scope has not been allocated, | 
| 1481 // and x.apply is Function.prototype.apply, this optimization | 1479 // and x.apply is Function.prototype.apply, this optimization | 
| 1482 // just copies y and the arguments of the current function on the | 1480 // just copies y and the arguments of the current function on the | 
| 1483 // stack, as receiver and arguments, and calls x. | 1481 // stack, as receiver and arguments, and calls x. | 
| 1484 // In the implementation comments, we call x the applicand | 1482 // In the implementation comments, we call x the applicand | 
| 1485 // and y the receiver. | 1483 // and y the receiver. | 
| 1486 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 1487 | 1484 | 
| 1488 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); | 1485 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); | 
| 1489 ASSERT(arguments->IsArguments()); | 1486 ASSERT(arguments->IsArguments()); | 
| 1490 | 1487 | 
| 1491 // Load applicand.apply onto the stack. This will usually | 1488 // Load applicand.apply onto the stack. This will usually | 
| 1492 // give us a megamorphic load site. Not super, but it works. | 1489 // give us a megamorphic load site. Not super, but it works. | 
| 1493 Load(applicand); | 1490 Load(applicand); | 
| 1494 Handle<String> name = Factory::LookupAsciiSymbol("apply"); | 1491 Handle<String> name = Factory::LookupAsciiSymbol("apply"); | 
| 1495 frame_->Dup(); | 1492 frame_->Dup(); | 
| 1496 frame_->CallLoadIC(name, RelocInfo::CODE_TARGET); | 1493 frame_->CallLoadIC(name, RelocInfo::CODE_TARGET); | 
| 1497 frame_->EmitPush(r0); | 1494 frame_->EmitPush(r0); | 
| 1498 | 1495 | 
| 1499 // Load the receiver and the existing arguments object onto the | 1496 // Load the receiver and the existing arguments object onto the | 
| 1500 // expression stack. Avoid allocating the arguments object here. | 1497 // expression stack. Avoid allocating the arguments object here. | 
| 1501 Load(receiver); | 1498 Load(receiver); | 
| 1502 LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); | 1499 LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); | 
| 1503 | 1500 | 
| 1501 // At this point the top two stack elements are probably in registers | |
| 1502 // since they were just loaded. Ensure they are in regs and get the | |
| 1503 // regs. | |
| 1504 Register receiver_reg = frame_->Peek2(); | |
| 1505 Register arguments_reg = frame_->Peek(); | |
| 1506 | |
| 1507 // From now on the frame is spilled. | |
| 1508 frame_->SpillAll(); | |
| 1509 | |
| 1504 // Emit the source position information after having loaded the | 1510 // Emit the source position information after having loaded the | 
| 1505 // receiver and the arguments. | 1511 // receiver and the arguments. | 
| 1506 CodeForSourcePosition(position); | 1512 CodeForSourcePosition(position); | 
| 1507 // Contents of the stack at this point: | 1513 // Contents of the stack at this point: | 
| 1508 // sp[0]: arguments object of the current function or the hole. | 1514 // sp[0]: arguments object of the current function or the hole. | 
| 1509 // sp[1]: receiver | 1515 // sp[1]: receiver | 
| 1510 // sp[2]: applicand.apply | 1516 // sp[2]: applicand.apply | 
| 1511 // sp[3]: applicand. | 1517 // sp[3]: applicand. | 
| 1512 | 1518 | 
| 1513 // Check if the arguments object has been lazily allocated | 1519 // Check if the arguments object has been lazily allocated | 
| 1514 // already. If so, just use that instead of copying the arguments | 1520 // already. If so, just use that instead of copying the arguments | 
| 1515 // from the stack. This also deals with cases where a local variable | 1521 // from the stack. This also deals with cases where a local variable | 
| 1516 // named 'arguments' has been introduced. | 1522 // named 'arguments' has been introduced. | 
| 1517 __ ldr(r0, MemOperand(sp, 0)); | 1523 JumpTarget slow; | 
| 1518 | 1524 Label done; | 
| 1519 Label slow, done; | |
| 1520 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 1525 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 
| 1521 __ cmp(ip, r0); | 1526 __ cmp(ip, arguments_reg); | 
| 1522 __ b(ne, &slow); | 1527 slow.Branch(ne); | 
| 1523 | 1528 | 
| 1524 Label build_args; | 1529 Label build_args; | 
| 1525 // Get rid of the arguments object probe. | 1530 // Get rid of the arguments object probe. | 
| 1526 frame_->Drop(); | 1531 frame_->Drop(); | 
| 1527 // Stack now has 3 elements on it. | 1532 // Stack now has 3 elements on it. | 
| 1528 // Contents of stack at this point: | 1533 // Contents of stack at this point: | 
| 1529 // sp[0]: receiver | 1534 // sp[0]: receiver - in the receiver_reg register. | 
| 1530 // sp[1]: applicand.apply | 1535 // sp[1]: applicand.apply | 
| 1531 // sp[2]: applicand. | 1536 // sp[2]: applicand. | 
| 1532 | 1537 | 
| 1533 // Check that the receiver really is a JavaScript object. | 1538 // Check that the receiver really is a JavaScript object. | 
| 1534 __ ldr(r0, MemOperand(sp, 0)); | 1539 __ BranchOnSmi(receiver_reg, &build_args); | 
| 1535 __ BranchOnSmi(r0, &build_args); | |
| 1536 // We allow all JSObjects including JSFunctions. As long as | 1540 // We allow all JSObjects including JSFunctions. As long as | 
| 1537 // JS_FUNCTION_TYPE is the last instance type and it is right | 1541 // JS_FUNCTION_TYPE is the last instance type and it is right | 
| 1538 // after LAST_JS_OBJECT_TYPE, we do not have to check the upper | 1542 // after LAST_JS_OBJECT_TYPE, we do not have to check the upper | 
| 1539 // bound. | 1543 // bound. | 
| 1540 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 1544 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 
| 1541 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 1545 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 
| 1542 __ CompareObjectType(r0, r1, r2, FIRST_JS_OBJECT_TYPE); | 1546 __ CompareObjectType(receiver_reg, r2, r3, FIRST_JS_OBJECT_TYPE); | 
| 1543 __ b(lt, &build_args); | 1547 __ b(lt, &build_args); | 
| 1544 | 1548 | 
| 1545 // Check that applicand.apply is Function.prototype.apply. | 1549 // Check that applicand.apply is Function.prototype.apply. | 
| 1546 __ ldr(r0, MemOperand(sp, kPointerSize)); | 1550 __ ldr(r0, MemOperand(sp, kPointerSize)); | 
| 1547 __ BranchOnSmi(r0, &build_args); | 1551 __ BranchOnSmi(r0, &build_args); | 
| 1548 __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE); | 1552 __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE); | 
| 1549 __ b(ne, &build_args); | 1553 __ b(ne, &build_args); | 
| 1550 __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); | 1554 __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); | 
| 1551 Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply)); | 1555 Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply)); | 
| 1552 __ ldr(r1, FieldMemOperand(r0, SharedFunctionInfo::kCodeOffset)); | 1556 __ ldr(r1, FieldMemOperand(r0, SharedFunctionInfo::kCodeOffset)); | 
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1621 // there, and fall-through to the slow-case where we call | 1625 // there, and fall-through to the slow-case where we call | 
| 1622 // applicand.apply. | 1626 // applicand.apply. | 
| 1623 __ bind(&build_args); | 1627 __ bind(&build_args); | 
| 1624 // Stack now has 3 elements, because we have jumped from where: | 1628 // Stack now has 3 elements, because we have jumped from where: | 
| 1625 // sp[0]: receiver | 1629 // sp[0]: receiver | 
| 1626 // sp[1]: applicand.apply | 1630 // sp[1]: applicand.apply | 
| 1627 // sp[2]: applicand. | 1631 // sp[2]: applicand. | 
| 1628 StoreArgumentsObject(false); | 1632 StoreArgumentsObject(false); | 
| 1629 | 1633 | 
| 1630 // Stack and frame now have 4 elements. | 1634 // Stack and frame now have 4 elements. | 
| 1631 __ bind(&slow); | 1635 slow.Bind(); | 
| 1632 | 1636 | 
| 1633 // Generic computation of x.apply(y, args) with no special optimization. | 1637 // Generic computation of x.apply(y, args) with no special optimization. | 
| 1634 // Flip applicand.apply and applicand on the stack, so | 1638 // Flip applicand.apply and applicand on the stack, so | 
| 1635 // applicand looks like the receiver of the applicand.apply call. | 1639 // applicand looks like the receiver of the applicand.apply call. | 
| 1636 // Then process it as a normal function call. | 1640 // Then process it as a normal function call. | 
| 1637 __ ldr(r0, MemOperand(sp, 3 * kPointerSize)); | 1641 __ ldr(r0, MemOperand(sp, 3 * kPointerSize)); | 
| 1638 __ ldr(r1, MemOperand(sp, 2 * kPointerSize)); | 1642 __ ldr(r1, MemOperand(sp, 2 * kPointerSize)); | 
| 1639 __ Strd(r0, r1, MemOperand(sp, 2 * kPointerSize)); | 1643 __ Strd(r0, r1, MemOperand(sp, 2 * kPointerSize)); | 
| 1640 | 1644 | 
| 1641 CallFunctionStub call_function(2, NOT_IN_LOOP, NO_CALL_FUNCTION_FLAGS); | 1645 CallFunctionStub call_function(2, NOT_IN_LOOP, NO_CALL_FUNCTION_FLAGS); | 
| 1642 frame_->CallStub(&call_function, 3); | 1646 frame_->CallStub(&call_function, 3); | 
| 1643 // The function and its two arguments have been dropped. | 1647 // The function and its two arguments have been dropped. | 
| 1644 frame_->Drop(); // Drop the receiver as well. | 1648 frame_->Drop(); // Drop the receiver as well. | 
| 1645 frame_->EmitPush(r0); | 1649 frame_->EmitPush(r0); | 
| 1646 // Stack now has 1 element: | 1650 // Stack now has 1 element: | 
| 1647 // sp[0]: result | 1651 // sp[0]: result | 
| 1648 __ bind(&done); | 1652 __ bind(&done); | 
| 1649 | 1653 | 
| 1650 // Restore the context register after a call. | 1654 // Restore the context register after a call. | 
| 1651 __ ldr(cp, frame_->Context()); | 1655 __ ldr(cp, frame_->Context()); | 
| 1652 } | 1656 } | 
| 1653 | 1657 | 
| 1654 | 1658 | 
| 1655 void CodeGenerator::Branch(bool if_true, JumpTarget* target) { | 1659 void CodeGenerator::Branch(bool if_true, JumpTarget* target) { | 
| 1656 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 1657 ASSERT(has_cc()); | 1660 ASSERT(has_cc()); | 
| 1658 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | 1661 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | 
| 1659 target->Branch(cc); | 1662 target->Branch(cc); | 
| 1660 cc_reg_ = al; | 1663 cc_reg_ = al; | 
| 1661 } | 1664 } | 
| 1662 | 1665 | 
| 1663 | 1666 | 
| 1664 void CodeGenerator::CheckStack() { | 1667 void CodeGenerator::CheckStack() { | 
| 1665 VirtualFrame::SpilledScope spilled_scope(frame_); | 1668 frame_->SpillAll(); | 
| 1666 Comment cmnt(masm_, "[ check stack"); | 1669 Comment cmnt(masm_, "[ check stack"); | 
| 1667 __ LoadRoot(ip, Heap::kStackLimitRootIndex); | 1670 __ LoadRoot(ip, Heap::kStackLimitRootIndex); | 
| 1668 // Put the lr setup instruction in the delay slot. kInstrSize is added to | 1671 // Put the lr setup instruction in the delay slot. kInstrSize is added to | 
| 1669 // the implicit 8 byte offset that always applies to operations with pc and | 1672 // the implicit 8 byte offset that always applies to operations with pc and | 
| 1670 // gives a return address 12 bytes down. | 1673 // gives a return address 12 bytes down. | 
| 1671 masm_->add(lr, pc, Operand(Assembler::kInstrSize)); | 1674 masm_->add(lr, pc, Operand(Assembler::kInstrSize)); | 
| 1672 masm_->cmp(sp, Operand(ip)); | 1675 masm_->cmp(sp, Operand(ip)); | 
| 1673 StackCheckStub stub; | 1676 StackCheckStub stub; | 
| 1674 // Call the stub if lower. | 1677 // Call the stub if lower. | 
| 1675 masm_->mov(pc, | 1678 masm_->mov(pc, | 
| 1676 Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()), | 1679 Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()), | 
| 1677 RelocInfo::CODE_TARGET), | 1680 RelocInfo::CODE_TARGET), | 
| 1678 LeaveCC, | 1681 LeaveCC, | 
| 1679 lo); | 1682 lo); | 
| 1680 } | 1683 } | 
| 1681 | 1684 | 
| 1682 | 1685 | 
| 1683 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { | 1686 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { | 
| 1684 #ifdef DEBUG | 1687 #ifdef DEBUG | 
| 1685 int original_height = frame_->height(); | 1688 int original_height = frame_->height(); | 
| 1686 #endif | 1689 #endif | 
| 1687 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 1688 for (int i = 0; frame_ != NULL && i < statements->length(); i++) { | 1690 for (int i = 0; frame_ != NULL && i < statements->length(); i++) { | 
| 1689 Visit(statements->at(i)); | 1691 Visit(statements->at(i)); | 
| 1690 } | 1692 } | 
| 1691 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 1693 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 
| 1692 } | 1694 } | 
| 1693 | 1695 | 
| 1694 | 1696 | 
| 1695 void CodeGenerator::VisitBlock(Block* node) { | 1697 void CodeGenerator::VisitBlock(Block* node) { | 
| 1696 #ifdef DEBUG | 1698 #ifdef DEBUG | 
| 1697 int original_height = frame_->height(); | 1699 int original_height = frame_->height(); | 
| 1698 #endif | 1700 #endif | 
| 1699 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 1700 Comment cmnt(masm_, "[ Block"); | 1701 Comment cmnt(masm_, "[ Block"); | 
| 1701 CodeForStatementPosition(node); | 1702 CodeForStatementPosition(node); | 
| 1702 node->break_target()->SetExpectedHeight(); | 1703 node->break_target()->SetExpectedHeight(); | 
| 1703 VisitStatements(node->statements()); | 1704 VisitStatements(node->statements()); | 
| 1704 if (node->break_target()->is_linked()) { | 1705 if (node->break_target()->is_linked()) { | 
| 1705 node->break_target()->Bind(); | 1706 node->break_target()->Bind(); | 
| 1706 } | 1707 } | 
| 1707 node->break_target()->Unuse(); | 1708 node->break_target()->Unuse(); | 
| 1708 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 1709 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 
| 1709 } | 1710 } | 
| 1710 | 1711 | 
| 1711 | 1712 | 
| 1712 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1713 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 
| 1713 frame_->EmitPush(cp); | 1714 frame_->EmitPush(cp); | 
| 1714 frame_->EmitPush(Operand(pairs)); | 1715 frame_->EmitPush(Operand(pairs)); | 
| 1715 frame_->EmitPush(Operand(Smi::FromInt(is_eval() ? 1 : 0))); | 1716 frame_->EmitPush(Operand(Smi::FromInt(is_eval() ? 1 : 0))); | 
| 1716 | 1717 | 
| 1717 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 1718 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 1718 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 
| 1719 // The result is discarded. | 1719 // The result is discarded. | 
| 1720 } | 1720 } | 
| 1721 | 1721 | 
| 1722 | 1722 | 
| 1723 void CodeGenerator::VisitDeclaration(Declaration* node) { | 1723 void CodeGenerator::VisitDeclaration(Declaration* node) { | 
| 1724 #ifdef DEBUG | 1724 #ifdef DEBUG | 
| 1725 int original_height = frame_->height(); | 1725 int original_height = frame_->height(); | 
| 1726 #endif | 1726 #endif | 
| 1727 Comment cmnt(masm_, "[ Declaration"); | 1727 Comment cmnt(masm_, "[ Declaration"); | 
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1748 // 'undefined') because we may have a (legal) redeclaration and we | 1748 // 'undefined') because we may have a (legal) redeclaration and we | 
| 1749 // must not destroy the current value. | 1749 // must not destroy the current value. | 
| 1750 if (node->mode() == Variable::CONST) { | 1750 if (node->mode() == Variable::CONST) { | 
| 1751 frame_->EmitPushRoot(Heap::kTheHoleValueRootIndex); | 1751 frame_->EmitPushRoot(Heap::kTheHoleValueRootIndex); | 
| 1752 } else if (node->fun() != NULL) { | 1752 } else if (node->fun() != NULL) { | 
| 1753 Load(node->fun()); | 1753 Load(node->fun()); | 
| 1754 } else { | 1754 } else { | 
| 1755 frame_->EmitPush(Operand(0)); | 1755 frame_->EmitPush(Operand(0)); | 
| 1756 } | 1756 } | 
| 1757 | 1757 | 
| 1758 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 1759 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); | 1758 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); | 
| 1760 // Ignore the return value (declarations are statements). | 1759 // Ignore the return value (declarations are statements). | 
| 1761 | 1760 | 
| 1762 ASSERT(frame_->height() == original_height); | 1761 ASSERT(frame_->height() == original_height); | 
| 1763 return; | 1762 return; | 
| 1764 } | 1763 } | 
| 1765 | 1764 | 
| 1766 ASSERT(!var->is_global()); | 1765 ASSERT(!var->is_global()); | 
| 1767 | 1766 | 
| 1768 // If we have a function or a constant, we need to initialize the variable. | 1767 // If we have a function or a constant, we need to initialize the variable. | 
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1893 | 1892 | 
| 1894 // end | 1893 // end | 
| 1895 if (exit.is_linked()) { | 1894 if (exit.is_linked()) { | 
| 1896 exit.Bind(); | 1895 exit.Bind(); | 
| 1897 } | 1896 } | 
| 1898 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 1897 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 
| 1899 } | 1898 } | 
| 1900 | 1899 | 
| 1901 | 1900 | 
| 1902 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1901 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 
| 1903 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 1904 Comment cmnt(masm_, "[ ContinueStatement"); | 1902 Comment cmnt(masm_, "[ ContinueStatement"); | 
| 1905 CodeForStatementPosition(node); | 1903 CodeForStatementPosition(node); | 
| 1906 node->target()->continue_target()->Jump(); | 1904 node->target()->continue_target()->Jump(); | 
| 1907 } | 1905 } | 
| 1908 | 1906 | 
| 1909 | 1907 | 
| 1910 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1908 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 
| 1911 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 1912 Comment cmnt(masm_, "[ BreakStatement"); | 1909 Comment cmnt(masm_, "[ BreakStatement"); | 
| 1913 CodeForStatementPosition(node); | 1910 CodeForStatementPosition(node); | 
| 1914 node->target()->break_target()->Jump(); | 1911 node->target()->break_target()->Jump(); | 
| 1915 } | 1912 } | 
| 1916 | 1913 | 
| 1917 | 1914 | 
| 1918 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1915 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 
| 1919 VirtualFrame::SpilledScope spilled_scope(frame_); | 1916 frame_->SpillAll(); | 
| 1920 Comment cmnt(masm_, "[ ReturnStatement"); | 1917 Comment cmnt(masm_, "[ ReturnStatement"); | 
| 1921 | 1918 | 
| 1922 CodeForStatementPosition(node); | 1919 CodeForStatementPosition(node); | 
| 1923 Load(node->expression()); | 1920 Load(node->expression()); | 
| 1924 if (function_return_is_shadowed_) { | 1921 if (function_return_is_shadowed_) { | 
| 1925 frame_->EmitPop(r0); | 1922 frame_->EmitPop(r0); | 
| 1926 function_return_.Jump(); | 1923 function_return_.Jump(); | 
| 1927 } else { | 1924 } else { | 
| 1928 // Pop the result from the frame and prepare the frame for | 1925 // Pop the result from the frame and prepare the frame for | 
| 1929 // returning thus making it easier to merge. | 1926 // returning thus making it easier to merge. | 
| 1930 frame_->EmitPop(r0); | 1927 frame_->PopToR0(); | 
| 1931 frame_->PrepareForReturn(); | 1928 frame_->PrepareForReturn(); | 
| 1932 if (function_return_.is_bound()) { | 1929 if (function_return_.is_bound()) { | 
| 1933 // If the function return label is already bound we reuse the | 1930 // If the function return label is already bound we reuse the | 
| 1934 // code by jumping to the return site. | 1931 // code by jumping to the return site. | 
| 1935 function_return_.Jump(); | 1932 function_return_.Jump(); | 
| 1936 } else { | 1933 } else { | 
| 1937 function_return_.Bind(); | 1934 function_return_.Bind(); | 
| 1938 GenerateReturnSequence(); | 1935 GenerateReturnSequence(); | 
| 1939 } | 1936 } | 
| 1940 } | 1937 } | 
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1980 Assembler::kJSReturnSequenceInstructions + 1); | 1977 Assembler::kJSReturnSequenceInstructions + 1); | 
| 1981 #endif | 1978 #endif | 
| 1982 } | 1979 } | 
| 1983 } | 1980 } | 
| 1984 | 1981 | 
| 1985 | 1982 | 
| 1986 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1983 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 
| 1987 #ifdef DEBUG | 1984 #ifdef DEBUG | 
| 1988 int original_height = frame_->height(); | 1985 int original_height = frame_->height(); | 
| 1989 #endif | 1986 #endif | 
| 1990 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 1991 Comment cmnt(masm_, "[ WithEnterStatement"); | 1987 Comment cmnt(masm_, "[ WithEnterStatement"); | 
| 1992 CodeForStatementPosition(node); | 1988 CodeForStatementPosition(node); | 
| 1993 Load(node->expression()); | 1989 Load(node->expression()); | 
| 1994 if (node->is_catch_block()) { | 1990 if (node->is_catch_block()) { | 
| 1995 frame_->CallRuntime(Runtime::kPushCatchContext, 1); | 1991 frame_->CallRuntime(Runtime::kPushCatchContext, 1); | 
| 1996 } else { | 1992 } else { | 
| 1997 frame_->CallRuntime(Runtime::kPushContext, 1); | 1993 frame_->CallRuntime(Runtime::kPushContext, 1); | 
| 1998 } | 1994 } | 
| 1999 #ifdef DEBUG | 1995 #ifdef DEBUG | 
| 2000 JumpTarget verified_true; | 1996 JumpTarget verified_true; | 
| 2001 __ cmp(r0, cp); | 1997 __ cmp(r0, cp); | 
| 2002 verified_true.Branch(eq); | 1998 verified_true.Branch(eq); | 
| 2003 __ stop("PushContext: r0 is expected to be the same as cp"); | 1999 __ stop("PushContext: r0 is expected to be the same as cp"); | 
| 2004 verified_true.Bind(); | 2000 verified_true.Bind(); | 
| 2005 #endif | 2001 #endif | 
| 2006 // Update context local. | 2002 // Update context local. | 
| 2007 __ str(cp, frame_->Context()); | 2003 __ str(cp, frame_->Context()); | 
| 2008 ASSERT(frame_->height() == original_height); | 2004 ASSERT(frame_->height() == original_height); | 
| 2009 } | 2005 } | 
| 2010 | 2006 | 
| 2011 | 2007 | 
| 2012 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 2008 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 
| 2013 #ifdef DEBUG | 2009 #ifdef DEBUG | 
| 2014 int original_height = frame_->height(); | 2010 int original_height = frame_->height(); | 
| 2015 #endif | 2011 #endif | 
| 2016 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 2017 Comment cmnt(masm_, "[ WithExitStatement"); | 2012 Comment cmnt(masm_, "[ WithExitStatement"); | 
| 2018 CodeForStatementPosition(node); | 2013 CodeForStatementPosition(node); | 
| 2019 // Pop context. | 2014 // Pop context. | 
| 2020 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX)); | 2015 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX)); | 
| 2021 // Update context local. | 2016 // Update context local. | 
| 2022 __ str(cp, frame_->Context()); | 2017 __ str(cp, frame_->Context()); | 
| 2023 ASSERT(frame_->height() == original_height); | 2018 ASSERT(frame_->height() == original_height); | 
| 2024 } | 2019 } | 
| 2025 | 2020 | 
| 2026 | 2021 | 
| 2027 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 2022 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 
| 2028 #ifdef DEBUG | 2023 #ifdef DEBUG | 
| 2029 int original_height = frame_->height(); | 2024 int original_height = frame_->height(); | 
| 2030 #endif | 2025 #endif | 
| 2031 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 2032 Comment cmnt(masm_, "[ SwitchStatement"); | 2026 Comment cmnt(masm_, "[ SwitchStatement"); | 
| 2033 CodeForStatementPosition(node); | 2027 CodeForStatementPosition(node); | 
| 2034 node->break_target()->SetExpectedHeight(); | 2028 node->break_target()->SetExpectedHeight(); | 
| 2035 | 2029 | 
| 2036 Load(node->tag()); | 2030 Load(node->tag()); | 
| 2037 | 2031 | 
| 2038 JumpTarget next_test; | 2032 JumpTarget next_test; | 
| 2039 JumpTarget fall_through; | 2033 JumpTarget fall_through; | 
| 2040 JumpTarget default_entry; | 2034 JumpTarget default_entry; | 
| 2041 JumpTarget default_exit(JumpTarget::BIDIRECTIONAL); | 2035 JumpTarget default_exit(JumpTarget::BIDIRECTIONAL); | 
| 2042 ZoneList<CaseClause*>* cases = node->cases(); | 2036 ZoneList<CaseClause*>* cases = node->cases(); | 
| 2043 int length = cases->length(); | 2037 int length = cases->length(); | 
| 2044 CaseClause* default_clause = NULL; | 2038 CaseClause* default_clause = NULL; | 
| 2045 | 2039 | 
| 2046 for (int i = 0; i < length; i++) { | 2040 for (int i = 0; i < length; i++) { | 
| 2047 CaseClause* clause = cases->at(i); | 2041 CaseClause* clause = cases->at(i); | 
| 2048 if (clause->is_default()) { | 2042 if (clause->is_default()) { | 
| 2049 // Remember the default clause and compile it at the end. | 2043 // Remember the default clause and compile it at the end. | 
| 2050 default_clause = clause; | 2044 default_clause = clause; | 
| 2051 continue; | 2045 continue; | 
| 2052 } | 2046 } | 
| 2053 | 2047 | 
| 2054 Comment cmnt(masm_, "[ Case clause"); | 2048 Comment cmnt(masm_, "[ Case clause"); | 
| 2055 // Compile the test. | 2049 // Compile the test. | 
| 2056 next_test.Bind(); | 2050 next_test.Bind(); | 
| 2057 next_test.Unuse(); | 2051 next_test.Unuse(); | 
| 2058 // Duplicate TOS. | 2052 // Duplicate TOS. | 
| 2059 __ ldr(r0, frame_->Top()); | 2053 frame_->Dup(); | 
| 2060 frame_->EmitPush(r0); | |
| 2061 Comparison(eq, NULL, clause->label(), true); | 2054 Comparison(eq, NULL, clause->label(), true); | 
| 2062 Branch(false, &next_test); | 2055 Branch(false, &next_test); | 
| 2063 | 2056 | 
| 2064 // Before entering the body from the test, remove the switch value from | 2057 // Before entering the body from the test, remove the switch value from | 
| 2065 // the stack. | 2058 // the stack. | 
| 2066 frame_->Drop(); | 2059 frame_->Drop(); | 
| 2067 | 2060 | 
| 2068 // Label the body so that fall through is enabled. | 2061 // Label the body so that fall through is enabled. | 
| 2069 if (i > 0 && cases->at(i - 1)->is_default()) { | 2062 if (i > 0 && cases->at(i - 1)->is_default()) { | 
| 2070 default_exit.Bind(); | 2063 default_exit.Bind(); | 
| (...skipping 17 matching lines...) Expand all Loading... | |
| 2088 // The final "test" removes the switch value. | 2081 // The final "test" removes the switch value. | 
| 2089 next_test.Bind(); | 2082 next_test.Bind(); | 
| 2090 frame_->Drop(); | 2083 frame_->Drop(); | 
| 2091 | 2084 | 
| 2092 // If there is a default clause, compile it. | 2085 // If there is a default clause, compile it. | 
| 2093 if (default_clause != NULL) { | 2086 if (default_clause != NULL) { | 
| 2094 Comment cmnt(masm_, "[ Default clause"); | 2087 Comment cmnt(masm_, "[ Default clause"); | 
| 2095 default_entry.Bind(); | 2088 default_entry.Bind(); | 
| 2096 VisitStatements(default_clause->statements()); | 2089 VisitStatements(default_clause->statements()); | 
| 2097 // If control flow can fall out of the default and there is a case after | 2090 // If control flow can fall out of the default and there is a case after | 
| 2098 // it, jup to that case's body. | 2091 // it, jump to that case's body. | 
| 2099 if (frame_ != NULL && default_exit.is_bound()) { | 2092 if (frame_ != NULL && default_exit.is_bound()) { | 
| 2100 default_exit.Jump(); | 2093 default_exit.Jump(); | 
| 2101 } | 2094 } | 
| 2102 } | 2095 } | 
| 2103 | 2096 | 
| 2104 if (fall_through.is_linked()) { | 2097 if (fall_through.is_linked()) { | 
| 2105 fall_through.Bind(); | 2098 fall_through.Bind(); | 
| 2106 } | 2099 } | 
| 2107 | 2100 | 
| 2108 if (node->break_target()->is_linked()) { | 2101 if (node->break_target()->is_linked()) { | 
| 2109 node->break_target()->Bind(); | 2102 node->break_target()->Bind(); | 
| 2110 } | 2103 } | 
| 2111 node->break_target()->Unuse(); | 2104 node->break_target()->Unuse(); | 
| 2112 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 2105 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 
| 2113 } | 2106 } | 
| 2114 | 2107 | 
| 2115 | 2108 | 
| 2116 void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) { | 2109 void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) { | 
| 2117 #ifdef DEBUG | 2110 #ifdef DEBUG | 
| 2118 int original_height = frame_->height(); | 2111 int original_height = frame_->height(); | 
| 2119 #endif | 2112 #endif | 
| 2120 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 2121 Comment cmnt(masm_, "[ DoWhileStatement"); | 2113 Comment cmnt(masm_, "[ DoWhileStatement"); | 
| 2122 CodeForStatementPosition(node); | 2114 CodeForStatementPosition(node); | 
| 2123 node->break_target()->SetExpectedHeight(); | 2115 node->break_target()->SetExpectedHeight(); | 
| 2124 JumpTarget body(JumpTarget::BIDIRECTIONAL); | 2116 JumpTarget body(JumpTarget::BIDIRECTIONAL); | 
| 2125 IncrementLoopNesting(); | 2117 IncrementLoopNesting(); | 
| 2126 | 2118 | 
| 2127 // Label the top of the loop for the backward CFG edge. If the test | 2119 // Label the top of the loop for the backward CFG edge. If the test | 
| 2128 // is always true we can use the continue target, and if the test is | 2120 // is always true we can use the continue target, and if the test is | 
| 2129 // always false there is no need. | 2121 // always false there is no need. | 
| 2130 ConditionAnalysis info = AnalyzeCondition(node->cond()); | 2122 ConditionAnalysis info = AnalyzeCondition(node->cond()); | 
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2185 } | 2177 } | 
| 2186 DecrementLoopNesting(); | 2178 DecrementLoopNesting(); | 
| 2187 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 2179 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 
| 2188 } | 2180 } | 
| 2189 | 2181 | 
| 2190 | 2182 | 
| 2191 void CodeGenerator::VisitWhileStatement(WhileStatement* node) { | 2183 void CodeGenerator::VisitWhileStatement(WhileStatement* node) { | 
| 2192 #ifdef DEBUG | 2184 #ifdef DEBUG | 
| 2193 int original_height = frame_->height(); | 2185 int original_height = frame_->height(); | 
| 2194 #endif | 2186 #endif | 
| 2195 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 2196 Comment cmnt(masm_, "[ WhileStatement"); | 2187 Comment cmnt(masm_, "[ WhileStatement"); | 
| 2197 CodeForStatementPosition(node); | 2188 CodeForStatementPosition(node); | 
| 2198 | 2189 | 
| 2199 // If the test is never true and has no side effects there is no need | 2190 // If the test is never true and has no side effects there is no need | 
| 2200 // to compile the test or body. | 2191 // to compile the test or body. | 
| 2201 ConditionAnalysis info = AnalyzeCondition(node->cond()); | 2192 ConditionAnalysis info = AnalyzeCondition(node->cond()); | 
| 2202 if (info == ALWAYS_FALSE) return; | 2193 if (info == ALWAYS_FALSE) return; | 
| 2203 | 2194 | 
| 2204 node->break_target()->SetExpectedHeight(); | 2195 node->break_target()->SetExpectedHeight(); | 
| 2205 IncrementLoopNesting(); | 2196 IncrementLoopNesting(); | 
| 2206 | 2197 | 
| 2207 // Label the top of the loop with the continue target for the backward | 2198 // Label the top of the loop with the continue target for the backward | 
| 2208 // CFG edge. | 2199 // CFG edge. | 
| 2209 node->continue_target()->SetExpectedHeight(); | 2200 node->continue_target()->SetExpectedHeight(); | 
| 2210 node->continue_target()->Bind(); | 2201 node->continue_target()->Bind(); | 
| 2211 | 2202 | 
| 2212 if (info == DONT_KNOW) { | 2203 if (info == DONT_KNOW) { | 
| 2213 JumpTarget body; | 2204 JumpTarget body(JumpTarget::BIDIRECTIONAL); | 
| 2214 LoadCondition(node->cond(), &body, node->break_target(), true); | 2205 LoadCondition(node->cond(), &body, node->break_target(), true); | 
| 2215 if (has_valid_frame()) { | 2206 if (has_valid_frame()) { | 
| 2216 // A NULL frame indicates that control did not fall out of the | 2207 // A NULL frame indicates that control did not fall out of the | 
| 2217 // test expression. | 2208 // test expression. | 
| 2218 Branch(false, node->break_target()); | 2209 Branch(false, node->break_target()); | 
| 2219 } | 2210 } | 
| 2220 if (has_valid_frame() || body.is_linked()) { | 2211 if (has_valid_frame() || body.is_linked()) { | 
| 2221 body.Bind(); | 2212 body.Bind(); | 
| 2222 } | 2213 } | 
| 2223 } | 2214 } | 
| (...skipping 12 matching lines...) Expand all Loading... | |
| 2236 } | 2227 } | 
| 2237 DecrementLoopNesting(); | 2228 DecrementLoopNesting(); | 
| 2238 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 2229 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 
| 2239 } | 2230 } | 
| 2240 | 2231 | 
| 2241 | 2232 | 
| 2242 void CodeGenerator::VisitForStatement(ForStatement* node) { | 2233 void CodeGenerator::VisitForStatement(ForStatement* node) { | 
| 2243 #ifdef DEBUG | 2234 #ifdef DEBUG | 
| 2244 int original_height = frame_->height(); | 2235 int original_height = frame_->height(); | 
| 2245 #endif | 2236 #endif | 
| 2246 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 2247 Comment cmnt(masm_, "[ ForStatement"); | 2237 Comment cmnt(masm_, "[ ForStatement"); | 
| 2248 CodeForStatementPosition(node); | 2238 CodeForStatementPosition(node); | 
| 2249 if (node->init() != NULL) { | 2239 if (node->init() != NULL) { | 
| 2250 Visit(node->init()); | 2240 Visit(node->init()); | 
| 2251 } | 2241 } | 
| 2252 | 2242 | 
| 2253 // If the test is never true there is no need to compile the test or | 2243 // If the test is never true there is no need to compile the test or | 
| 2254 // body. | 2244 // body. | 
| 2255 ConditionAnalysis info = AnalyzeCondition(node->cond()); | 2245 ConditionAnalysis info = AnalyzeCondition(node->cond()); | 
| 2256 if (info == ALWAYS_FALSE) return; | 2246 if (info == ALWAYS_FALSE) return; | 
| (...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2925 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral"); | 2915 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral"); | 
| 2926 InstantiateFunction(node->shared_function_info()); | 2916 InstantiateFunction(node->shared_function_info()); | 
| 2927 ASSERT_EQ(original_height + 1, frame_->height()); | 2917 ASSERT_EQ(original_height + 1, frame_->height()); | 
| 2928 } | 2918 } | 
| 2929 | 2919 | 
| 2930 | 2920 | 
| 2931 void CodeGenerator::VisitConditional(Conditional* node) { | 2921 void CodeGenerator::VisitConditional(Conditional* node) { | 
| 2932 #ifdef DEBUG | 2922 #ifdef DEBUG | 
| 2933 int original_height = frame_->height(); | 2923 int original_height = frame_->height(); | 
| 2934 #endif | 2924 #endif | 
| 2935 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 2936 Comment cmnt(masm_, "[ Conditional"); | 2925 Comment cmnt(masm_, "[ Conditional"); | 
| 2937 JumpTarget then; | 2926 JumpTarget then; | 
| 2938 JumpTarget else_; | 2927 JumpTarget else_; | 
| 2939 LoadCondition(node->condition(), &then, &else_, true); | 2928 LoadCondition(node->condition(), &then, &else_, true); | 
| 2940 if (has_valid_frame()) { | 2929 if (has_valid_frame()) { | 
| 2941 Branch(false, &else_); | 2930 Branch(false, &else_); | 
| 2942 } | 2931 } | 
| 2943 if (has_valid_frame() || then.is_linked()) { | 2932 if (has_valid_frame() || then.is_linked()) { | 
| 2944 then.Bind(); | 2933 then.Bind(); | 
| 2945 Load(node->then_expression()); | 2934 Load(node->then_expression()); | 
| (...skipping 20 matching lines...) Expand all Loading... | |
| 2966 | 2955 | 
| 2967 // Generate fast case for loading from slots that correspond to | 2956 // Generate fast case for loading from slots that correspond to | 
| 2968 // local/global variables or arguments unless they are shadowed by | 2957 // local/global variables or arguments unless they are shadowed by | 
| 2969 // eval-introduced bindings. | 2958 // eval-introduced bindings. | 
| 2970 EmitDynamicLoadFromSlotFastCase(slot, | 2959 EmitDynamicLoadFromSlotFastCase(slot, | 
| 2971 typeof_state, | 2960 typeof_state, | 
| 2972 &slow, | 2961 &slow, | 
| 2973 &done); | 2962 &done); | 
| 2974 | 2963 | 
| 2975 slow.Bind(); | 2964 slow.Bind(); | 
| 2976 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 2977 frame_->EmitPush(cp); | 2965 frame_->EmitPush(cp); | 
| 2978 __ mov(r0, Operand(slot->var()->name())); | 2966 frame_->EmitPush(Operand(slot->var()->name())); | 
| 2979 frame_->EmitPush(r0); | |
| 2980 | 2967 | 
| 2981 if (typeof_state == INSIDE_TYPEOF) { | 2968 if (typeof_state == INSIDE_TYPEOF) { | 
| 2982 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2969 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 
| 2983 } else { | 2970 } else { | 
| 2984 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 2971 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 
| 2985 } | 2972 } | 
| 2986 | 2973 | 
| 2987 done.Bind(); | 2974 done.Bind(); | 
| 2988 frame_->EmitPush(r0); | 2975 frame_->EmitPush(r0); | 
| 2989 | 2976 | 
| 2990 } else { | 2977 } else { | 
| 2991 Register scratch = VirtualFrame::scratch0(); | 2978 Register scratch = VirtualFrame::scratch0(); | 
| 2992 TypeInfo info = type_info(slot); | 2979 TypeInfo info = type_info(slot); | 
| 2993 frame_->EmitPush(SlotOperand(slot, scratch), info); | 2980 frame_->EmitPush(SlotOperand(slot, scratch), info); | 
| 2981 | |
| 2994 if (slot->var()->mode() == Variable::CONST) { | 2982 if (slot->var()->mode() == Variable::CONST) { | 
| 2995 // Const slots may contain 'the hole' value (the constant hasn't been | 2983 // Const slots may contain 'the hole' value (the constant hasn't been | 
| 2996 // initialized yet) which needs to be converted into the 'undefined' | 2984 // initialized yet) which needs to be converted into the 'undefined' | 
| 2997 // value. | 2985 // value. | 
| 2998 Comment cmnt(masm_, "[ Unhole const"); | 2986 Comment cmnt(masm_, "[ Unhole const"); | 
| 2999 frame_->EmitPop(scratch); | 2987 Register tos = frame_->PopToRegister(); | 
| 3000 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 2988 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 
| 3001 __ cmp(scratch, ip); | 2989 __ cmp(tos, ip); | 
| 3002 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex, eq); | 2990 __ LoadRoot(tos, Heap::kUndefinedValueRootIndex, eq); | 
| 3003 frame_->EmitPush(scratch); | 2991 frame_->EmitPush(tos); | 
| 3004 } | 2992 } | 
| 3005 } | 2993 } | 
| 3006 } | 2994 } | 
| 3007 | 2995 | 
| 3008 | 2996 | 
| 3009 void CodeGenerator::LoadFromSlotCheckForArguments(Slot* slot, | 2997 void CodeGenerator::LoadFromSlotCheckForArguments(Slot* slot, | 
| 3010 TypeofState state) { | 2998 TypeofState state) { | 
| 2999 VirtualFrame::RegisterAllocationScope scope(this); | |
| 3011 LoadFromSlot(slot, state); | 3000 LoadFromSlot(slot, state); | 
| 3012 | 3001 | 
| 3013 // Bail out quickly if we're not using lazy arguments allocation. | 3002 // Bail out quickly if we're not using lazy arguments allocation. | 
| 3014 if (ArgumentsMode() != LAZY_ARGUMENTS_ALLOCATION) return; | 3003 if (ArgumentsMode() != LAZY_ARGUMENTS_ALLOCATION) return; | 
| 3015 | 3004 | 
| 3016 // ... or if the slot isn't a non-parameter arguments slot. | 3005 // ... or if the slot isn't a non-parameter arguments slot. | 
| 3017 if (slot->type() == Slot::PARAMETER || !slot->is_arguments()) return; | 3006 if (slot->type() == Slot::PARAMETER || !slot->is_arguments()) return; | 
| 3018 | 3007 | 
| 3019 VirtualFrame::SpilledScope spilled_scope(frame_); | 3008 // Load the loaded value from the stack into a register but leave it on the | 
| 3020 | |
| 3021 // Load the loaded value from the stack into r0 but leave it on the | |
| 3022 // stack. | 3009 // stack. | 
| 3023 __ ldr(r0, MemOperand(sp, 0)); | 3010 Register tos = frame_->Peek(); | 
| 3024 | 3011 | 
| 3025 // If the loaded value is the sentinel that indicates that we | 3012 // If the loaded value is the sentinel that indicates that we | 
| 3026 // haven't loaded the arguments object yet, we need to do it now. | 3013 // haven't loaded the arguments object yet, we need to do it now. | 
| 3027 JumpTarget exit; | 3014 JumpTarget exit; | 
| 3028 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 3015 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 
| 3029 __ cmp(r0, ip); | 3016 __ cmp(tos, ip); | 
| 3030 exit.Branch(ne); | 3017 exit.Branch(ne); | 
| 3031 frame_->Drop(); | 3018 frame_->Drop(); | 
| 3032 StoreArgumentsObject(false); | 3019 StoreArgumentsObject(false); | 
| 3033 exit.Bind(); | 3020 exit.Bind(); | 
| 3034 } | 3021 } | 
| 3035 | 3022 | 
| 3036 | 3023 | 
| 3037 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { | 3024 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { | 
| 3038 ASSERT(slot != NULL); | 3025 ASSERT(slot != NULL); | 
| 3026 VirtualFrame::RegisterAllocationScope scope(this); | |
| 3039 if (slot->type() == Slot::LOOKUP) { | 3027 if (slot->type() == Slot::LOOKUP) { | 
| 3040 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 3041 ASSERT(slot->var()->is_dynamic()); | 3028 ASSERT(slot->var()->is_dynamic()); | 
| 3042 | 3029 | 
| 3043 // For now, just do a runtime call. | 3030 // For now, just do a runtime call. | 
| 3044 frame_->EmitPush(cp); | 3031 frame_->EmitPush(cp); | 
| 3045 __ mov(r0, Operand(slot->var()->name())); | 3032 frame_->EmitPush(Operand(slot->var()->name())); | 
| 3046 frame_->EmitPush(r0); | |
| 3047 | 3033 | 
| 3048 if (init_state == CONST_INIT) { | 3034 if (init_state == CONST_INIT) { | 
| 3049 // Same as the case for a normal store, but ignores attribute | 3035 // Same as the case for a normal store, but ignores attribute | 
| 3050 // (e.g. READ_ONLY) of context slot so that we can initialize | 3036 // (e.g. READ_ONLY) of context slot so that we can initialize | 
| 3051 // const properties (introduced via eval("const foo = (some | 3037 // const properties (introduced via eval("const foo = (some | 
| 3052 // expr);")). Also, uses the current function context instead of | 3038 // expr);")). Also, uses the current function context instead of | 
| 3053 // the top context. | 3039 // the top context. | 
| 3054 // | 3040 // | 
| 3055 // Note that we must declare the foo upon entry of eval(), via a | 3041 // Note that we must declare the foo upon entry of eval(), via a | 
| 3056 // context slot declaration, but we cannot initialize it at the | 3042 // context slot declaration, but we cannot initialize it at the | 
| 3057 // same time, because the const declaration may be at the end of | 3043 // same time, because the const declaration may be at the end of | 
| 3058 // the eval code (sigh...) and the const variable may have been | 3044 // the eval code (sigh...) and the const variable may have been | 
| 3059 // used before (where its value is 'undefined'). Thus, we can only | 3045 // used before (where its value is 'undefined'). Thus, we can only | 
| 3060 // do the initialization when we actually encounter the expression | 3046 // do the initialization when we actually encounter the expression | 
| 3061 // and when the expression operands are defined and valid, and | 3047 // and when the expression operands are defined and valid, and | 
| 3062 // thus we need the split into 2 operations: declaration of the | 3048 // thus we need the split into 2 operations: declaration of the | 
| 3063 // context slot followed by initialization. | 3049 // context slot followed by initialization. | 
| 3064 frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 3050 frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 
| 3065 } else { | 3051 } else { | 
| 3066 frame_->CallRuntime(Runtime::kStoreContextSlot, 3); | 3052 frame_->CallRuntime(Runtime::kStoreContextSlot, 3); | 
| 3067 } | 3053 } | 
| 3068 // Storing a variable must keep the (new) value on the expression | 3054 // Storing a variable must keep the (new) value on the expression | 
| 3069 // stack. This is necessary for compiling assignment expressions. | 3055 // stack. This is necessary for compiling assignment expressions. | 
| 3070 frame_->EmitPush(r0); | 3056 frame_->EmitPush(r0); | 
| 3071 | 3057 | 
| 3072 } else { | 3058 } else { | 
| 3073 ASSERT(!slot->var()->is_dynamic()); | 3059 ASSERT(!slot->var()->is_dynamic()); | 
| 3074 Register scratch = VirtualFrame::scratch0(); | 3060 Register scratch = VirtualFrame::scratch0(); | 
| 3075 VirtualFrame::RegisterAllocationScope scope(this); | 3061 Register scratch2 = VirtualFrame::scratch1(); | 
| 3076 | 3062 | 
| 3077 // The frame must be spilled when branching to this target. | 3063 // The frame must be spilled when branching to this target. | 
| 3078 JumpTarget exit; | 3064 JumpTarget exit; | 
| 3079 | 3065 | 
| 3080 if (init_state == CONST_INIT) { | 3066 if (init_state == CONST_INIT) { | 
| 3081 ASSERT(slot->var()->mode() == Variable::CONST); | 3067 ASSERT(slot->var()->mode() == Variable::CONST); | 
| 3082 // Only the first const initialization must be executed (the slot | 3068 // Only the first const initialization must be executed (the slot | 
| 3083 // still contains 'the hole' value). When the assignment is | 3069 // still contains 'the hole' value). When the assignment is | 
| 3084 // executed, the code is identical to a normal store (see below). | 3070 // executed, the code is identical to a normal store (see below). | 
| 3085 Comment cmnt(masm_, "[ Init const"); | 3071 Comment cmnt(masm_, "[ Init const"); | 
| 3086 __ ldr(scratch, SlotOperand(slot, scratch)); | 3072 __ ldr(scratch, SlotOperand(slot, scratch)); | 
| 3087 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 3073 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 
| 3088 __ cmp(scratch, ip); | 3074 __ cmp(scratch, ip); | 
| 3089 frame_->SpillAll(); | |
| 3090 exit.Branch(ne); | 3075 exit.Branch(ne); | 
| 3091 } | 3076 } | 
| 3092 | 3077 | 
| 3093 // We must execute the store. Storing a variable must keep the | 3078 // We must execute the store. Storing a variable must keep the | 
| 3094 // (new) value on the stack. This is necessary for compiling | 3079 // (new) value on the stack. This is necessary for compiling | 
| 3095 // assignment expressions. | 3080 // assignment expressions. | 
| 3096 // | 3081 // | 
| 3097 // Note: We will reach here even with slot->var()->mode() == | 3082 // Note: We will reach here even with slot->var()->mode() == | 
| 3098 // Variable::CONST because of const declarations which will | 3083 // Variable::CONST because of const declarations which will | 
| 3099 // initialize consts to 'the hole' value and by doing so, end up | 3084 // initialize consts to 'the hole' value and by doing so, end up | 
| 3100 // calling this code. r2 may be loaded with context; used below in | 3085 // calling this code. r2 may be loaded with context; used below in | 
| 3101 // RecordWrite. | 3086 // RecordWrite. | 
| 3102 Register tos = frame_->Peek(); | 3087 Register tos = frame_->Peek(); | 
| 3103 __ str(tos, SlotOperand(slot, scratch)); | 3088 __ str(tos, SlotOperand(slot, scratch)); | 
| 3104 if (slot->type() == Slot::CONTEXT) { | 3089 if (slot->type() == Slot::CONTEXT) { | 
| 3105 // Skip write barrier if the written value is a smi. | 3090 // Skip write barrier if the written value is a smi. | 
| 3106 __ tst(tos, Operand(kSmiTagMask)); | 3091 __ tst(tos, Operand(kSmiTagMask)); | 
| 3107 // We don't use tos any more after here. | 3092 // We don't use tos any more after here. | 
| 3108 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 3109 exit.Branch(eq); | 3093 exit.Branch(eq); | 
| 3110 // scratch is loaded with context when calling SlotOperand above. | 3094 // scratch is loaded with context when calling SlotOperand above. | 
| 3111 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 3095 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 
| 3112 __ mov(r3, Operand(offset)); | 3096 __ mov(scratch2, Operand(offset)); | 
| 3113 // r1 could be identical with tos, but that doesn't matter. | 3097 // We need an extra register. Until we have a way to do that in the | 
| 3114 __ RecordWrite(scratch, r3, r1); | 3098 // virtual frame we will cheat and ask for a free TOS register. | 
| 3099 Register scratch3 = frame_->GetTOSRegister(); | |
| 3100 __ RecordWrite(scratch, scratch2, scratch3); | |
| 3115 } | 3101 } | 
| 3116 // If we definitely did not jump over the assignment, we do not need | 3102 // If we definitely did not jump over the assignment, we do not need | 
| 3117 // to bind the exit label. Doing so can defeat peephole | 3103 // to bind the exit label. Doing so can defeat peephole | 
| 3118 // optimization. | 3104 // optimization. | 
| 3119 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { | 3105 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { | 
| 3120 frame_->SpillAll(); | |
| 3121 exit.Bind(); | 3106 exit.Bind(); | 
| 3122 } | 3107 } | 
| 3123 } | 3108 } | 
| 3124 } | 3109 } | 
| 3125 | 3110 | 
| 3126 | 3111 | 
| 3127 void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, | 3112 void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, | 
| 3128 TypeofState typeof_state, | 3113 TypeofState typeof_state, | 
| 3129 JumpTarget* slow) { | 3114 JumpTarget* slow) { | 
| 3130 // Check that no extension objects have been created by calls to | 3115 // Check that no extension objects have been created by calls to | 
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3284 __ mov(reg, Operand(node->handle())); | 3269 __ mov(reg, Operand(node->handle())); | 
| 3285 frame_->EmitPush(reg, is_smi ? TypeInfo::Smi() : TypeInfo::Unknown()); | 3270 frame_->EmitPush(reg, is_smi ? TypeInfo::Smi() : TypeInfo::Unknown()); | 
| 3286 ASSERT_EQ(original_height + 1, frame_->height()); | 3271 ASSERT_EQ(original_height + 1, frame_->height()); | 
| 3287 } | 3272 } | 
| 3288 | 3273 | 
| 3289 | 3274 | 
| 3290 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 3275 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 
| 3291 #ifdef DEBUG | 3276 #ifdef DEBUG | 
| 3292 int original_height = frame_->height(); | 3277 int original_height = frame_->height(); | 
| 3293 #endif | 3278 #endif | 
| 3294 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 3295 Comment cmnt(masm_, "[ RexExp Literal"); | 3279 Comment cmnt(masm_, "[ RexExp Literal"); | 
| 3296 | 3280 | 
| 3281 Register tmp = VirtualFrame::scratch0(); | |
| 3282 // Free up a TOS register that can be used to push the literal. | |
| 3283 Register literal = frame_->GetTOSRegister(); | |
| 3284 | |
| 3297 // Retrieve the literal array and check the allocated entry. | 3285 // Retrieve the literal array and check the allocated entry. | 
| 3298 | 3286 | 
| 3299 // Load the function of this activation. | 3287 // Load the function of this activation. | 
| 3300 __ ldr(r1, frame_->Function()); | 3288 __ ldr(tmp, frame_->Function()); | 
| 3301 | 3289 | 
| 3302 // Load the literals array of the function. | 3290 // Load the literals array of the function. | 
| 3303 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); | 3291 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kLiteralsOffset)); | 
| 3304 | 3292 | 
| 3305 // Load the literal at the ast saved index. | 3293 // Load the literal at the ast saved index. | 
| 3306 int literal_offset = | 3294 int literal_offset = | 
| 3307 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 3295 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 
| 3308 __ ldr(r2, FieldMemOperand(r1, literal_offset)); | 3296 __ ldr(literal, FieldMemOperand(tmp, literal_offset)); | 
| 3309 | 3297 | 
| 3310 JumpTarget done; | 3298 JumpTarget done; | 
| 3311 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 3299 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 
| 3312 __ cmp(r2, ip); | 3300 __ cmp(literal, ip); | 
| 3301 // This branch locks the virtual frame at the done label to match the | |
| 3302 // one we have here, where the literal register is not on the stack and | |
| 3303 // nothing is spilled. | |
| 3313 done.Branch(ne); | 3304 done.Branch(ne); | 
| 3314 | 3305 | 
| 3315 // If the entry is undefined we call the runtime system to computed | 3306 // If the entry is undefined we call the runtime system to compute | 
| 3316 // the literal. | 3307 // the literal. | 
| 3317 frame_->EmitPush(r1); // literal array (0) | 3308 // literal array (0) | 
| 3318 __ mov(r0, Operand(Smi::FromInt(node->literal_index()))); | 3309 frame_->EmitPush(tmp); | 
| 3319 frame_->EmitPush(r0); // literal index (1) | 3310 // literal index (1) | 
| 3320 __ mov(r0, Operand(node->pattern())); // RegExp pattern (2) | 3311 frame_->EmitPush(Operand(Smi::FromInt(node->literal_index()))); | 
| 3321 frame_->EmitPush(r0); | 3312 // RegExp pattern (2) | 
| 3322 __ mov(r0, Operand(node->flags())); // RegExp flags (3) | 3313 frame_->EmitPush(Operand(node->pattern())); | 
| 3323 frame_->EmitPush(r0); | 3314 // RegExp flags (3) | 
| 3315 frame_->EmitPush(Operand(node->flags())); | |
| 3324 frame_->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 3316 frame_->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 
| 3325 __ mov(r2, Operand(r0)); | 3317 __ Move(literal, r0); | 
| 3326 | 3318 | 
| 3319 // This call to bind will get us back to the virtual frame we had before | |
| 3320 // where things are not spilled and the literal register is not on the stack. | |
| 3327 done.Bind(); | 3321 done.Bind(); | 
| 3328 // Push the literal. | 3322 // Push the literal. | 
| 3329 frame_->EmitPush(r2); | 3323 frame_->EmitPush(literal); | 
| 3330 ASSERT_EQ(original_height + 1, frame_->height()); | 3324 ASSERT_EQ(original_height + 1, frame_->height()); | 
| 3331 } | 3325 } | 
| 3332 | 3326 | 
| 3333 | 3327 | 
| 3334 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 3328 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 
| 3335 #ifdef DEBUG | 3329 #ifdef DEBUG | 
| 3336 int original_height = frame_->height(); | 3330 int original_height = frame_->height(); | 
| 3337 #endif | 3331 #endif | 
| 3338 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 3339 Comment cmnt(masm_, "[ ObjectLiteral"); | 3332 Comment cmnt(masm_, "[ ObjectLiteral"); | 
| 3340 | 3333 | 
| 3334 Register literal = frame_->GetTOSRegister(); | |
| 3341 // Load the function of this activation. | 3335 // Load the function of this activation. | 
| 3342 __ ldr(r3, frame_->Function()); | 3336 __ ldr(literal, frame_->Function()); | 
| 3343 // Literal array. | 3337 // Literal array. | 
| 3344 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); | 3338 __ ldr(literal, FieldMemOperand(literal, JSFunction::kLiteralsOffset)); | 
| 3339 frame_->EmitPush(literal); | |
| 3345 // Literal index. | 3340 // Literal index. | 
| 3346 __ mov(r2, Operand(Smi::FromInt(node->literal_index()))); | 3341 frame_->EmitPush(Operand(Smi::FromInt(node->literal_index()))); | 
| 3347 // Constant properties. | 3342 // Constant properties. | 
| 3348 __ mov(r1, Operand(node->constant_properties())); | 3343 frame_->EmitPush(Operand(node->constant_properties())); | 
| 3349 // Should the object literal have fast elements? | 3344 // Should the object literal have fast elements? | 
| 3350 __ mov(r0, Operand(Smi::FromInt(node->fast_elements() ? 1 : 0))); | 3345 frame_->EmitPush(Operand(Smi::FromInt(node->fast_elements() ? 1 : 0))); | 
| 3351 frame_->EmitPushMultiple(4, r3.bit() | r2.bit() | r1.bit() | r0.bit()); | |
| 3352 if (node->depth() > 1) { | 3346 if (node->depth() > 1) { | 
| 3353 frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4); | 3347 frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4); | 
| 3354 } else { | 3348 } else { | 
| 3355 frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); | 3349 frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); | 
| 3356 } | 3350 } | 
| 3357 frame_->EmitPush(r0); // save the result | 3351 frame_->EmitPush(r0); // save the result | 
| 3358 for (int i = 0; i < node->properties()->length(); i++) { | 3352 for (int i = 0; i < node->properties()->length(); i++) { | 
| 3359 // At the start of each iteration, the top of stack contains | 3353 // At the start of each iteration, the top of stack contains | 
| 3360 // the newly created object literal. | 3354 // the newly created object literal. | 
| 3361 ObjectLiteral::Property* property = node->properties()->at(i); | 3355 ObjectLiteral::Property* property = node->properties()->at(i); | 
| 3362 Literal* key = property->key(); | 3356 Literal* key = property->key(); | 
| 3363 Expression* value = property->value(); | 3357 Expression* value = property->value(); | 
| 3364 switch (property->kind()) { | 3358 switch (property->kind()) { | 
| 3365 case ObjectLiteral::Property::CONSTANT: | 3359 case ObjectLiteral::Property::CONSTANT: | 
| 3366 break; | 3360 break; | 
| 3367 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 3361 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 
| 3368 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; | 3362 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; | 
| 3369 // else fall through | 3363 // else fall through | 
| 3370 case ObjectLiteral::Property::COMPUTED: | 3364 case ObjectLiteral::Property::COMPUTED: | 
| 3371 if (key->handle()->IsSymbol()) { | 3365 if (key->handle()->IsSymbol()) { | 
| 3372 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 3366 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 
| 3373 Load(value); | 3367 Load(value); | 
| 3374 frame_->EmitPop(r0); | 3368 frame_->PopToR0(); | 
| 3369 // Fetch the object literal. | |
| 3370 frame_->SpillAllButCopyTOSToR1(); | |
| 3375 __ mov(r2, Operand(key->handle())); | 3371 __ mov(r2, Operand(key->handle())); | 
| 3376 __ ldr(r1, frame_->Top()); // Load the receiver. | |
| 3377 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 3372 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 
| 3378 break; | 3373 break; | 
| 3379 } | 3374 } | 
| 3380 // else fall through | 3375 // else fall through | 
| 3381 case ObjectLiteral::Property::PROTOTYPE: { | 3376 case ObjectLiteral::Property::PROTOTYPE: { | 
| 3382 __ ldr(r0, frame_->Top()); | 3377 frame_->Dup(); | 
| 3383 frame_->EmitPush(r0); // dup the result | |
| 3384 Load(key); | 3378 Load(key); | 
| 3385 Load(value); | 3379 Load(value); | 
| 3386 frame_->CallRuntime(Runtime::kSetProperty, 3); | 3380 frame_->CallRuntime(Runtime::kSetProperty, 3); | 
| 3387 break; | 3381 break; | 
| 3388 } | 3382 } | 
| 3389 case ObjectLiteral::Property::SETTER: { | 3383 case ObjectLiteral::Property::SETTER: { | 
| 3390 __ ldr(r0, frame_->Top()); | 3384 frame_->Dup(); | 
| 3391 frame_->EmitPush(r0); | |
| 3392 Load(key); | 3385 Load(key); | 
| 3393 __ mov(r0, Operand(Smi::FromInt(1))); | 3386 frame_->EmitPush(Operand(Smi::FromInt(1))); | 
| 3394 frame_->EmitPush(r0); | |
| 3395 Load(value); | 3387 Load(value); | 
| 3396 frame_->CallRuntime(Runtime::kDefineAccessor, 4); | 3388 frame_->CallRuntime(Runtime::kDefineAccessor, 4); | 
| 3397 break; | 3389 break; | 
| 3398 } | 3390 } | 
| 3399 case ObjectLiteral::Property::GETTER: { | 3391 case ObjectLiteral::Property::GETTER: { | 
| 3400 __ ldr(r0, frame_->Top()); | 3392 frame_->Dup(); | 
| 3401 frame_->EmitPush(r0); | |
| 3402 Load(key); | 3393 Load(key); | 
| 3403 __ mov(r0, Operand(Smi::FromInt(0))); | 3394 frame_->EmitPush(Operand(Smi::FromInt(0))); | 
| 3404 frame_->EmitPush(r0); | |
| 3405 Load(value); | 3395 Load(value); | 
| 3406 frame_->CallRuntime(Runtime::kDefineAccessor, 4); | 3396 frame_->CallRuntime(Runtime::kDefineAccessor, 4); | 
| 3407 break; | 3397 break; | 
| 3408 } | 3398 } | 
| 3409 } | 3399 } | 
| 3410 } | 3400 } | 
| 3411 ASSERT_EQ(original_height + 1, frame_->height()); | 3401 ASSERT_EQ(original_height + 1, frame_->height()); | 
| 3412 } | 3402 } | 
| 3413 | 3403 | 
| 3414 | 3404 | 
| 3415 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 3405 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 
| 3416 #ifdef DEBUG | 3406 #ifdef DEBUG | 
| 3417 int original_height = frame_->height(); | 3407 int original_height = frame_->height(); | 
| 3418 #endif | 3408 #endif | 
| 3419 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 3420 Comment cmnt(masm_, "[ ArrayLiteral"); | 3409 Comment cmnt(masm_, "[ ArrayLiteral"); | 
| 3421 | 3410 | 
| 3411 Register tos = frame_->GetTOSRegister(); | |
| 3422 // Load the function of this activation. | 3412 // Load the function of this activation. | 
| 3423 __ ldr(r2, frame_->Function()); | 3413 __ ldr(tos, frame_->Function()); | 
| 3424 // Load the literals array of the function. | 3414 // Load the literals array of the function. | 
| 3425 __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset)); | 3415 __ ldr(tos, FieldMemOperand(tos, JSFunction::kLiteralsOffset)); | 
| 3426 __ mov(r1, Operand(Smi::FromInt(node->literal_index()))); | 3416 frame_->EmitPush(tos); | 
| 3427 __ mov(r0, Operand(node->constant_elements())); | 3417 frame_->EmitPush(Operand(Smi::FromInt(node->literal_index()))); | 
| 3428 frame_->EmitPushMultiple(3, r2.bit() | r1.bit() | r0.bit()); | 3418 frame_->EmitPush(Operand(node->constant_elements())); | 
| 3429 int length = node->values()->length(); | 3419 int length = node->values()->length(); | 
| 3430 if (node->depth() > 1) { | 3420 if (node->depth() > 1) { | 
| 3431 frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3); | 3421 frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3); | 
| 3432 } else if (length > FastCloneShallowArrayStub::kMaximumLength) { | 3422 } else if (length > FastCloneShallowArrayStub::kMaximumLength) { | 
| 3433 frame_->CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); | 3423 frame_->CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); | 
| 3434 } else { | 3424 } else { | 
| 3435 FastCloneShallowArrayStub stub(length); | 3425 FastCloneShallowArrayStub stub(length); | 
| 3436 frame_->CallStub(&stub, 3); | 3426 frame_->CallStub(&stub, 3); | 
| 3437 } | 3427 } | 
| 3438 frame_->EmitPush(r0); // save the result | 3428 frame_->EmitPush(r0); // save the result | 
| 3439 // r0: created object literal | 3429 // r0: created object literal | 
| 3440 | 3430 | 
| 3441 // Generate code to set the elements in the array that are not | 3431 // Generate code to set the elements in the array that are not | 
| 3442 // literals. | 3432 // literals. | 
| 3443 for (int i = 0; i < node->values()->length(); i++) { | 3433 for (int i = 0; i < node->values()->length(); i++) { | 
| 3444 Expression* value = node->values()->at(i); | 3434 Expression* value = node->values()->at(i); | 
| 3445 | 3435 | 
| 3446 // If value is a literal the property value is already set in the | 3436 // If value is a literal the property value is already set in the | 
| 3447 // boilerplate object. | 3437 // boilerplate object. | 
| 3448 if (value->AsLiteral() != NULL) continue; | 3438 if (value->AsLiteral() != NULL) continue; | 
| 3449 // If value is a materialized literal the property value is already set | 3439 // If value is a materialized literal the property value is already set | 
| 3450 // in the boilerplate object if it is simple. | 3440 // in the boilerplate object if it is simple. | 
| 3451 if (CompileTimeValue::IsCompileTimeValue(value)) continue; | 3441 if (CompileTimeValue::IsCompileTimeValue(value)) continue; | 
| 3452 | 3442 | 
| 3453 // The property must be set by generated code. | 3443 // The property must be set by generated code. | 
| 3454 Load(value); | 3444 Load(value); | 
| 3455 frame_->EmitPop(r0); | 3445 frame_->PopToR0(); | 
| 3446 // Fetch the object literal. | |
| 3447 frame_->SpillAllButCopyTOSToR1(); | |
| 3456 | 3448 | 
| 3457 // Fetch the object literal. | |
| 3458 __ ldr(r1, frame_->Top()); | |
| 3459 // Get the elements array. | 3449 // Get the elements array. | 
| 3460 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); | 3450 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); | 
| 3461 | 3451 | 
| 3462 // Write to the indexed properties array. | 3452 // Write to the indexed properties array. | 
| 3463 int offset = i * kPointerSize + FixedArray::kHeaderSize; | 3453 int offset = i * kPointerSize + FixedArray::kHeaderSize; | 
| 3464 __ str(r0, FieldMemOperand(r1, offset)); | 3454 __ str(r0, FieldMemOperand(r1, offset)); | 
| 3465 | 3455 | 
| 3466 // Update the write barrier for the array address. | 3456 // Update the write barrier for the array address. | 
| 3467 __ mov(r3, Operand(offset)); | 3457 __ mov(r3, Operand(offset)); | 
| 3468 __ RecordWrite(r1, r3, r2); | 3458 __ RecordWrite(r1, r3, r2); | 
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3859 // ------------------------------------------------------------------------ | 3849 // ------------------------------------------------------------------------ | 
| 3860 // Fast-case: Use inline caching. | 3850 // Fast-case: Use inline caching. | 
| 3861 // --- | 3851 // --- | 
| 3862 // According to ECMA-262, section 11.2.3, page 44, the function to call | 3852 // According to ECMA-262, section 11.2.3, page 44, the function to call | 
| 3863 // must be resolved after the arguments have been evaluated. The IC code | 3853 // must be resolved after the arguments have been evaluated. The IC code | 
| 3864 // automatically handles this by loading the arguments before the function | 3854 // automatically handles this by loading the arguments before the function | 
| 3865 // is resolved in cache misses (this also holds for megamorphic calls). | 3855 // is resolved in cache misses (this also holds for megamorphic calls). | 
| 3866 // ------------------------------------------------------------------------ | 3856 // ------------------------------------------------------------------------ | 
| 3867 | 3857 | 
| 3868 if (var != NULL && var->is_possibly_eval()) { | 3858 if (var != NULL && var->is_possibly_eval()) { | 
| 3869 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 3870 // ---------------------------------- | 3859 // ---------------------------------- | 
| 3871 // JavaScript example: 'eval(arg)' // eval is not known to be shadowed | 3860 // JavaScript example: 'eval(arg)' // eval is not known to be shadowed | 
| 3872 // ---------------------------------- | 3861 // ---------------------------------- | 
| 3873 | 3862 | 
| 3874 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 3863 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 
| 3875 // resolve the function we need to call and the receiver of the | 3864 // resolve the function we need to call and the receiver of the | 
| 3876 // call. Then we call the resolved function using the given | 3865 // call. Then we call the resolved function using the given | 
| 3877 // arguments. | 3866 // arguments. | 
| 3878 | 3867 | 
| 3879 // Prepare stack for call to resolved function. | 3868 // Prepare stack for call to resolved function. | 
| 3880 Load(function); | 3869 Load(function); | 
| 3881 | 3870 | 
| 3882 // Allocate a frame slot for the receiver. | 3871 // Allocate a frame slot for the receiver. | 
| 3883 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); | 3872 frame_->EmitPushRoot(Heap::kUndefinedValueRootIndex); | 
| 3884 frame_->EmitPush(r2); | |
| 3885 | 3873 | 
| 3886 // Load the arguments. | 3874 // Load the arguments. | 
| 3887 int arg_count = args->length(); | 3875 int arg_count = args->length(); | 
| 3888 for (int i = 0; i < arg_count; i++) { | 3876 for (int i = 0; i < arg_count; i++) { | 
| 3889 Load(args->at(i)); | 3877 Load(args->at(i)); | 
| 3890 } | 3878 } | 
| 3891 | 3879 | 
| 3880 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 3881 | |
| 3892 // If we know that eval can only be shadowed by eval-introduced | 3882 // If we know that eval can only be shadowed by eval-introduced | 
| 3893 // variables we attempt to load the global eval function directly | 3883 // variables we attempt to load the global eval function directly | 
| 3894 // in generated code. If we succeed, there is no need to perform a | 3884 // in generated code. If we succeed, there is no need to perform a | 
| 3895 // context lookup in the runtime system. | 3885 // context lookup in the runtime system. | 
| 3896 JumpTarget done; | 3886 JumpTarget done; | 
| 3897 if (var->slot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { | 3887 if (var->slot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { | 
| 3898 ASSERT(var->slot()->type() == Slot::LOOKUP); | 3888 ASSERT(var->slot()->type() == Slot::LOOKUP); | 
| 3899 JumpTarget slow; | 3889 JumpTarget slow; | 
| 3900 // Prepare the stack for the call to | 3890 // Prepare the stack for the call to | 
| 3901 // ResolvePossiblyDirectEvalNoLookup by pushing the loaded | 3891 // ResolvePossiblyDirectEvalNoLookup by pushing the loaded | 
| (...skipping 6766 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10668 __ bind(&string_add_runtime); | 10658 __ bind(&string_add_runtime); | 
| 10669 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 10659 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 
| 10670 } | 10660 } | 
| 10671 | 10661 | 
| 10672 | 10662 | 
| 10673 #undef __ | 10663 #undef __ | 
| 10674 | 10664 | 
| 10675 } } // namespace v8::internal | 10665 } } // namespace v8::internal | 
| 10676 | 10666 | 
| 10677 #endif // V8_TARGET_ARCH_ARM | 10667 #endif // V8_TARGET_ARCH_ARM | 
| OLD | NEW |