| 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 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 masm_(masm), | 147 masm_(masm), |
| 148 info_(NULL), | 148 info_(NULL), |
| 149 frame_(NULL), | 149 frame_(NULL), |
| 150 allocator_(NULL), | 150 allocator_(NULL), |
| 151 state_(NULL), | 151 state_(NULL), |
| 152 loop_nesting_(0), | 152 loop_nesting_(0), |
| 153 in_safe_int32_mode_(false), | 153 in_safe_int32_mode_(false), |
| 154 safe_int32_mode_enabled_(true), | 154 safe_int32_mode_enabled_(true), |
| 155 function_return_is_shadowed_(false), | 155 function_return_is_shadowed_(false), |
| 156 in_spilled_code_(false), | 156 in_spilled_code_(false), |
| 157 jit_cookie_((FLAG_mask_constants_with_cookie) ? V8::RandomPrivate() : 0) { | 157 jit_cookie_((FLAG_mask_constants_with_cookie) ? |
| 158 V8::RandomPrivate(Isolate::Current()) : 0) { |
| 158 } | 159 } |
| 159 | 160 |
| 160 | 161 |
| 161 // Calling conventions: | 162 // Calling conventions: |
| 162 // ebp: caller's frame pointer | 163 // ebp: caller's frame pointer |
| 163 // esp: stack pointer | 164 // esp: stack pointer |
| 164 // edi: called JS function | 165 // edi: called JS function |
| 165 // esi: callee's context | 166 // esi: callee's context |
| 166 | 167 |
| 167 void CodeGenerator::Generate(CompilationInfo* info) { | 168 void CodeGenerator::Generate(CompilationInfo* info) { |
| 168 // Record the position for debugging purposes. | 169 // Record the position for debugging purposes. |
| 169 CodeForFunctionPosition(info->function()); | 170 CodeForFunctionPosition(info->function()); |
| 170 Comment cmnt(masm_, "[ function compiled by virtual frame code generator"); | 171 Comment cmnt(masm_, "[ function compiled by virtual frame code generator"); |
| 171 | 172 |
| 172 // Initialize state. | 173 // Initialize state. |
| 173 info_ = info; | 174 info_ = info; |
| 174 ASSERT(allocator_ == NULL); | 175 ASSERT(allocator_ == NULL); |
| 175 RegisterAllocator register_allocator(this); | 176 RegisterAllocator register_allocator(this); |
| 176 allocator_ = ®ister_allocator; | 177 allocator_ = ®ister_allocator; |
| 177 ASSERT(frame_ == NULL); | 178 ASSERT(frame_ == NULL); |
| 178 frame_ = new VirtualFrame(); | 179 frame_ = new VirtualFrame(); |
| 179 set_in_spilled_code(false); | 180 set_in_spilled_code(false); |
| 180 | 181 |
| 181 // Adjust for function-level loop nesting. | 182 // Adjust for function-level loop nesting. |
| 182 ASSERT_EQ(0, loop_nesting_); | 183 ASSERT_EQ(0, loop_nesting_); |
| 183 loop_nesting_ = info->is_in_loop() ? 1 : 0; | 184 loop_nesting_ = info->is_in_loop() ? 1 : 0; |
| 184 | 185 |
| 185 JumpTarget::set_compiling_deferred_code(false); | 186 Isolate::Current()->set_jump_target_compiling_deferred_code(false); |
| 186 | 187 |
| 187 { | 188 { |
| 188 CodeGenState state(this); | 189 CodeGenState state(this); |
| 189 | 190 |
| 190 // Entry: | 191 // Entry: |
| 191 // Stack: receiver, arguments, return address. | 192 // Stack: receiver, arguments, return address. |
| 192 // ebp: caller's frame pointer | 193 // ebp: caller's frame pointer |
| 193 // esp: stack pointer | 194 // esp: stack pointer |
| 194 // edi: called JS function | 195 // edi: called JS function |
| 195 // esi: callee's context | 196 // esi: callee's context |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 | 278 |
| 278 // Store the arguments object. This must happen after context | 279 // Store the arguments object. This must happen after context |
| 279 // initialization because the arguments object may be stored in | 280 // initialization because the arguments object may be stored in |
| 280 // the context. | 281 // the context. |
| 281 if (ArgumentsMode() != NO_ARGUMENTS_ALLOCATION) { | 282 if (ArgumentsMode() != NO_ARGUMENTS_ALLOCATION) { |
| 282 StoreArgumentsObject(true); | 283 StoreArgumentsObject(true); |
| 283 } | 284 } |
| 284 | 285 |
| 285 // Initialize ThisFunction reference if present. | 286 // Initialize ThisFunction reference if present. |
| 286 if (scope()->is_function_scope() && scope()->function() != NULL) { | 287 if (scope()->is_function_scope() && scope()->function() != NULL) { |
| 287 frame_->Push(Factory::the_hole_value()); | 288 frame_->Push(FACTORY->the_hole_value()); |
| 288 StoreToSlot(scope()->function()->AsSlot(), NOT_CONST_INIT); | 289 StoreToSlot(scope()->function()->AsSlot(), NOT_CONST_INIT); |
| 289 } | 290 } |
| 290 | 291 |
| 291 | 292 |
| 292 // Initialize the function return target after the locals are set | 293 // Initialize the function return target after the locals are set |
| 293 // up, because it needs the expected frame height from the frame. | 294 // up, because it needs the expected frame height from the frame. |
| 294 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); | 295 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); |
| 295 function_return_is_shadowed_ = false; | 296 function_return_is_shadowed_ = false; |
| 296 | 297 |
| 297 // Generate code to 'execute' declarations and initialize functions | 298 // Generate code to 'execute' declarations and initialize functions |
| (...skipping 15 matching lines...) Expand all Loading... |
| 313 // Ignore the return value. | 314 // Ignore the return value. |
| 314 } | 315 } |
| 315 CheckStack(); | 316 CheckStack(); |
| 316 | 317 |
| 317 // Compile the body of the function in a vanilla state. Don't | 318 // Compile the body of the function in a vanilla state. Don't |
| 318 // bother compiling all the code if the scope has an illegal | 319 // bother compiling all the code if the scope has an illegal |
| 319 // redeclaration. | 320 // redeclaration. |
| 320 if (!scope()->HasIllegalRedeclaration()) { | 321 if (!scope()->HasIllegalRedeclaration()) { |
| 321 Comment cmnt(masm_, "[ function body"); | 322 Comment cmnt(masm_, "[ function body"); |
| 322 #ifdef DEBUG | 323 #ifdef DEBUG |
| 323 bool is_builtin = Bootstrapper::IsActive(); | 324 bool is_builtin = info->isolate()->bootstrapper()->IsActive(); |
| 324 bool should_trace = | 325 bool should_trace = |
| 325 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; | 326 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; |
| 326 if (should_trace) { | 327 if (should_trace) { |
| 327 frame_->CallRuntime(Runtime::kDebugTrace, 0); | 328 frame_->CallRuntime(Runtime::kDebugTrace, 0); |
| 328 // Ignore the return value. | 329 // Ignore the return value. |
| 329 } | 330 } |
| 330 #endif | 331 #endif |
| 331 VisitStatements(info->function()->body()); | 332 VisitStatements(info->function()->body()); |
| 332 | 333 |
| 333 // Handle the return from the function. | 334 // Handle the return from the function. |
| 334 if (has_valid_frame()) { | 335 if (has_valid_frame()) { |
| 335 // If there is a valid frame, control flow can fall off the end of | 336 // If there is a valid frame, control flow can fall off the end of |
| 336 // the body. In that case there is an implicit return statement. | 337 // the body. In that case there is an implicit return statement. |
| 337 ASSERT(!function_return_is_shadowed_); | 338 ASSERT(!function_return_is_shadowed_); |
| 338 CodeForReturnPosition(info->function()); | 339 CodeForReturnPosition(info->function()); |
| 339 frame_->PrepareForReturn(); | 340 frame_->PrepareForReturn(); |
| 340 Result undefined(Factory::undefined_value()); | 341 Result undefined(FACTORY->undefined_value()); |
| 341 if (function_return_.is_bound()) { | 342 if (function_return_.is_bound()) { |
| 342 function_return_.Jump(&undefined); | 343 function_return_.Jump(&undefined); |
| 343 } else { | 344 } else { |
| 344 function_return_.Bind(&undefined); | 345 function_return_.Bind(&undefined); |
| 345 GenerateReturnSequence(&undefined); | 346 GenerateReturnSequence(&undefined); |
| 346 } | 347 } |
| 347 } else if (function_return_.is_linked()) { | 348 } else if (function_return_.is_linked()) { |
| 348 // If the return target has dangling jumps to it, then we have not | 349 // If the return target has dangling jumps to it, then we have not |
| 349 // yet generated the return sequence. This can happen when (a) | 350 // yet generated the return sequence. This can happen when (a) |
| 350 // control does not flow off the end of the body so we did not | 351 // control does not flow off the end of the body so we did not |
| (...skipping 11 matching lines...) Expand all Loading... |
| 362 loop_nesting_ = 0; | 363 loop_nesting_ = 0; |
| 363 | 364 |
| 364 // Code generation state must be reset. | 365 // Code generation state must be reset. |
| 365 ASSERT(state_ == NULL); | 366 ASSERT(state_ == NULL); |
| 366 ASSERT(!function_return_is_shadowed_); | 367 ASSERT(!function_return_is_shadowed_); |
| 367 function_return_.Unuse(); | 368 function_return_.Unuse(); |
| 368 DeleteFrame(); | 369 DeleteFrame(); |
| 369 | 370 |
| 370 // Process any deferred code using the register allocator. | 371 // Process any deferred code using the register allocator. |
| 371 if (!HasStackOverflow()) { | 372 if (!HasStackOverflow()) { |
| 372 JumpTarget::set_compiling_deferred_code(true); | 373 info->isolate()->set_jump_target_compiling_deferred_code(true); |
| 373 ProcessDeferred(); | 374 ProcessDeferred(); |
| 374 JumpTarget::set_compiling_deferred_code(false); | 375 info->isolate()->set_jump_target_compiling_deferred_code(false); |
| 375 } | 376 } |
| 376 | 377 |
| 377 // There is no need to delete the register allocator, it is a | 378 // There is no need to delete the register allocator, it is a |
| 378 // stack-allocated local. | 379 // stack-allocated local. |
| 379 allocator_ = NULL; | 380 allocator_ = NULL; |
| 380 } | 381 } |
| 381 | 382 |
| 382 | 383 |
| 383 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 384 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
| 384 // Currently, this assertion will fail if we try to assign to | 385 // Currently, this assertion will fail if we try to assign to |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 548 void CodeGenerator::ConvertInt32ResultToNumber(Result* value) { | 549 void CodeGenerator::ConvertInt32ResultToNumber(Result* value) { |
| 549 ASSERT(value->is_untagged_int32()); | 550 ASSERT(value->is_untagged_int32()); |
| 550 if (value->is_register()) { | 551 if (value->is_register()) { |
| 551 Register val = value->reg(); | 552 Register val = value->reg(); |
| 552 JumpTarget done; | 553 JumpTarget done; |
| 553 __ add(val, Operand(val)); | 554 __ add(val, Operand(val)); |
| 554 done.Branch(no_overflow, value); | 555 done.Branch(no_overflow, value); |
| 555 __ sar(val, 1); | 556 __ sar(val, 1); |
| 556 // If there was an overflow, bits 30 and 31 of the original number disagree. | 557 // If there was an overflow, bits 30 and 31 of the original number disagree. |
| 557 __ xor_(val, 0x80000000u); | 558 __ xor_(val, 0x80000000u); |
| 558 if (CpuFeatures::IsSupported(SSE2)) { | 559 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 559 CpuFeatures::Scope fscope(SSE2); | 560 CpuFeatures::Scope fscope(SSE2); |
| 560 __ cvtsi2sd(xmm0, Operand(val)); | 561 __ cvtsi2sd(xmm0, Operand(val)); |
| 561 } else { | 562 } else { |
| 562 // Move val to ST[0] in the FPU | 563 // Move val to ST[0] in the FPU |
| 563 // Push and pop are safe with respect to the virtual frame because | 564 // Push and pop are safe with respect to the virtual frame because |
| 564 // all synced elements are below the actual stack pointer. | 565 // all synced elements are below the actual stack pointer. |
| 565 __ push(val); | 566 __ push(val); |
| 566 __ fild_s(Operand(esp, 0)); | 567 __ fild_s(Operand(esp, 0)); |
| 567 __ pop(val); | 568 __ pop(val); |
| 568 } | 569 } |
| 569 Result scratch = allocator_->Allocate(); | 570 Result scratch = allocator_->Allocate(); |
| 570 ASSERT(scratch.is_register()); | 571 ASSERT(scratch.is_register()); |
| 571 Label allocation_failed; | 572 Label allocation_failed; |
| 572 __ AllocateHeapNumber(val, scratch.reg(), | 573 __ AllocateHeapNumber(val, scratch.reg(), |
| 573 no_reg, &allocation_failed); | 574 no_reg, &allocation_failed); |
| 574 VirtualFrame* clone = new VirtualFrame(frame_); | 575 VirtualFrame* clone = new VirtualFrame(frame_); |
| 575 scratch.Unuse(); | 576 scratch.Unuse(); |
| 576 if (CpuFeatures::IsSupported(SSE2)) { | 577 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 577 CpuFeatures::Scope fscope(SSE2); | 578 CpuFeatures::Scope fscope(SSE2); |
| 578 __ movdbl(FieldOperand(val, HeapNumber::kValueOffset), xmm0); | 579 __ movdbl(FieldOperand(val, HeapNumber::kValueOffset), xmm0); |
| 579 } else { | 580 } else { |
| 580 __ fstp_d(FieldOperand(val, HeapNumber::kValueOffset)); | 581 __ fstp_d(FieldOperand(val, HeapNumber::kValueOffset)); |
| 581 } | 582 } |
| 582 done.Jump(value); | 583 done.Jump(value); |
| 583 | 584 |
| 584 // Establish the virtual frame, cloned from where AllocateHeapNumber | 585 // Establish the virtual frame, cloned from where AllocateHeapNumber |
| 585 // jumped to allocation_failed. | 586 // jumped to allocation_failed. |
| 586 RegisterFile empty_regs; | 587 RegisterFile empty_regs; |
| 587 SetFrame(clone, &empty_regs); | 588 SetFrame(clone, &empty_regs); |
| 588 __ bind(&allocation_failed); | 589 __ bind(&allocation_failed); |
| 589 if (!CpuFeatures::IsSupported(SSE2)) { | 590 if (!Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 590 // Pop the value from the floating point stack. | 591 // Pop the value from the floating point stack. |
| 591 __ fstp(0); | 592 __ fstp(0); |
| 592 } | 593 } |
| 593 unsafe_bailout_->Jump(); | 594 unsafe_bailout_->Jump(); |
| 594 | 595 |
| 595 done.Bind(value); | 596 done.Bind(value); |
| 596 } else { | 597 } else { |
| 597 ASSERT(value->is_constant()); | 598 ASSERT(value->is_constant()); |
| 598 } | 599 } |
| 599 value->set_untagged_int32(false); | 600 value->set_untagged_int32(false); |
| 600 value->set_type_info(TypeInfo::Integer32()); | 601 value->set_type_info(TypeInfo::Integer32()); |
| 601 } | 602 } |
| 602 | 603 |
| 603 | 604 |
| 604 void CodeGenerator::Load(Expression* expr) { | 605 void CodeGenerator::Load(Expression* expr) { |
| 605 #ifdef DEBUG | 606 #ifdef DEBUG |
| 606 int original_height = frame_->height(); | 607 int original_height = frame_->height(); |
| 607 #endif | 608 #endif |
| 608 ASSERT(!in_spilled_code()); | 609 ASSERT(!in_spilled_code()); |
| 609 | 610 |
| 610 // If the expression should be a side-effect-free 32-bit int computation, | 611 // If the expression should be a side-effect-free 32-bit int computation, |
| 611 // compile that SafeInt32 path, and a bailout path. | 612 // compile that SafeInt32 path, and a bailout path. |
| 612 if (!in_safe_int32_mode() && | 613 if (!in_safe_int32_mode() && |
| 613 safe_int32_mode_enabled() && | 614 safe_int32_mode_enabled() && |
| 614 expr->side_effect_free() && | 615 expr->side_effect_free() && |
| 615 expr->num_bit_ops() > 2 && | 616 expr->num_bit_ops() > 2 && |
| 616 CpuFeatures::IsSupported(SSE2)) { | 617 Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 617 BreakTarget unsafe_bailout; | 618 BreakTarget unsafe_bailout; |
| 618 JumpTarget done; | 619 JumpTarget done; |
| 619 unsafe_bailout.set_expected_height(frame_->height()); | 620 unsafe_bailout.set_expected_height(frame_->height()); |
| 620 LoadInSafeInt32Mode(expr, &unsafe_bailout); | 621 LoadInSafeInt32Mode(expr, &unsafe_bailout); |
| 621 done.Jump(); | 622 done.Jump(); |
| 622 | 623 |
| 623 if (unsafe_bailout.is_linked()) { | 624 if (unsafe_bailout.is_linked()) { |
| 624 unsafe_bailout.Bind(); | 625 unsafe_bailout.Bind(); |
| 625 LoadWithSafeInt32ModeDisabled(expr); | 626 LoadWithSafeInt32ModeDisabled(expr); |
| 626 } | 627 } |
| 627 done.Bind(); | 628 done.Bind(); |
| 628 } else { | 629 } else { |
| 629 JumpTarget true_target; | 630 JumpTarget true_target; |
| 630 JumpTarget false_target; | 631 JumpTarget false_target; |
| 631 ControlDestination dest(&true_target, &false_target, true); | 632 ControlDestination dest(&true_target, &false_target, true); |
| 632 LoadCondition(expr, &dest, false); | 633 LoadCondition(expr, &dest, false); |
| 633 | 634 |
| 634 if (dest.false_was_fall_through()) { | 635 if (dest.false_was_fall_through()) { |
| 635 // The false target was just bound. | 636 // The false target was just bound. |
| 636 JumpTarget loaded; | 637 JumpTarget loaded; |
| 637 frame_->Push(Factory::false_value()); | 638 frame_->Push(FACTORY->false_value()); |
| 638 // There may be dangling jumps to the true target. | 639 // There may be dangling jumps to the true target. |
| 639 if (true_target.is_linked()) { | 640 if (true_target.is_linked()) { |
| 640 loaded.Jump(); | 641 loaded.Jump(); |
| 641 true_target.Bind(); | 642 true_target.Bind(); |
| 642 frame_->Push(Factory::true_value()); | 643 frame_->Push(FACTORY->true_value()); |
| 643 loaded.Bind(); | 644 loaded.Bind(); |
| 644 } | 645 } |
| 645 | 646 |
| 646 } else if (dest.is_used()) { | 647 } else if (dest.is_used()) { |
| 647 // There is true, and possibly false, control flow (with true as | 648 // There is true, and possibly false, control flow (with true as |
| 648 // the fall through). | 649 // the fall through). |
| 649 JumpTarget loaded; | 650 JumpTarget loaded; |
| 650 frame_->Push(Factory::true_value()); | 651 frame_->Push(FACTORY->true_value()); |
| 651 if (false_target.is_linked()) { | 652 if (false_target.is_linked()) { |
| 652 loaded.Jump(); | 653 loaded.Jump(); |
| 653 false_target.Bind(); | 654 false_target.Bind(); |
| 654 frame_->Push(Factory::false_value()); | 655 frame_->Push(FACTORY->false_value()); |
| 655 loaded.Bind(); | 656 loaded.Bind(); |
| 656 } | 657 } |
| 657 | 658 |
| 658 } else { | 659 } else { |
| 659 // We have a valid value on top of the frame, but we still may | 660 // We have a valid value on top of the frame, but we still may |
| 660 // have dangling jumps to the true and false targets from nested | 661 // have dangling jumps to the true and false targets from nested |
| 661 // subexpressions (eg, the left subexpressions of the | 662 // subexpressions (eg, the left subexpressions of the |
| 662 // short-circuited boolean operators). | 663 // short-circuited boolean operators). |
| 663 ASSERT(has_valid_frame()); | 664 ASSERT(has_valid_frame()); |
| 664 if (true_target.is_linked() || false_target.is_linked()) { | 665 if (true_target.is_linked() || false_target.is_linked()) { |
| 665 JumpTarget loaded; | 666 JumpTarget loaded; |
| 666 loaded.Jump(); // Don't lose the current TOS. | 667 loaded.Jump(); // Don't lose the current TOS. |
| 667 if (true_target.is_linked()) { | 668 if (true_target.is_linked()) { |
| 668 true_target.Bind(); | 669 true_target.Bind(); |
| 669 frame_->Push(Factory::true_value()); | 670 frame_->Push(FACTORY->true_value()); |
| 670 if (false_target.is_linked()) { | 671 if (false_target.is_linked()) { |
| 671 loaded.Jump(); | 672 loaded.Jump(); |
| 672 } | 673 } |
| 673 } | 674 } |
| 674 if (false_target.is_linked()) { | 675 if (false_target.is_linked()) { |
| 675 false_target.Bind(); | 676 false_target.Bind(); |
| 676 frame_->Push(Factory::false_value()); | 677 frame_->Push(FACTORY->false_value()); |
| 677 } | 678 } |
| 678 loaded.Bind(); | 679 loaded.Bind(); |
| 679 } | 680 } |
| 680 } | 681 } |
| 681 } | 682 } |
| 682 ASSERT(has_valid_frame()); | 683 ASSERT(has_valid_frame()); |
| 683 ASSERT(frame_->height() == original_height + 1); | 684 ASSERT(frame_->height() == original_height + 1); |
| 684 } | 685 } |
| 685 | 686 |
| 686 | 687 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 744 | 745 |
| 745 Result CodeGenerator::StoreArgumentsObject(bool initial) { | 746 Result CodeGenerator::StoreArgumentsObject(bool initial) { |
| 746 ArgumentsAllocationMode mode = ArgumentsMode(); | 747 ArgumentsAllocationMode mode = ArgumentsMode(); |
| 747 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); | 748 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); |
| 748 | 749 |
| 749 Comment cmnt(masm_, "[ store arguments object"); | 750 Comment cmnt(masm_, "[ store arguments object"); |
| 750 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { | 751 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { |
| 751 // When using lazy arguments allocation, we store the arguments marker value | 752 // When using lazy arguments allocation, we store the arguments marker value |
| 752 // as a sentinel indicating that the arguments object hasn't been | 753 // as a sentinel indicating that the arguments object hasn't been |
| 753 // allocated yet. | 754 // allocated yet. |
| 754 frame_->Push(Factory::arguments_marker()); | 755 frame_->Push(FACTORY->arguments_marker()); |
| 755 } else { | 756 } else { |
| 756 ArgumentsAccessStub stub(is_strict_mode() | 757 ArgumentsAccessStub stub(is_strict_mode() |
| 757 ? ArgumentsAccessStub::NEW_STRICT | 758 ? ArgumentsAccessStub::NEW_STRICT |
| 758 : ArgumentsAccessStub::NEW_NON_STRICT); | 759 : ArgumentsAccessStub::NEW_NON_STRICT); |
| 759 frame_->PushFunction(); | 760 frame_->PushFunction(); |
| 760 frame_->PushReceiverSlotAddress(); | 761 frame_->PushReceiverSlotAddress(); |
| 761 frame_->Push(Smi::FromInt(scope()->num_parameters())); | 762 frame_->Push(Smi::FromInt(scope()->num_parameters())); |
| 762 Result result = frame_->CallStub(&stub, 3); | 763 Result result = frame_->CallStub(&stub, 3); |
| 763 frame_->Push(&result); | 764 frame_->Push(&result); |
| 764 } | 765 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 776 // We have to skip storing into the arguments slot if it has | 777 // We have to skip storing into the arguments slot if it has |
| 777 // already been written to. This can happen if the a function | 778 // already been written to. This can happen if the a function |
| 778 // has a local variable named 'arguments'. | 779 // has a local variable named 'arguments'. |
| 779 LoadFromSlot(arguments->AsSlot(), NOT_INSIDE_TYPEOF); | 780 LoadFromSlot(arguments->AsSlot(), NOT_INSIDE_TYPEOF); |
| 780 Result probe = frame_->Pop(); | 781 Result probe = frame_->Pop(); |
| 781 if (probe.is_constant()) { | 782 if (probe.is_constant()) { |
| 782 // We have to skip updating the arguments object if it has | 783 // We have to skip updating the arguments object if it has |
| 783 // been assigned a proper value. | 784 // been assigned a proper value. |
| 784 skip_arguments = !probe.handle()->IsArgumentsMarker(); | 785 skip_arguments = !probe.handle()->IsArgumentsMarker(); |
| 785 } else { | 786 } else { |
| 786 __ cmp(Operand(probe.reg()), Immediate(Factory::arguments_marker())); | 787 __ cmp(Operand(probe.reg()), Immediate(FACTORY->arguments_marker())); |
| 787 probe.Unuse(); | 788 probe.Unuse(); |
| 788 done.Branch(not_equal); | 789 done.Branch(not_equal); |
| 789 } | 790 } |
| 790 } | 791 } |
| 791 if (!skip_arguments) { | 792 if (!skip_arguments) { |
| 792 StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); | 793 StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); |
| 793 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); | 794 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); |
| 794 } | 795 } |
| 795 if (shadow != NULL) { | 796 if (shadow != NULL) { |
| 796 StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); | 797 StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 907 __ test(value.reg(), Immediate(kSmiTagMask)); | 908 __ test(value.reg(), Immediate(kSmiTagMask)); |
| 908 dest->true_target()->Branch(zero); | 909 dest->true_target()->Branch(zero); |
| 909 __ fldz(); | 910 __ fldz(); |
| 910 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); | 911 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); |
| 911 __ FCmp(); | 912 __ FCmp(); |
| 912 value.Unuse(); | 913 value.Unuse(); |
| 913 dest->Split(not_zero); | 914 dest->Split(not_zero); |
| 914 } else { | 915 } else { |
| 915 // Fast case checks. | 916 // Fast case checks. |
| 916 // 'false' => false. | 917 // 'false' => false. |
| 917 __ cmp(value.reg(), Factory::false_value()); | 918 __ cmp(value.reg(), FACTORY->false_value()); |
| 918 dest->false_target()->Branch(equal); | 919 dest->false_target()->Branch(equal); |
| 919 | 920 |
| 920 // 'true' => true. | 921 // 'true' => true. |
| 921 __ cmp(value.reg(), Factory::true_value()); | 922 __ cmp(value.reg(), FACTORY->true_value()); |
| 922 dest->true_target()->Branch(equal); | 923 dest->true_target()->Branch(equal); |
| 923 | 924 |
| 924 // 'undefined' => false. | 925 // 'undefined' => false. |
| 925 __ cmp(value.reg(), Factory::undefined_value()); | 926 __ cmp(value.reg(), FACTORY->undefined_value()); |
| 926 dest->false_target()->Branch(equal); | 927 dest->false_target()->Branch(equal); |
| 927 | 928 |
| 928 // Smi => false iff zero. | 929 // Smi => false iff zero. |
| 929 STATIC_ASSERT(kSmiTag == 0); | 930 STATIC_ASSERT(kSmiTag == 0); |
| 930 __ test(value.reg(), Operand(value.reg())); | 931 __ test(value.reg(), Operand(value.reg())); |
| 931 dest->false_target()->Branch(zero); | 932 dest->false_target()->Branch(zero); |
| 932 __ test(value.reg(), Immediate(kSmiTagMask)); | 933 __ test(value.reg(), Immediate(kSmiTagMask)); |
| 933 dest->true_target()->Branch(zero); | 934 dest->true_target()->Branch(zero); |
| 934 | 935 |
| 935 // Call the stub for all other cases. | 936 // Call the stub for all other cases. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 986 TypeInfo right_info_; | 987 TypeInfo right_info_; |
| 987 OverwriteMode mode_; | 988 OverwriteMode mode_; |
| 988 Label answer_out_of_range_; | 989 Label answer_out_of_range_; |
| 989 Label non_smi_input_; | 990 Label non_smi_input_; |
| 990 Label constant_rhs_; | 991 Label constant_rhs_; |
| 991 Smi* smi_value_; | 992 Smi* smi_value_; |
| 992 }; | 993 }; |
| 993 | 994 |
| 994 | 995 |
| 995 Label* DeferredInlineBinaryOperation::NonSmiInputLabel() { | 996 Label* DeferredInlineBinaryOperation::NonSmiInputLabel() { |
| 996 if (Token::IsBitOp(op_) && CpuFeatures::IsSupported(SSE2)) { | 997 if (Token::IsBitOp(op_) && |
| 998 Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 997 return &non_smi_input_; | 999 return &non_smi_input_; |
| 998 } else { | 1000 } else { |
| 999 return entry_label(); | 1001 return entry_label(); |
| 1000 } | 1002 } |
| 1001 } | 1003 } |
| 1002 | 1004 |
| 1003 | 1005 |
| 1004 void DeferredInlineBinaryOperation::JumpToAnswerOutOfRange(Condition cond) { | 1006 void DeferredInlineBinaryOperation::JumpToAnswerOutOfRange(Condition cond) { |
| 1005 __ j(cond, &answer_out_of_range_); | 1007 __ j(cond, &answer_out_of_range_); |
| 1006 } | 1008 } |
| 1007 | 1009 |
| 1008 | 1010 |
| 1009 void DeferredInlineBinaryOperation::JumpToConstantRhs(Condition cond, | 1011 void DeferredInlineBinaryOperation::JumpToConstantRhs(Condition cond, |
| 1010 Smi* smi_value) { | 1012 Smi* smi_value) { |
| 1011 smi_value_ = smi_value; | 1013 smi_value_ = smi_value; |
| 1012 __ j(cond, &constant_rhs_); | 1014 __ j(cond, &constant_rhs_); |
| 1013 } | 1015 } |
| 1014 | 1016 |
| 1015 | 1017 |
| 1016 void DeferredInlineBinaryOperation::Generate() { | 1018 void DeferredInlineBinaryOperation::Generate() { |
| 1017 // Registers are not saved implicitly for this stub, so we should not | 1019 // Registers are not saved implicitly for this stub, so we should not |
| 1018 // tread on the registers that were not passed to us. | 1020 // tread on the registers that were not passed to us. |
| 1019 if (CpuFeatures::IsSupported(SSE2) && | 1021 if (Isolate::Current()->cpu_features()->IsSupported(SSE2) && |
| 1020 ((op_ == Token::ADD) || | 1022 ((op_ == Token::ADD) || |
| 1021 (op_ == Token::SUB) || | 1023 (op_ == Token::SUB) || |
| 1022 (op_ == Token::MUL) || | 1024 (op_ == Token::MUL) || |
| 1023 (op_ == Token::DIV))) { | 1025 (op_ == Token::DIV))) { |
| 1024 CpuFeatures::Scope use_sse2(SSE2); | 1026 CpuFeatures::Scope use_sse2(SSE2); |
| 1025 Label call_runtime, after_alloc_failure; | 1027 Label call_runtime, after_alloc_failure; |
| 1026 Label left_smi, right_smi, load_right, do_op; | 1028 Label left_smi, right_smi, load_right, do_op; |
| 1027 if (!left_info_.IsSmi()) { | 1029 if (!left_info_.IsSmi()) { |
| 1028 __ test(left_, Immediate(kSmiTagMask)); | 1030 __ test(left_, Immediate(kSmiTagMask)); |
| 1029 __ j(zero, &left_smi); | 1031 __ j(zero, &left_smi); |
| 1030 if (!left_info_.IsNumber()) { | 1032 if (!left_info_.IsNumber()) { |
| 1031 __ cmp(FieldOperand(left_, HeapObject::kMapOffset), | 1033 __ cmp(FieldOperand(left_, HeapObject::kMapOffset), |
| 1032 Factory::heap_number_map()); | 1034 FACTORY->heap_number_map()); |
| 1033 __ j(not_equal, &call_runtime); | 1035 __ j(not_equal, &call_runtime); |
| 1034 } | 1036 } |
| 1035 __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset)); | 1037 __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset)); |
| 1036 if (mode_ == OVERWRITE_LEFT) { | 1038 if (mode_ == OVERWRITE_LEFT) { |
| 1037 __ mov(dst_, left_); | 1039 __ mov(dst_, left_); |
| 1038 } | 1040 } |
| 1039 __ jmp(&load_right); | 1041 __ jmp(&load_right); |
| 1040 | 1042 |
| 1041 __ bind(&left_smi); | 1043 __ bind(&left_smi); |
| 1042 } else { | 1044 } else { |
| 1043 if (FLAG_debug_code) __ AbortIfNotSmi(left_); | 1045 if (FLAG_debug_code) __ AbortIfNotSmi(left_); |
| 1044 } | 1046 } |
| 1045 __ SmiUntag(left_); | 1047 __ SmiUntag(left_); |
| 1046 __ cvtsi2sd(xmm0, Operand(left_)); | 1048 __ cvtsi2sd(xmm0, Operand(left_)); |
| 1047 __ SmiTag(left_); | 1049 __ SmiTag(left_); |
| 1048 if (mode_ == OVERWRITE_LEFT) { | 1050 if (mode_ == OVERWRITE_LEFT) { |
| 1049 Label alloc_failure; | 1051 Label alloc_failure; |
| 1050 __ push(left_); | 1052 __ push(left_); |
| 1051 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 1053 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); |
| 1052 __ pop(left_); | 1054 __ pop(left_); |
| 1053 } | 1055 } |
| 1054 | 1056 |
| 1055 __ bind(&load_right); | 1057 __ bind(&load_right); |
| 1056 if (!right_info_.IsSmi()) { | 1058 if (!right_info_.IsSmi()) { |
| 1057 __ test(right_, Immediate(kSmiTagMask)); | 1059 __ test(right_, Immediate(kSmiTagMask)); |
| 1058 __ j(zero, &right_smi); | 1060 __ j(zero, &right_smi); |
| 1059 if (!right_info_.IsNumber()) { | 1061 if (!right_info_.IsNumber()) { |
| 1060 __ cmp(FieldOperand(right_, HeapObject::kMapOffset), | 1062 __ cmp(FieldOperand(right_, HeapObject::kMapOffset), |
| 1061 Factory::heap_number_map()); | 1063 FACTORY->heap_number_map()); |
| 1062 __ j(not_equal, &call_runtime); | 1064 __ j(not_equal, &call_runtime); |
| 1063 } | 1065 } |
| 1064 __ movdbl(xmm1, FieldOperand(right_, HeapNumber::kValueOffset)); | 1066 __ movdbl(xmm1, FieldOperand(right_, HeapNumber::kValueOffset)); |
| 1065 if (mode_ == OVERWRITE_RIGHT) { | 1067 if (mode_ == OVERWRITE_RIGHT) { |
| 1066 __ mov(dst_, right_); | 1068 __ mov(dst_, right_); |
| 1067 } else if (mode_ == NO_OVERWRITE) { | 1069 } else if (mode_ == NO_OVERWRITE) { |
| 1068 Label alloc_failure; | 1070 Label alloc_failure; |
| 1069 __ push(left_); | 1071 __ push(left_); |
| 1070 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 1072 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); |
| 1071 __ pop(left_); | 1073 __ pop(left_); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1145 } | 1147 } |
| 1146 | 1148 |
| 1147 __ bind(&non_smi_input_); | 1149 __ bind(&non_smi_input_); |
| 1148 | 1150 |
| 1149 if (rhs_is_constant) { | 1151 if (rhs_is_constant) { |
| 1150 __ bind(&constant_rhs_); | 1152 __ bind(&constant_rhs_); |
| 1151 // In this case the input is a heap object and it is in the dst_ register. | 1153 // In this case the input is a heap object and it is in the dst_ register. |
| 1152 // The left_ and right_ registers have not been initialized yet. | 1154 // The left_ and right_ registers have not been initialized yet. |
| 1153 __ mov(right_, Immediate(smi_value_)); | 1155 __ mov(right_, Immediate(smi_value_)); |
| 1154 __ mov(left_, Operand(dst_)); | 1156 __ mov(left_, Operand(dst_)); |
| 1155 if (!CpuFeatures::IsSupported(SSE2)) { | 1157 if (!Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 1156 __ jmp(entry_label()); | 1158 __ jmp(entry_label()); |
| 1157 return; | 1159 return; |
| 1158 } else { | 1160 } else { |
| 1159 CpuFeatures::Scope use_sse2(SSE2); | 1161 CpuFeatures::Scope use_sse2(SSE2); |
| 1160 __ JumpIfNotNumber(dst_, left_info_, entry_label()); | 1162 __ JumpIfNotNumber(dst_, left_info_, entry_label()); |
| 1161 __ ConvertToInt32(dst_, left_, dst_, left_info_, entry_label()); | 1163 __ ConvertToInt32(dst_, left_, dst_, left_info_, entry_label()); |
| 1162 __ SmiUntag(right_); | 1164 __ SmiUntag(right_); |
| 1163 } | 1165 } |
| 1164 } else { | 1166 } else { |
| 1165 // We know we have SSE2 here because otherwise the label is not linked (see | 1167 // We know we have SSE2 here because otherwise the label is not linked (see |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1258 // Put a heap number pointer in left_. | 1260 // Put a heap number pointer in left_. |
| 1259 __ bind(&answer_out_of_range_); | 1261 __ bind(&answer_out_of_range_); |
| 1260 SaveRegisters(); | 1262 SaveRegisters(); |
| 1261 if (mode_ == OVERWRITE_LEFT) { | 1263 if (mode_ == OVERWRITE_LEFT) { |
| 1262 __ test(left_, Immediate(kSmiTagMask)); | 1264 __ test(left_, Immediate(kSmiTagMask)); |
| 1263 __ j(not_zero, &allocation_ok); | 1265 __ j(not_zero, &allocation_ok); |
| 1264 } | 1266 } |
| 1265 // This trashes right_. | 1267 // This trashes right_. |
| 1266 __ AllocateHeapNumber(left_, right_, no_reg, &after_alloc_failure2); | 1268 __ AllocateHeapNumber(left_, right_, no_reg, &after_alloc_failure2); |
| 1267 __ bind(&allocation_ok); | 1269 __ bind(&allocation_ok); |
| 1268 if (CpuFeatures::IsSupported(SSE2) && op_ != Token::SHR) { | 1270 if (Isolate::Current()->cpu_features()->IsSupported(SSE2) && |
| 1271 op_ != Token::SHR) { |
| 1269 CpuFeatures::Scope use_sse2(SSE2); | 1272 CpuFeatures::Scope use_sse2(SSE2); |
| 1270 ASSERT(Token::IsBitOp(op_)); | 1273 ASSERT(Token::IsBitOp(op_)); |
| 1271 // Signed conversion. | 1274 // Signed conversion. |
| 1272 __ cvtsi2sd(xmm0, Operand(dst_)); | 1275 __ cvtsi2sd(xmm0, Operand(dst_)); |
| 1273 __ movdbl(FieldOperand(left_, HeapNumber::kValueOffset), xmm0); | 1276 __ movdbl(FieldOperand(left_, HeapNumber::kValueOffset), xmm0); |
| 1274 } else { | 1277 } else { |
| 1275 if (op_ == Token::SHR) { | 1278 if (op_ == Token::SHR) { |
| 1276 __ push(Immediate(0)); // High word of unsigned value. | 1279 __ push(Immediate(0)); // High word of unsigned value. |
| 1277 __ push(dst_); | 1280 __ push(dst_); |
| 1278 __ fild_d(Operand(esp, 0)); | 1281 __ fild_d(Operand(esp, 0)); |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1500 return frame_->CallStub(stub, left, right); | 1503 return frame_->CallStub(stub, left, right); |
| 1501 } else { | 1504 } else { |
| 1502 frame_->Push(left); | 1505 frame_->Push(left); |
| 1503 frame_->Push(right); | 1506 frame_->Push(right); |
| 1504 return frame_->CallStub(stub, 2); | 1507 return frame_->CallStub(stub, 2); |
| 1505 } | 1508 } |
| 1506 } | 1509 } |
| 1507 | 1510 |
| 1508 | 1511 |
| 1509 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { | 1512 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { |
| 1510 Object* answer_object = Heap::undefined_value(); | 1513 Object* answer_object = HEAP->undefined_value(); |
| 1511 switch (op) { | 1514 switch (op) { |
| 1512 case Token::ADD: | 1515 case Token::ADD: |
| 1513 if (Smi::IsValid(left + right)) { | 1516 if (Smi::IsValid(left + right)) { |
| 1514 answer_object = Smi::FromInt(left + right); | 1517 answer_object = Smi::FromInt(left + right); |
| 1515 } | 1518 } |
| 1516 break; | 1519 break; |
| 1517 case Token::SUB: | 1520 case Token::SUB: |
| 1518 if (Smi::IsValid(left - right)) { | 1521 if (Smi::IsValid(left - right)) { |
| 1519 answer_object = Smi::FromInt(left - right); | 1522 answer_object = Smi::FromInt(left - right); |
| 1520 } | 1523 } |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1572 unsigned_left >>= shift_amount; | 1575 unsigned_left >>= shift_amount; |
| 1573 } | 1576 } |
| 1574 ASSERT(Smi::IsValid(static_cast<int32_t>(unsigned_left))); | 1577 ASSERT(Smi::IsValid(static_cast<int32_t>(unsigned_left))); |
| 1575 answer_object = Smi::FromInt(static_cast<int32_t>(unsigned_left)); | 1578 answer_object = Smi::FromInt(static_cast<int32_t>(unsigned_left)); |
| 1576 break; | 1579 break; |
| 1577 } | 1580 } |
| 1578 default: | 1581 default: |
| 1579 UNREACHABLE(); | 1582 UNREACHABLE(); |
| 1580 break; | 1583 break; |
| 1581 } | 1584 } |
| 1582 if (answer_object == Heap::undefined_value()) { | 1585 if (answer_object->IsUndefined()) { |
| 1583 return false; | 1586 return false; |
| 1584 } | 1587 } |
| 1585 frame_->Push(Handle<Object>(answer_object)); | 1588 frame_->Push(Handle<Object>(answer_object)); |
| 1586 return true; | 1589 return true; |
| 1587 } | 1590 } |
| 1588 | 1591 |
| 1589 | 1592 |
| 1590 void CodeGenerator::JumpIfBothSmiUsingTypeInfo(Result* left, | 1593 void CodeGenerator::JumpIfBothSmiUsingTypeInfo(Result* left, |
| 1591 Result* right, | 1594 Result* right, |
| 1592 JumpTarget* both_smi) { | 1595 JumpTarget* both_smi) { |
| (...skipping 1428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3021 dest->false_target()->Branch(zero); | 3024 dest->false_target()->Branch(zero); |
| 3022 } else { | 3025 } else { |
| 3023 // Do the smi check, then the comparison. | 3026 // Do the smi check, then the comparison. |
| 3024 __ test(left_reg, Immediate(kSmiTagMask)); | 3027 __ test(left_reg, Immediate(kSmiTagMask)); |
| 3025 is_smi.Branch(zero, left_side, right_side); | 3028 is_smi.Branch(zero, left_side, right_side); |
| 3026 } | 3029 } |
| 3027 | 3030 |
| 3028 // Jump or fall through to here if we are comparing a non-smi to a | 3031 // Jump or fall through to here if we are comparing a non-smi to a |
| 3029 // constant smi. If the non-smi is a heap number and this is not | 3032 // constant smi. If the non-smi is a heap number and this is not |
| 3030 // a loop condition, inline the floating point code. | 3033 // a loop condition, inline the floating point code. |
| 3031 if (!is_loop_condition && CpuFeatures::IsSupported(SSE2)) { | 3034 if (!is_loop_condition && |
| 3035 Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 3032 // Right side is a constant smi and left side has been checked | 3036 // Right side is a constant smi and left side has been checked |
| 3033 // not to be a smi. | 3037 // not to be a smi. |
| 3034 CpuFeatures::Scope use_sse2(SSE2); | 3038 CpuFeatures::Scope use_sse2(SSE2); |
| 3035 JumpTarget not_number; | 3039 JumpTarget not_number; |
| 3036 __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset), | 3040 __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset), |
| 3037 Immediate(Factory::heap_number_map())); | 3041 Immediate(FACTORY->heap_number_map())); |
| 3038 not_number.Branch(not_equal, left_side); | 3042 not_number.Branch(not_equal, left_side); |
| 3039 __ movdbl(xmm1, | 3043 __ movdbl(xmm1, |
| 3040 FieldOperand(left_reg, HeapNumber::kValueOffset)); | 3044 FieldOperand(left_reg, HeapNumber::kValueOffset)); |
| 3041 int value = Smi::cast(*right_val)->value(); | 3045 int value = Smi::cast(*right_val)->value(); |
| 3042 if (value == 0) { | 3046 if (value == 0) { |
| 3043 __ xorpd(xmm0, xmm0); | 3047 __ xorpd(xmm0, xmm0); |
| 3044 } else { | 3048 } else { |
| 3045 Result temp = allocator()->Allocate(); | 3049 Result temp = allocator()->Allocate(); |
| 3046 __ mov(temp.reg(), Immediate(value)); | 3050 __ mov(temp.reg(), Immediate(value)); |
| 3047 __ cvtsi2sd(xmm0, Operand(temp.reg())); | 3051 __ cvtsi2sd(xmm0, Operand(temp.reg())); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3093 Result* operand, | 3097 Result* operand, |
| 3094 Result* left_side, | 3098 Result* left_side, |
| 3095 Result* right_side, | 3099 Result* right_side, |
| 3096 JumpTarget* not_numbers) { | 3100 JumpTarget* not_numbers) { |
| 3097 // Perform check if operand is not known to be a number. | 3101 // Perform check if operand is not known to be a number. |
| 3098 if (!operand->type_info().IsNumber()) { | 3102 if (!operand->type_info().IsNumber()) { |
| 3099 Label done; | 3103 Label done; |
| 3100 __ test(operand->reg(), Immediate(kSmiTagMask)); | 3104 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 3101 __ j(zero, &done); | 3105 __ j(zero, &done); |
| 3102 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset), | 3106 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset), |
| 3103 Immediate(Factory::heap_number_map())); | 3107 Immediate(FACTORY->heap_number_map())); |
| 3104 not_numbers->Branch(not_equal, left_side, right_side, not_taken); | 3108 not_numbers->Branch(not_equal, left_side, right_side, not_taken); |
| 3105 __ bind(&done); | 3109 __ bind(&done); |
| 3106 } | 3110 } |
| 3107 } | 3111 } |
| 3108 | 3112 |
| 3109 | 3113 |
| 3110 // Load a comparison operand to the FPU stack. This assumes that the operand has | 3114 // Load a comparison operand to the FPU stack. This assumes that the operand has |
| 3111 // already been checked and is a number. | 3115 // already been checked and is a number. |
| 3112 static void LoadComparisonOperand(MacroAssembler* masm_, | 3116 static void LoadComparisonOperand(MacroAssembler* masm_, |
| 3113 Result* operand) { | 3117 Result* operand) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3160 __ SmiUntag(operand->reg()); | 3164 __ SmiUntag(operand->reg()); |
| 3161 __ cvtsi2sd(xmm_reg, Operand(operand->reg())); | 3165 __ cvtsi2sd(xmm_reg, Operand(operand->reg())); |
| 3162 __ SmiTag(operand->reg()); | 3166 __ SmiTag(operand->reg()); |
| 3163 } else { | 3167 } else { |
| 3164 // Operand type not known, check for smi or heap number. | 3168 // Operand type not known, check for smi or heap number. |
| 3165 Label smi; | 3169 Label smi; |
| 3166 __ test(operand->reg(), Immediate(kSmiTagMask)); | 3170 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 3167 __ j(zero, &smi); | 3171 __ j(zero, &smi); |
| 3168 if (!operand->type_info().IsNumber()) { | 3172 if (!operand->type_info().IsNumber()) { |
| 3169 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset), | 3173 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset), |
| 3170 Immediate(Factory::heap_number_map())); | 3174 Immediate(FACTORY->heap_number_map())); |
| 3171 not_numbers->Branch(not_equal, left_side, right_side, taken); | 3175 not_numbers->Branch(not_equal, left_side, right_side, taken); |
| 3172 } | 3176 } |
| 3173 __ movdbl(xmm_reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); | 3177 __ movdbl(xmm_reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); |
| 3174 __ jmp(&done); | 3178 __ jmp(&done); |
| 3175 | 3179 |
| 3176 __ bind(&smi); | 3180 __ bind(&smi); |
| 3177 // Comvert smi to float and keep the original smi. | 3181 // Comvert smi to float and keep the original smi. |
| 3178 __ SmiUntag(operand->reg()); | 3182 __ SmiUntag(operand->reg()); |
| 3179 __ cvtsi2sd(xmm_reg, Operand(operand->reg())); | 3183 __ cvtsi2sd(xmm_reg, Operand(operand->reg())); |
| 3180 __ SmiTag(operand->reg()); | 3184 __ SmiTag(operand->reg()); |
| 3181 __ jmp(&done); | 3185 __ jmp(&done); |
| 3182 } | 3186 } |
| 3183 __ bind(&done); | 3187 __ bind(&done); |
| 3184 } | 3188 } |
| 3185 | 3189 |
| 3186 | 3190 |
| 3187 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, | 3191 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, |
| 3188 Result* right_side, | 3192 Result* right_side, |
| 3189 Condition cc, | 3193 Condition cc, |
| 3190 ControlDestination* dest) { | 3194 ControlDestination* dest) { |
| 3191 ASSERT(left_side->is_register()); | 3195 ASSERT(left_side->is_register()); |
| 3192 ASSERT(right_side->is_register()); | 3196 ASSERT(right_side->is_register()); |
| 3193 | 3197 |
| 3194 JumpTarget not_numbers; | 3198 JumpTarget not_numbers; |
| 3195 if (CpuFeatures::IsSupported(SSE2)) { | 3199 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 3196 CpuFeatures::Scope use_sse2(SSE2); | 3200 CpuFeatures::Scope use_sse2(SSE2); |
| 3197 | 3201 |
| 3198 // Load left and right operand into registers xmm0 and xmm1 and compare. | 3202 // Load left and right operand into registers xmm0 and xmm1 and compare. |
| 3199 LoadComparisonOperandSSE2(masm_, left_side, xmm0, left_side, right_side, | 3203 LoadComparisonOperandSSE2(masm_, left_side, xmm0, left_side, right_side, |
| 3200 ¬_numbers); | 3204 ¬_numbers); |
| 3201 LoadComparisonOperandSSE2(masm_, right_side, xmm1, left_side, right_side, | 3205 LoadComparisonOperandSSE2(masm_, right_side, xmm1, left_side, right_side, |
| 3202 ¬_numbers); | 3206 ¬_numbers); |
| 3203 __ ucomisd(xmm0, xmm1); | 3207 __ ucomisd(xmm0, xmm1); |
| 3204 } else { | 3208 } else { |
| 3205 Label check_right, compare; | 3209 Label check_right, compare; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3267 // stack, as receiver and arguments, and calls x. | 3271 // stack, as receiver and arguments, and calls x. |
| 3268 // In the implementation comments, we call x the applicand | 3272 // In the implementation comments, we call x the applicand |
| 3269 // and y the receiver. | 3273 // and y the receiver. |
| 3270 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); | 3274 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); |
| 3271 ASSERT(arguments->IsArguments()); | 3275 ASSERT(arguments->IsArguments()); |
| 3272 | 3276 |
| 3273 // Load applicand.apply onto the stack. This will usually | 3277 // Load applicand.apply onto the stack. This will usually |
| 3274 // give us a megamorphic load site. Not super, but it works. | 3278 // give us a megamorphic load site. Not super, but it works. |
| 3275 Load(applicand); | 3279 Load(applicand); |
| 3276 frame()->Dup(); | 3280 frame()->Dup(); |
| 3277 Handle<String> name = Factory::LookupAsciiSymbol("apply"); | 3281 Handle<String> name = FACTORY->LookupAsciiSymbol("apply"); |
| 3278 frame()->Push(name); | 3282 frame()->Push(name); |
| 3279 Result answer = frame()->CallLoadIC(RelocInfo::CODE_TARGET); | 3283 Result answer = frame()->CallLoadIC(RelocInfo::CODE_TARGET); |
| 3280 __ nop(); | 3284 __ nop(); |
| 3281 frame()->Push(&answer); | 3285 frame()->Push(&answer); |
| 3282 | 3286 |
| 3283 // Load the receiver and the existing arguments object onto the | 3287 // Load the receiver and the existing arguments object onto the |
| 3284 // expression stack. Avoid allocating the arguments object here. | 3288 // expression stack. Avoid allocating the arguments object here. |
| 3285 Load(receiver); | 3289 Load(receiver); |
| 3286 LoadFromSlot(scope()->arguments()->AsSlot(), NOT_INSIDE_TYPEOF); | 3290 LoadFromSlot(scope()->arguments()->AsSlot(), NOT_INSIDE_TYPEOF); |
| 3287 | 3291 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3299 // from the stack. This also deals with cases where a local variable | 3303 // from the stack. This also deals with cases where a local variable |
| 3300 // named 'arguments' has been introduced. | 3304 // named 'arguments' has been introduced. |
| 3301 frame_->Dup(); | 3305 frame_->Dup(); |
| 3302 Result probe = frame_->Pop(); | 3306 Result probe = frame_->Pop(); |
| 3303 { VirtualFrame::SpilledScope spilled_scope; | 3307 { VirtualFrame::SpilledScope spilled_scope; |
| 3304 Label slow, done; | 3308 Label slow, done; |
| 3305 bool try_lazy = true; | 3309 bool try_lazy = true; |
| 3306 if (probe.is_constant()) { | 3310 if (probe.is_constant()) { |
| 3307 try_lazy = probe.handle()->IsArgumentsMarker(); | 3311 try_lazy = probe.handle()->IsArgumentsMarker(); |
| 3308 } else { | 3312 } else { |
| 3309 __ cmp(Operand(probe.reg()), Immediate(Factory::arguments_marker())); | 3313 __ cmp(Operand(probe.reg()), Immediate(FACTORY->arguments_marker())); |
| 3310 probe.Unuse(); | 3314 probe.Unuse(); |
| 3311 __ j(not_equal, &slow); | 3315 __ j(not_equal, &slow); |
| 3312 } | 3316 } |
| 3313 | 3317 |
| 3314 if (try_lazy) { | 3318 if (try_lazy) { |
| 3315 Label build_args; | 3319 Label build_args; |
| 3316 // Get rid of the arguments object probe. | 3320 // Get rid of the arguments object probe. |
| 3317 frame_->Drop(); // Can be called on a spilled frame. | 3321 frame_->Drop(); // Can be called on a spilled frame. |
| 3318 // Stack now has 3 elements on it. | 3322 // Stack now has 3 elements on it. |
| 3319 // Contents of stack at this point: | 3323 // Contents of stack at this point: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3335 __ j(below, &build_args); | 3339 __ j(below, &build_args); |
| 3336 | 3340 |
| 3337 // Check that applicand.apply is Function.prototype.apply. | 3341 // Check that applicand.apply is Function.prototype.apply. |
| 3338 __ mov(eax, Operand(esp, kPointerSize)); | 3342 __ mov(eax, Operand(esp, kPointerSize)); |
| 3339 __ test(eax, Immediate(kSmiTagMask)); | 3343 __ test(eax, Immediate(kSmiTagMask)); |
| 3340 __ j(zero, &build_args); | 3344 __ j(zero, &build_args); |
| 3341 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ecx); | 3345 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ecx); |
| 3342 __ j(not_equal, &build_args); | 3346 __ j(not_equal, &build_args); |
| 3343 __ mov(ecx, FieldOperand(eax, JSFunction::kCodeEntryOffset)); | 3347 __ mov(ecx, FieldOperand(eax, JSFunction::kCodeEntryOffset)); |
| 3344 __ sub(Operand(ecx), Immediate(Code::kHeaderSize - kHeapObjectTag)); | 3348 __ sub(Operand(ecx), Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 3345 Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply)); | 3349 Handle<Code> apply_code(Isolate::Current()->builtins()->builtin( |
| 3350 Builtins::FunctionApply)); |
| 3346 __ cmp(Operand(ecx), Immediate(apply_code)); | 3351 __ cmp(Operand(ecx), Immediate(apply_code)); |
| 3347 __ j(not_equal, &build_args); | 3352 __ j(not_equal, &build_args); |
| 3348 | 3353 |
| 3349 // Check that applicand is a function. | 3354 // Check that applicand is a function. |
| 3350 __ mov(edi, Operand(esp, 2 * kPointerSize)); | 3355 __ mov(edi, Operand(esp, 2 * kPointerSize)); |
| 3351 __ test(edi, Immediate(kSmiTagMask)); | 3356 __ test(edi, Immediate(kSmiTagMask)); |
| 3352 __ j(zero, &build_args); | 3357 __ j(zero, &build_args); |
| 3353 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 3358 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
| 3354 __ j(not_equal, &build_args); | 3359 __ j(not_equal, &build_args); |
| 3355 | 3360 |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3562 frame_->EmitPush(Immediate(var->name())); | 3567 frame_->EmitPush(Immediate(var->name())); |
| 3563 // Declaration nodes are always introduced in one of two modes. | 3568 // Declaration nodes are always introduced in one of two modes. |
| 3564 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); | 3569 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); |
| 3565 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; | 3570 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
| 3566 frame_->EmitPush(Immediate(Smi::FromInt(attr))); | 3571 frame_->EmitPush(Immediate(Smi::FromInt(attr))); |
| 3567 // Push initial value, if any. | 3572 // Push initial value, if any. |
| 3568 // Note: For variables we must not push an initial value (such as | 3573 // Note: For variables we must not push an initial value (such as |
| 3569 // 'undefined') because we may have a (legal) redeclaration and we | 3574 // 'undefined') because we may have a (legal) redeclaration and we |
| 3570 // must not destroy the current value. | 3575 // must not destroy the current value. |
| 3571 if (node->mode() == Variable::CONST) { | 3576 if (node->mode() == Variable::CONST) { |
| 3572 frame_->EmitPush(Immediate(Factory::the_hole_value())); | 3577 frame_->EmitPush(Immediate(FACTORY->the_hole_value())); |
| 3573 } else if (node->fun() != NULL) { | 3578 } else if (node->fun() != NULL) { |
| 3574 Load(node->fun()); | 3579 Load(node->fun()); |
| 3575 } else { | 3580 } else { |
| 3576 frame_->EmitPush(Immediate(Smi::FromInt(0))); // no initial value! | 3581 frame_->EmitPush(Immediate(Smi::FromInt(0))); // no initial value! |
| 3577 } | 3582 } |
| 3578 Result ignored = frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); | 3583 Result ignored = frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 3579 // Ignore the return value (declarations are statements). | 3584 // Ignore the return value (declarations are statements). |
| 3580 return; | 3585 return; |
| 3581 } | 3586 } |
| 3582 | 3587 |
| 3583 ASSERT(!var->is_global()); | 3588 ASSERT(!var->is_global()); |
| 3584 | 3589 |
| 3585 // If we have a function or a constant, we need to initialize the variable. | 3590 // If we have a function or a constant, we need to initialize the variable. |
| 3586 Expression* val = NULL; | 3591 Expression* val = NULL; |
| 3587 if (node->mode() == Variable::CONST) { | 3592 if (node->mode() == Variable::CONST) { |
| 3588 val = new Literal(Factory::the_hole_value()); | 3593 val = new Literal(FACTORY->the_hole_value()); |
| 3589 } else { | 3594 } else { |
| 3590 val = node->fun(); // NULL if we don't have a function | 3595 val = node->fun(); // NULL if we don't have a function |
| 3591 } | 3596 } |
| 3592 | 3597 |
| 3593 if (val != NULL) { | 3598 if (val != NULL) { |
| 3594 { | 3599 { |
| 3595 // Set the initial value. | 3600 // Set the initial value. |
| 3596 Reference target(this, node->proxy()); | 3601 Reference target(this, node->proxy()); |
| 3597 Load(val); | 3602 Load(val); |
| 3598 target.SetValue(NOT_CONST_INIT); | 3603 target.SetValue(NOT_CONST_INIT); |
| (...skipping 760 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4359 JumpTarget exit; | 4364 JumpTarget exit; |
| 4360 | 4365 |
| 4361 // Get the object to enumerate over (converted to JSObject). | 4366 // Get the object to enumerate over (converted to JSObject). |
| 4362 LoadAndSpill(node->enumerable()); | 4367 LoadAndSpill(node->enumerable()); |
| 4363 | 4368 |
| 4364 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 4369 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 4365 // to the specification. 12.6.4 mandates a call to ToObject. | 4370 // to the specification. 12.6.4 mandates a call to ToObject. |
| 4366 frame_->EmitPop(eax); | 4371 frame_->EmitPop(eax); |
| 4367 | 4372 |
| 4368 // eax: value to be iterated over | 4373 // eax: value to be iterated over |
| 4369 __ cmp(eax, Factory::undefined_value()); | 4374 __ cmp(eax, FACTORY->undefined_value()); |
| 4370 exit.Branch(equal); | 4375 exit.Branch(equal); |
| 4371 __ cmp(eax, Factory::null_value()); | 4376 __ cmp(eax, FACTORY->null_value()); |
| 4372 exit.Branch(equal); | 4377 exit.Branch(equal); |
| 4373 | 4378 |
| 4374 // Stack layout in body: | 4379 // Stack layout in body: |
| 4375 // [iteration counter (smi)] <- slot 0 | 4380 // [iteration counter (smi)] <- slot 0 |
| 4376 // [length of array] <- slot 1 | 4381 // [length of array] <- slot 1 |
| 4377 // [FixedArray] <- slot 2 | 4382 // [FixedArray] <- slot 2 |
| 4378 // [Map or 0] <- slot 3 | 4383 // [Map or 0] <- slot 3 |
| 4379 // [Object] <- slot 4 | 4384 // [Object] <- slot 4 |
| 4380 | 4385 |
| 4381 // Check if enumerable is already a JSObject | 4386 // Check if enumerable is already a JSObject |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4400 // guarantee cache validity, call the runtime system to check cache | 4405 // guarantee cache validity, call the runtime system to check cache |
| 4401 // validity or get the property names in a fixed array. | 4406 // validity or get the property names in a fixed array. |
| 4402 JumpTarget call_runtime; | 4407 JumpTarget call_runtime; |
| 4403 JumpTarget loop(JumpTarget::BIDIRECTIONAL); | 4408 JumpTarget loop(JumpTarget::BIDIRECTIONAL); |
| 4404 JumpTarget check_prototype; | 4409 JumpTarget check_prototype; |
| 4405 JumpTarget use_cache; | 4410 JumpTarget use_cache; |
| 4406 __ mov(ecx, eax); | 4411 __ mov(ecx, eax); |
| 4407 loop.Bind(); | 4412 loop.Bind(); |
| 4408 // Check that there are no elements. | 4413 // Check that there are no elements. |
| 4409 __ mov(edx, FieldOperand(ecx, JSObject::kElementsOffset)); | 4414 __ mov(edx, FieldOperand(ecx, JSObject::kElementsOffset)); |
| 4410 __ cmp(Operand(edx), Immediate(Factory::empty_fixed_array())); | 4415 __ cmp(Operand(edx), Immediate(FACTORY->empty_fixed_array())); |
| 4411 call_runtime.Branch(not_equal); | 4416 call_runtime.Branch(not_equal); |
| 4412 // Check that instance descriptors are not empty so that we can | 4417 // Check that instance descriptors are not empty so that we can |
| 4413 // check for an enum cache. Leave the map in ebx for the subsequent | 4418 // check for an enum cache. Leave the map in ebx for the subsequent |
| 4414 // prototype load. | 4419 // prototype load. |
| 4415 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); | 4420 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 4416 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); | 4421 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); |
| 4417 __ cmp(Operand(edx), Immediate(Factory::empty_descriptor_array())); | 4422 __ cmp(Operand(edx), Immediate(FACTORY->empty_descriptor_array())); |
| 4418 call_runtime.Branch(equal); | 4423 call_runtime.Branch(equal); |
| 4419 // Check that there in an enum cache in the non-empty instance | 4424 // Check that there in an enum cache in the non-empty instance |
| 4420 // descriptors. This is the case if the next enumeration index | 4425 // descriptors. This is the case if the next enumeration index |
| 4421 // field does not contain a smi. | 4426 // field does not contain a smi. |
| 4422 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); | 4427 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); |
| 4423 __ test(edx, Immediate(kSmiTagMask)); | 4428 __ test(edx, Immediate(kSmiTagMask)); |
| 4424 call_runtime.Branch(zero); | 4429 call_runtime.Branch(zero); |
| 4425 // For all objects but the receiver, check that the cache is empty. | 4430 // For all objects but the receiver, check that the cache is empty. |
| 4426 __ cmp(ecx, Operand(eax)); | 4431 __ cmp(ecx, Operand(eax)); |
| 4427 check_prototype.Branch(equal); | 4432 check_prototype.Branch(equal); |
| 4428 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 4433 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 4429 __ cmp(Operand(edx), Immediate(Factory::empty_fixed_array())); | 4434 __ cmp(Operand(edx), Immediate(FACTORY->empty_fixed_array())); |
| 4430 call_runtime.Branch(not_equal); | 4435 call_runtime.Branch(not_equal); |
| 4431 check_prototype.Bind(); | 4436 check_prototype.Bind(); |
| 4432 // Load the prototype from the map and loop if non-null. | 4437 // Load the prototype from the map and loop if non-null. |
| 4433 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); | 4438 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); |
| 4434 __ cmp(Operand(ecx), Immediate(Factory::null_value())); | 4439 __ cmp(Operand(ecx), Immediate(FACTORY->null_value())); |
| 4435 loop.Branch(not_equal); | 4440 loop.Branch(not_equal); |
| 4436 // The enum cache is valid. Load the map of the object being | 4441 // The enum cache is valid. Load the map of the object being |
| 4437 // iterated over and use the cache for the iteration. | 4442 // iterated over and use the cache for the iteration. |
| 4438 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 4443 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 4439 use_cache.Jump(); | 4444 use_cache.Jump(); |
| 4440 | 4445 |
| 4441 call_runtime.Bind(); | 4446 call_runtime.Bind(); |
| 4442 // Call the runtime to get the property names for the object. | 4447 // Call the runtime to get the property names for the object. |
| 4443 frame_->EmitPush(eax); // push the Object (slot 4) for the runtime call | 4448 frame_->EmitPush(eax); // push the Object (slot 4) for the runtime call |
| 4444 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 4449 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 4445 | 4450 |
| 4446 // If we got a map from the runtime call, we can do a fast | 4451 // If we got a map from the runtime call, we can do a fast |
| 4447 // modification check. Otherwise, we got a fixed array, and we have | 4452 // modification check. Otherwise, we got a fixed array, and we have |
| 4448 // to do a slow check. | 4453 // to do a slow check. |
| 4449 // eax: map or fixed array (result from call to | 4454 // eax: map or fixed array (result from call to |
| 4450 // Runtime::kGetPropertyNamesFast) | 4455 // Runtime::kGetPropertyNamesFast) |
| 4451 __ mov(edx, Operand(eax)); | 4456 __ mov(edx, Operand(eax)); |
| 4452 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 4457 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 4453 __ cmp(ecx, Factory::meta_map()); | 4458 __ cmp(ecx, FACTORY->meta_map()); |
| 4454 fixed_array.Branch(not_equal); | 4459 fixed_array.Branch(not_equal); |
| 4455 | 4460 |
| 4456 use_cache.Bind(); | 4461 use_cache.Bind(); |
| 4457 // Get enum cache | 4462 // Get enum cache |
| 4458 // eax: map (either the result from a call to | 4463 // eax: map (either the result from a call to |
| 4459 // Runtime::kGetPropertyNamesFast or has been fetched directly from | 4464 // Runtime::kGetPropertyNamesFast or has been fetched directly from |
| 4460 // the object) | 4465 // the object) |
| 4461 __ mov(ecx, Operand(eax)); | 4466 __ mov(ecx, Operand(eax)); |
| 4462 | 4467 |
| 4463 __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset)); | 4468 __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset)); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4635 // After shadowing stops, the original targets are unshadowed and the | 4640 // After shadowing stops, the original targets are unshadowed and the |
| 4636 // ShadowTargets represent the formerly shadowing targets. | 4641 // ShadowTargets represent the formerly shadowing targets. |
| 4637 bool has_unlinks = false; | 4642 bool has_unlinks = false; |
| 4638 for (int i = 0; i < shadows.length(); i++) { | 4643 for (int i = 0; i < shadows.length(); i++) { |
| 4639 shadows[i]->StopShadowing(); | 4644 shadows[i]->StopShadowing(); |
| 4640 has_unlinks = has_unlinks || shadows[i]->is_linked(); | 4645 has_unlinks = has_unlinks || shadows[i]->is_linked(); |
| 4641 } | 4646 } |
| 4642 function_return_is_shadowed_ = function_return_was_shadowed; | 4647 function_return_is_shadowed_ = function_return_was_shadowed; |
| 4643 | 4648 |
| 4644 // Get an external reference to the handler address. | 4649 // Get an external reference to the handler address. |
| 4645 ExternalReference handler_address(Top::k_handler_address); | 4650 ExternalReference handler_address(Isolate::k_handler_address); |
| 4646 | 4651 |
| 4647 // Make sure that there's nothing left on the stack above the | 4652 // Make sure that there's nothing left on the stack above the |
| 4648 // handler structure. | 4653 // handler structure. |
| 4649 if (FLAG_debug_code) { | 4654 if (FLAG_debug_code) { |
| 4650 __ mov(eax, Operand::StaticVariable(handler_address)); | 4655 __ mov(eax, Operand::StaticVariable(handler_address)); |
| 4651 __ cmp(esp, Operand(eax)); | 4656 __ cmp(esp, Operand(eax)); |
| 4652 __ Assert(equal, "stack pointer should point to top handler"); | 4657 __ Assert(equal, "stack pointer should point to top handler"); |
| 4653 } | 4658 } |
| 4654 | 4659 |
| 4655 // If we can fall off the end of the try block, unlink from try chain. | 4660 // If we can fall off the end of the try block, unlink from try chain. |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4761 // After shadowing stops, the original targets are unshadowed and the | 4766 // After shadowing stops, the original targets are unshadowed and the |
| 4762 // ShadowTargets represent the formerly shadowing targets. | 4767 // ShadowTargets represent the formerly shadowing targets. |
| 4763 int nof_unlinks = 0; | 4768 int nof_unlinks = 0; |
| 4764 for (int i = 0; i < shadows.length(); i++) { | 4769 for (int i = 0; i < shadows.length(); i++) { |
| 4765 shadows[i]->StopShadowing(); | 4770 shadows[i]->StopShadowing(); |
| 4766 if (shadows[i]->is_linked()) nof_unlinks++; | 4771 if (shadows[i]->is_linked()) nof_unlinks++; |
| 4767 } | 4772 } |
| 4768 function_return_is_shadowed_ = function_return_was_shadowed; | 4773 function_return_is_shadowed_ = function_return_was_shadowed; |
| 4769 | 4774 |
| 4770 // Get an external reference to the handler address. | 4775 // Get an external reference to the handler address. |
| 4771 ExternalReference handler_address(Top::k_handler_address); | 4776 ExternalReference handler_address(Isolate::k_handler_address); |
| 4772 | 4777 |
| 4773 // If we can fall off the end of the try block, unlink from the try | 4778 // If we can fall off the end of the try block, unlink from the try |
| 4774 // chain and set the state on the frame to FALLING. | 4779 // chain and set the state on the frame to FALLING. |
| 4775 if (has_valid_frame()) { | 4780 if (has_valid_frame()) { |
| 4776 // The next handler address is on top of the frame. | 4781 // The next handler address is on top of the frame. |
| 4777 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | 4782 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
| 4778 frame_->EmitPop(Operand::StaticVariable(handler_address)); | 4783 frame_->EmitPop(Operand::StaticVariable(handler_address)); |
| 4779 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 4784 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 4780 | 4785 |
| 4781 // Fake a top of stack value (unneeded when FALLING) and set the | 4786 // Fake a top of stack value (unneeded when FALLING) and set the |
| 4782 // state in ecx, then jump around the unlink blocks if any. | 4787 // state in ecx, then jump around the unlink blocks if any. |
| 4783 frame_->EmitPush(Immediate(Factory::undefined_value())); | 4788 frame_->EmitPush(Immediate(FACTORY->undefined_value())); |
| 4784 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); | 4789 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); |
| 4785 if (nof_unlinks > 0) { | 4790 if (nof_unlinks > 0) { |
| 4786 finally_block.Jump(); | 4791 finally_block.Jump(); |
| 4787 } | 4792 } |
| 4788 } | 4793 } |
| 4789 | 4794 |
| 4790 // Generate code to unlink and set the state for the (formerly) | 4795 // Generate code to unlink and set the state for the (formerly) |
| 4791 // shadowing targets that have been jumped to. | 4796 // shadowing targets that have been jumped to. |
| 4792 for (int i = 0; i < shadows.length(); i++) { | 4797 for (int i = 0; i < shadows.length(); i++) { |
| 4793 if (shadows[i]->is_linked()) { | 4798 if (shadows[i]->is_linked()) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 4816 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | 4821 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
| 4817 frame_->EmitPop(Operand::StaticVariable(handler_address)); | 4822 frame_->EmitPop(Operand::StaticVariable(handler_address)); |
| 4818 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 4823 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 4819 | 4824 |
| 4820 if (i == kReturnShadowIndex) { | 4825 if (i == kReturnShadowIndex) { |
| 4821 // If this target shadowed the function return, materialize | 4826 // If this target shadowed the function return, materialize |
| 4822 // the return value on the stack. | 4827 // the return value on the stack. |
| 4823 frame_->EmitPush(eax); | 4828 frame_->EmitPush(eax); |
| 4824 } else { | 4829 } else { |
| 4825 // Fake TOS for targets that shadowed breaks and continues. | 4830 // Fake TOS for targets that shadowed breaks and continues. |
| 4826 frame_->EmitPush(Immediate(Factory::undefined_value())); | 4831 frame_->EmitPush(Immediate(FACTORY->undefined_value())); |
| 4827 } | 4832 } |
| 4828 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); | 4833 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); |
| 4829 if (--nof_unlinks > 0) { | 4834 if (--nof_unlinks > 0) { |
| 4830 // If this is not the last unlink block, jump around the next. | 4835 // If this is not the last unlink block, jump around the next. |
| 4831 finally_block.Jump(); | 4836 finally_block.Jump(); |
| 4832 } | 4837 } |
| 4833 } | 4838 } |
| 4834 } | 4839 } |
| 4835 | 4840 |
| 4836 // --- Finally block --- | 4841 // --- Finally block --- |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4924 FastNewClosureStub stub( | 4929 FastNewClosureStub stub( |
| 4925 function_info->strict_mode() ? kStrictMode : kNonStrictMode); | 4930 function_info->strict_mode() ? kStrictMode : kNonStrictMode); |
| 4926 frame()->EmitPush(Immediate(function_info)); | 4931 frame()->EmitPush(Immediate(function_info)); |
| 4927 return frame()->CallStub(&stub, 1); | 4932 return frame()->CallStub(&stub, 1); |
| 4928 } else { | 4933 } else { |
| 4929 // Call the runtime to instantiate the function based on the | 4934 // Call the runtime to instantiate the function based on the |
| 4930 // shared function info. | 4935 // shared function info. |
| 4931 frame()->EmitPush(esi); | 4936 frame()->EmitPush(esi); |
| 4932 frame()->EmitPush(Immediate(function_info)); | 4937 frame()->EmitPush(Immediate(function_info)); |
| 4933 frame()->EmitPush(Immediate(pretenure | 4938 frame()->EmitPush(Immediate(pretenure |
| 4934 ? Factory::true_value() | 4939 ? FACTORY->true_value() |
| 4935 : Factory::false_value())); | 4940 : FACTORY->false_value())); |
| 4936 return frame()->CallRuntime(Runtime::kNewClosure, 3); | 4941 return frame()->CallRuntime(Runtime::kNewClosure, 3); |
| 4937 } | 4942 } |
| 4938 } | 4943 } |
| 4939 | 4944 |
| 4940 | 4945 |
| 4941 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 4946 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
| 4942 Comment cmnt(masm_, "[ FunctionLiteral"); | 4947 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 4943 ASSERT(!in_safe_int32_mode()); | 4948 ASSERT(!in_safe_int32_mode()); |
| 4944 // Build the function info and instantiate it. | 4949 // Build the function info and instantiate it. |
| 4945 Handle<SharedFunctionInfo> function_info = | 4950 Handle<SharedFunctionInfo> function_info = |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5033 // Const slots may contain 'the hole' value (the constant hasn't been | 5038 // Const slots may contain 'the hole' value (the constant hasn't been |
| 5034 // initialized yet) which needs to be converted into the 'undefined' | 5039 // initialized yet) which needs to be converted into the 'undefined' |
| 5035 // value. | 5040 // value. |
| 5036 // | 5041 // |
| 5037 // We currently spill the virtual frame because constants use the | 5042 // We currently spill the virtual frame because constants use the |
| 5038 // potentially unsafe direct-frame access of SlotOperand. | 5043 // potentially unsafe direct-frame access of SlotOperand. |
| 5039 VirtualFrame::SpilledScope spilled_scope; | 5044 VirtualFrame::SpilledScope spilled_scope; |
| 5040 Comment cmnt(masm_, "[ Load const"); | 5045 Comment cmnt(masm_, "[ Load const"); |
| 5041 Label exit; | 5046 Label exit; |
| 5042 __ mov(ecx, SlotOperand(slot, ecx)); | 5047 __ mov(ecx, SlotOperand(slot, ecx)); |
| 5043 __ cmp(ecx, Factory::the_hole_value()); | 5048 __ cmp(ecx, FACTORY->the_hole_value()); |
| 5044 __ j(not_equal, &exit); | 5049 __ j(not_equal, &exit); |
| 5045 __ mov(ecx, Factory::undefined_value()); | 5050 __ mov(ecx, FACTORY->undefined_value()); |
| 5046 __ bind(&exit); | 5051 __ bind(&exit); |
| 5047 frame()->EmitPush(ecx); | 5052 frame()->EmitPush(ecx); |
| 5048 | 5053 |
| 5049 } else if (slot->type() == Slot::PARAMETER) { | 5054 } else if (slot->type() == Slot::PARAMETER) { |
| 5050 frame()->PushParameterAt(slot->index()); | 5055 frame()->PushParameterAt(slot->index()); |
| 5051 | 5056 |
| 5052 } else if (slot->type() == Slot::LOCAL) { | 5057 } else if (slot->type() == Slot::LOCAL) { |
| 5053 frame()->PushLocalAt(slot->index()); | 5058 frame()->PushLocalAt(slot->index()); |
| 5054 | 5059 |
| 5055 } else { | 5060 } else { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 5085 result = StoreArgumentsObject(false); | 5090 result = StoreArgumentsObject(false); |
| 5086 } | 5091 } |
| 5087 frame()->Push(&result); | 5092 frame()->Push(&result); |
| 5088 return; | 5093 return; |
| 5089 } | 5094 } |
| 5090 ASSERT(result.is_register()); | 5095 ASSERT(result.is_register()); |
| 5091 // The loaded value is in a register. If it is the sentinel that | 5096 // The loaded value is in a register. If it is the sentinel that |
| 5092 // indicates that we haven't loaded the arguments object yet, we | 5097 // indicates that we haven't loaded the arguments object yet, we |
| 5093 // need to do it now. | 5098 // need to do it now. |
| 5094 JumpTarget exit; | 5099 JumpTarget exit; |
| 5095 __ cmp(Operand(result.reg()), Immediate(Factory::arguments_marker())); | 5100 __ cmp(Operand(result.reg()), Immediate(FACTORY->arguments_marker())); |
| 5096 frame()->Push(&result); | 5101 frame()->Push(&result); |
| 5097 exit.Branch(not_equal); | 5102 exit.Branch(not_equal); |
| 5098 | 5103 |
| 5099 result = StoreArgumentsObject(false); | 5104 result = StoreArgumentsObject(false); |
| 5100 frame()->SetElementAt(0, &result); | 5105 frame()->SetElementAt(0, &result); |
| 5101 result.Unuse(); | 5106 result.Unuse(); |
| 5102 exit.Bind(); | 5107 exit.Bind(); |
| 5103 return; | 5108 return; |
| 5104 } | 5109 } |
| 5105 | 5110 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5139 if (s != NULL && s->is_eval_scope()) { | 5144 if (s != NULL && s->is_eval_scope()) { |
| 5140 // Loop up the context chain. There is no frame effect so it is | 5145 // Loop up the context chain. There is no frame effect so it is |
| 5141 // safe to use raw labels here. | 5146 // safe to use raw labels here. |
| 5142 Label next, fast; | 5147 Label next, fast; |
| 5143 if (!context.is(tmp.reg())) { | 5148 if (!context.is(tmp.reg())) { |
| 5144 __ mov(tmp.reg(), context); | 5149 __ mov(tmp.reg(), context); |
| 5145 } | 5150 } |
| 5146 __ bind(&next); | 5151 __ bind(&next); |
| 5147 // Terminate at global context. | 5152 // Terminate at global context. |
| 5148 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), | 5153 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), |
| 5149 Immediate(Factory::global_context_map())); | 5154 Immediate(FACTORY->global_context_map())); |
| 5150 __ j(equal, &fast); | 5155 __ j(equal, &fast); |
| 5151 // Check that extension is NULL. | 5156 // Check that extension is NULL. |
| 5152 __ cmp(ContextOperand(tmp.reg(), Context::EXTENSION_INDEX), Immediate(0)); | 5157 __ cmp(ContextOperand(tmp.reg(), Context::EXTENSION_INDEX), Immediate(0)); |
| 5153 slow->Branch(not_equal, not_taken); | 5158 slow->Branch(not_equal, not_taken); |
| 5154 // Load next context in chain. | 5159 // Load next context in chain. |
| 5155 __ mov(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX)); | 5160 __ mov(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX)); |
| 5156 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); | 5161 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); |
| 5157 __ jmp(&next); | 5162 __ jmp(&next); |
| 5158 __ bind(&fast); | 5163 __ bind(&fast); |
| 5159 } | 5164 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5199 if (potential_slot != NULL) { | 5204 if (potential_slot != NULL) { |
| 5200 // Generate fast case for locals that rewrite to slots. | 5205 // Generate fast case for locals that rewrite to slots. |
| 5201 // Allocate a fresh register to use as a temp in | 5206 // Allocate a fresh register to use as a temp in |
| 5202 // ContextSlotOperandCheckExtensions and to hold the result | 5207 // ContextSlotOperandCheckExtensions and to hold the result |
| 5203 // value. | 5208 // value. |
| 5204 *result = allocator()->Allocate(); | 5209 *result = allocator()->Allocate(); |
| 5205 ASSERT(result->is_valid()); | 5210 ASSERT(result->is_valid()); |
| 5206 __ mov(result->reg(), | 5211 __ mov(result->reg(), |
| 5207 ContextSlotOperandCheckExtensions(potential_slot, *result, slow)); | 5212 ContextSlotOperandCheckExtensions(potential_slot, *result, slow)); |
| 5208 if (potential_slot->var()->mode() == Variable::CONST) { | 5213 if (potential_slot->var()->mode() == Variable::CONST) { |
| 5209 __ cmp(result->reg(), Factory::the_hole_value()); | 5214 __ cmp(result->reg(), FACTORY->the_hole_value()); |
| 5210 done->Branch(not_equal, result); | 5215 done->Branch(not_equal, result); |
| 5211 __ mov(result->reg(), Factory::undefined_value()); | 5216 __ mov(result->reg(), FACTORY->undefined_value()); |
| 5212 } | 5217 } |
| 5213 done->Jump(result); | 5218 done->Jump(result); |
| 5214 } else if (rewrite != NULL) { | 5219 } else if (rewrite != NULL) { |
| 5215 // Generate fast case for calls of an argument function. | 5220 // Generate fast case for calls of an argument function. |
| 5216 Property* property = rewrite->AsProperty(); | 5221 Property* property = rewrite->AsProperty(); |
| 5217 if (property != NULL) { | 5222 if (property != NULL) { |
| 5218 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 5223 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 5219 Literal* key_literal = property->key()->AsLiteral(); | 5224 Literal* key_literal = property->key()->AsLiteral(); |
| 5220 if (obj_proxy != NULL && | 5225 if (obj_proxy != NULL && |
| 5221 key_literal != NULL && | 5226 key_literal != NULL && |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5288 // Only the first const initialization must be executed (the slot | 5293 // Only the first const initialization must be executed (the slot |
| 5289 // still contains 'the hole' value). When the assignment is executed, | 5294 // still contains 'the hole' value). When the assignment is executed, |
| 5290 // the code is identical to a normal store (see below). | 5295 // the code is identical to a normal store (see below). |
| 5291 // | 5296 // |
| 5292 // We spill the frame in the code below because the direct-frame | 5297 // We spill the frame in the code below because the direct-frame |
| 5293 // access of SlotOperand is potentially unsafe with an unspilled | 5298 // access of SlotOperand is potentially unsafe with an unspilled |
| 5294 // frame. | 5299 // frame. |
| 5295 VirtualFrame::SpilledScope spilled_scope; | 5300 VirtualFrame::SpilledScope spilled_scope; |
| 5296 Comment cmnt(masm_, "[ Init const"); | 5301 Comment cmnt(masm_, "[ Init const"); |
| 5297 __ mov(ecx, SlotOperand(slot, ecx)); | 5302 __ mov(ecx, SlotOperand(slot, ecx)); |
| 5298 __ cmp(ecx, Factory::the_hole_value()); | 5303 __ cmp(ecx, FACTORY->the_hole_value()); |
| 5299 exit.Branch(not_equal); | 5304 exit.Branch(not_equal); |
| 5300 } | 5305 } |
| 5301 | 5306 |
| 5302 // We must execute the store. Storing a variable must keep the (new) | 5307 // We must execute the store. Storing a variable must keep the (new) |
| 5303 // value on the stack. This is necessary for compiling assignment | 5308 // value on the stack. This is necessary for compiling assignment |
| 5304 // expressions. | 5309 // expressions. |
| 5305 // | 5310 // |
| 5306 // Note: We will reach here even with slot->var()->mode() == | 5311 // Note: We will reach here even with slot->var()->mode() == |
| 5307 // Variable::CONST because of const declarations which will initialize | 5312 // Variable::CONST because of const declarations which will initialize |
| 5308 // consts to 'the hole' value and by doing so, end up calling this code. | 5313 // consts to 'the hole' value and by doing so, end up calling this code. |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5459 if (!boilerplate_.is(eax)) __ mov(boilerplate_, eax); | 5464 if (!boilerplate_.is(eax)) __ mov(boilerplate_, eax); |
| 5460 } | 5465 } |
| 5461 | 5466 |
| 5462 | 5467 |
| 5463 class DeferredAllocateInNewSpace: public DeferredCode { | 5468 class DeferredAllocateInNewSpace: public DeferredCode { |
| 5464 public: | 5469 public: |
| 5465 DeferredAllocateInNewSpace(int size, | 5470 DeferredAllocateInNewSpace(int size, |
| 5466 Register target, | 5471 Register target, |
| 5467 int registers_to_save = 0) | 5472 int registers_to_save = 0) |
| 5468 : size_(size), target_(target), registers_to_save_(registers_to_save) { | 5473 : size_(size), target_(target), registers_to_save_(registers_to_save) { |
| 5469 ASSERT(size >= kPointerSize && size <= Heap::MaxObjectSizeInNewSpace()); | 5474 ASSERT(size >= kPointerSize && size <= HEAP->MaxObjectSizeInNewSpace()); |
| 5470 ASSERT_EQ(0, registers_to_save & target.bit()); | 5475 ASSERT_EQ(0, registers_to_save & target.bit()); |
| 5471 set_comment("[ DeferredAllocateInNewSpace"); | 5476 set_comment("[ DeferredAllocateInNewSpace"); |
| 5472 } | 5477 } |
| 5473 void Generate(); | 5478 void Generate(); |
| 5474 | 5479 |
| 5475 private: | 5480 private: |
| 5476 int size_; | 5481 int size_; |
| 5477 Register target_; | 5482 Register target_; |
| 5478 int registers_to_save_; | 5483 int registers_to_save_; |
| 5479 }; | 5484 }; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5520 Result boilerplate = allocator_->Allocate(); | 5525 Result boilerplate = allocator_->Allocate(); |
| 5521 ASSERT(boilerplate.is_valid()); | 5526 ASSERT(boilerplate.is_valid()); |
| 5522 int literal_offset = | 5527 int literal_offset = |
| 5523 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 5528 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
| 5524 __ mov(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset)); | 5529 __ mov(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset)); |
| 5525 | 5530 |
| 5526 // Check whether we need to materialize the RegExp object. If so, | 5531 // Check whether we need to materialize the RegExp object. If so, |
| 5527 // jump to the deferred code passing the literals array. | 5532 // jump to the deferred code passing the literals array. |
| 5528 DeferredRegExpLiteral* deferred = | 5533 DeferredRegExpLiteral* deferred = |
| 5529 new DeferredRegExpLiteral(boilerplate.reg(), literals.reg(), node); | 5534 new DeferredRegExpLiteral(boilerplate.reg(), literals.reg(), node); |
| 5530 __ cmp(boilerplate.reg(), Factory::undefined_value()); | 5535 __ cmp(boilerplate.reg(), FACTORY->undefined_value()); |
| 5531 deferred->Branch(equal); | 5536 deferred->Branch(equal); |
| 5532 deferred->BindExit(); | 5537 deferred->BindExit(); |
| 5533 | 5538 |
| 5534 // Register of boilerplate contains RegExp object. | 5539 // Register of boilerplate contains RegExp object. |
| 5535 | 5540 |
| 5536 Result tmp = allocator()->Allocate(); | 5541 Result tmp = allocator()->Allocate(); |
| 5537 ASSERT(tmp.is_valid()); | 5542 ASSERT(tmp.is_valid()); |
| 5538 | 5543 |
| 5539 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; | 5544 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; |
| 5540 | 5545 |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5678 | 5683 |
| 5679 // Load the literals array of the function. | 5684 // Load the literals array of the function. |
| 5680 __ mov(literals.reg(), | 5685 __ mov(literals.reg(), |
| 5681 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); | 5686 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); |
| 5682 | 5687 |
| 5683 frame_->Push(&literals); | 5688 frame_->Push(&literals); |
| 5684 frame_->Push(Smi::FromInt(node->literal_index())); | 5689 frame_->Push(Smi::FromInt(node->literal_index())); |
| 5685 frame_->Push(node->constant_elements()); | 5690 frame_->Push(node->constant_elements()); |
| 5686 int length = node->values()->length(); | 5691 int length = node->values()->length(); |
| 5687 Result clone; | 5692 Result clone; |
| 5688 if (node->constant_elements()->map() == Heap::fixed_cow_array_map()) { | 5693 if (node->constant_elements()->map() == HEAP->fixed_cow_array_map()) { |
| 5689 FastCloneShallowArrayStub stub( | 5694 FastCloneShallowArrayStub stub( |
| 5690 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); | 5695 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); |
| 5691 clone = frame_->CallStub(&stub, 3); | 5696 clone = frame_->CallStub(&stub, 3); |
| 5692 __ IncrementCounter(&Counters::cow_arrays_created_stub, 1); | 5697 __ IncrementCounter(COUNTERS->cow_arrays_created_stub(), 1); |
| 5693 } else if (node->depth() > 1) { | 5698 } else if (node->depth() > 1) { |
| 5694 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3); | 5699 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3); |
| 5695 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { | 5700 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { |
| 5696 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); | 5701 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); |
| 5697 } else { | 5702 } else { |
| 5698 FastCloneShallowArrayStub stub( | 5703 FastCloneShallowArrayStub stub( |
| 5699 FastCloneShallowArrayStub::CLONE_ELEMENTS, length); | 5704 FastCloneShallowArrayStub::CLONE_ELEMENTS, length); |
| 5700 clone = frame_->CallStub(&stub, 3); | 5705 clone = frame_->CallStub(&stub, 3); |
| 5701 } | 5706 } |
| 5702 frame_->Push(&clone); | 5707 frame_->Push(&clone); |
| (...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6085 | 6090 |
| 6086 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 6091 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
| 6087 // resolve the function we need to call and the receiver of the | 6092 // resolve the function we need to call and the receiver of the |
| 6088 // call. Then we call the resolved function using the given | 6093 // call. Then we call the resolved function using the given |
| 6089 // arguments. | 6094 // arguments. |
| 6090 | 6095 |
| 6091 // Prepare the stack for the call to the resolved function. | 6096 // Prepare the stack for the call to the resolved function. |
| 6092 Load(function); | 6097 Load(function); |
| 6093 | 6098 |
| 6094 // Allocate a frame slot for the receiver. | 6099 // Allocate a frame slot for the receiver. |
| 6095 frame_->Push(Factory::undefined_value()); | 6100 frame_->Push(FACTORY->undefined_value()); |
| 6096 | 6101 |
| 6097 // Load the arguments. | 6102 // Load the arguments. |
| 6098 int arg_count = args->length(); | 6103 int arg_count = args->length(); |
| 6099 for (int i = 0; i < arg_count; i++) { | 6104 for (int i = 0; i < arg_count; i++) { |
| 6100 Load(args->at(i)); | 6105 Load(args->at(i)); |
| 6101 frame_->SpillTop(); | 6106 frame_->SpillTop(); |
| 6102 } | 6107 } |
| 6103 | 6108 |
| 6104 // Result to hold the result of the function resolution and the | 6109 // Result to hold the result of the function resolution and the |
| 6105 // final result of the eval call. | 6110 // final result of the eval call. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 6117 // ResolvePossiblyDirectEvalNoLookup by pushing the loaded | 6122 // ResolvePossiblyDirectEvalNoLookup by pushing the loaded |
| 6118 // function, the first argument to the eval call and the | 6123 // function, the first argument to the eval call and the |
| 6119 // receiver. | 6124 // receiver. |
| 6120 Result fun = LoadFromGlobalSlotCheckExtensions(var->AsSlot(), | 6125 Result fun = LoadFromGlobalSlotCheckExtensions(var->AsSlot(), |
| 6121 NOT_INSIDE_TYPEOF, | 6126 NOT_INSIDE_TYPEOF, |
| 6122 &slow); | 6127 &slow); |
| 6123 frame_->Push(&fun); | 6128 frame_->Push(&fun); |
| 6124 if (arg_count > 0) { | 6129 if (arg_count > 0) { |
| 6125 frame_->PushElementAt(arg_count); | 6130 frame_->PushElementAt(arg_count); |
| 6126 } else { | 6131 } else { |
| 6127 frame_->Push(Factory::undefined_value()); | 6132 frame_->Push(FACTORY->undefined_value()); |
| 6128 } | 6133 } |
| 6129 frame_->PushParameterAt(-1); | 6134 frame_->PushParameterAt(-1); |
| 6130 | 6135 |
| 6131 // Push the strict mode flag. | 6136 // Push the strict mode flag. |
| 6132 frame_->Push(Smi::FromInt(strict_mode_flag())); | 6137 frame_->Push(Smi::FromInt(strict_mode_flag())); |
| 6133 | 6138 |
| 6134 // Resolve the call. | 6139 // Resolve the call. |
| 6135 result = | 6140 result = |
| 6136 frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 4); | 6141 frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 4); |
| 6137 | 6142 |
| 6138 done.Jump(&result); | 6143 done.Jump(&result); |
| 6139 slow.Bind(); | 6144 slow.Bind(); |
| 6140 } | 6145 } |
| 6141 | 6146 |
| 6142 // Prepare the stack for the call to ResolvePossiblyDirectEval by | 6147 // Prepare the stack for the call to ResolvePossiblyDirectEval by |
| 6143 // pushing the loaded function, the first argument to the eval | 6148 // pushing the loaded function, the first argument to the eval |
| 6144 // call and the receiver. | 6149 // call and the receiver. |
| 6145 frame_->PushElementAt(arg_count + 1); | 6150 frame_->PushElementAt(arg_count + 1); |
| 6146 if (arg_count > 0) { | 6151 if (arg_count > 0) { |
| 6147 frame_->PushElementAt(arg_count); | 6152 frame_->PushElementAt(arg_count); |
| 6148 } else { | 6153 } else { |
| 6149 frame_->Push(Factory::undefined_value()); | 6154 frame_->Push(FACTORY->undefined_value()); |
| 6150 } | 6155 } |
| 6151 frame_->PushParameterAt(-1); | 6156 frame_->PushParameterAt(-1); |
| 6152 | 6157 |
| 6153 // Push the strict mode flag. | 6158 // Push the strict mode flag. |
| 6154 frame_->Push(Smi::FromInt(strict_mode_flag())); | 6159 frame_->Push(Smi::FromInt(strict_mode_flag())); |
| 6155 | 6160 |
| 6156 // Resolve the call. | 6161 // Resolve the call. |
| 6157 result = frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 4); | 6162 result = frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 4); |
| 6158 | 6163 |
| 6159 // If we generated fast-case code bind the jump-target where fast | 6164 // If we generated fast-case code bind the jump-target where fast |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6433 // 2 (array): Arguments to the format string. | 6438 // 2 (array): Arguments to the format string. |
| 6434 ASSERT_EQ(args->length(), 3); | 6439 ASSERT_EQ(args->length(), 3); |
| 6435 #ifdef ENABLE_LOGGING_AND_PROFILING | 6440 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 6436 if (ShouldGenerateLog(args->at(0))) { | 6441 if (ShouldGenerateLog(args->at(0))) { |
| 6437 Load(args->at(1)); | 6442 Load(args->at(1)); |
| 6438 Load(args->at(2)); | 6443 Load(args->at(2)); |
| 6439 frame_->CallRuntime(Runtime::kLog, 2); | 6444 frame_->CallRuntime(Runtime::kLog, 2); |
| 6440 } | 6445 } |
| 6441 #endif | 6446 #endif |
| 6442 // Finally, we're expected to leave a value on the top of the stack. | 6447 // Finally, we're expected to leave a value on the top of the stack. |
| 6443 frame_->Push(Factory::undefined_value()); | 6448 frame_->Push(FACTORY->undefined_value()); |
| 6444 } | 6449 } |
| 6445 | 6450 |
| 6446 | 6451 |
| 6447 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 6452 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 6448 ASSERT(args->length() == 1); | 6453 ASSERT(args->length() == 1); |
| 6449 Load(args->at(0)); | 6454 Load(args->at(0)); |
| 6450 Result value = frame_->Pop(); | 6455 Result value = frame_->Pop(); |
| 6451 value.ToRegister(); | 6456 value.ToRegister(); |
| 6452 ASSERT(value.is_valid()); | 6457 ASSERT(value.is_valid()); |
| 6453 __ test(value.reg(), Immediate(kSmiTagMask | kSmiSignMask)); | 6458 __ test(value.reg(), Immediate(kSmiTagMask | kSmiSignMask)); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 6476 return &char_code_at_generator_; | 6481 return &char_code_at_generator_; |
| 6477 } | 6482 } |
| 6478 | 6483 |
| 6479 virtual void Generate() { | 6484 virtual void Generate() { |
| 6480 VirtualFrameRuntimeCallHelper call_helper(frame_state()); | 6485 VirtualFrameRuntimeCallHelper call_helper(frame_state()); |
| 6481 char_code_at_generator_.GenerateSlow(masm(), call_helper); | 6486 char_code_at_generator_.GenerateSlow(masm(), call_helper); |
| 6482 | 6487 |
| 6483 __ bind(&need_conversion_); | 6488 __ bind(&need_conversion_); |
| 6484 // Move the undefined value into the result register, which will | 6489 // Move the undefined value into the result register, which will |
| 6485 // trigger conversion. | 6490 // trigger conversion. |
| 6486 __ Set(result_, Immediate(Factory::undefined_value())); | 6491 __ Set(result_, Immediate(FACTORY->undefined_value())); |
| 6487 __ jmp(exit_label()); | 6492 __ jmp(exit_label()); |
| 6488 | 6493 |
| 6489 __ bind(&index_out_of_range_); | 6494 __ bind(&index_out_of_range_); |
| 6490 // When the index is out of range, the spec requires us to return | 6495 // When the index is out of range, the spec requires us to return |
| 6491 // NaN. | 6496 // NaN. |
| 6492 __ Set(result_, Immediate(Factory::nan_value())); | 6497 __ Set(result_, Immediate(FACTORY->nan_value())); |
| 6493 __ jmp(exit_label()); | 6498 __ jmp(exit_label()); |
| 6494 } | 6499 } |
| 6495 | 6500 |
| 6496 private: | 6501 private: |
| 6497 Register result_; | 6502 Register result_; |
| 6498 | 6503 |
| 6499 Label need_conversion_; | 6504 Label need_conversion_; |
| 6500 Label index_out_of_range_; | 6505 Label index_out_of_range_; |
| 6501 | 6506 |
| 6502 StringCharCodeAtGenerator char_code_at_generator_; | 6507 StringCharCodeAtGenerator char_code_at_generator_; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6605 | 6610 |
| 6606 __ bind(&need_conversion_); | 6611 __ bind(&need_conversion_); |
| 6607 // Move smi zero into the result register, which will trigger | 6612 // Move smi zero into the result register, which will trigger |
| 6608 // conversion. | 6613 // conversion. |
| 6609 __ Set(result_, Immediate(Smi::FromInt(0))); | 6614 __ Set(result_, Immediate(Smi::FromInt(0))); |
| 6610 __ jmp(exit_label()); | 6615 __ jmp(exit_label()); |
| 6611 | 6616 |
| 6612 __ bind(&index_out_of_range_); | 6617 __ bind(&index_out_of_range_); |
| 6613 // When the index is out of range, the spec requires us to return | 6618 // When the index is out of range, the spec requires us to return |
| 6614 // the empty string. | 6619 // the empty string. |
| 6615 __ Set(result_, Immediate(Factory::empty_string())); | 6620 __ Set(result_, Immediate(FACTORY->empty_string())); |
| 6616 __ jmp(exit_label()); | 6621 __ jmp(exit_label()); |
| 6617 } | 6622 } |
| 6618 | 6623 |
| 6619 private: | 6624 private: |
| 6620 Register result_; | 6625 Register result_; |
| 6621 | 6626 |
| 6622 Label need_conversion_; | 6627 Label need_conversion_; |
| 6623 Label index_out_of_range_; | 6628 Label index_out_of_range_; |
| 6624 | 6629 |
| 6625 StringCharAtGenerator char_at_generator_; | 6630 StringCharAtGenerator char_at_generator_; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6723 | 6728 |
| 6724 // Check that the array has fast elements. | 6729 // Check that the array has fast elements. |
| 6725 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), | 6730 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), |
| 6726 1 << Map::kHasFastElements); | 6731 1 << Map::kHasFastElements); |
| 6727 __ j(zero, &bailout); | 6732 __ j(zero, &bailout); |
| 6728 | 6733 |
| 6729 // If the array has length zero, return the empty string. | 6734 // If the array has length zero, return the empty string. |
| 6730 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); | 6735 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); |
| 6731 __ sar(array_length, 1); | 6736 __ sar(array_length, 1); |
| 6732 __ j(not_zero, &non_trivial_array); | 6737 __ j(not_zero, &non_trivial_array); |
| 6733 __ mov(result_operand, Factory::empty_string()); | 6738 __ mov(result_operand, FACTORY->empty_string()); |
| 6734 __ jmp(&done); | 6739 __ jmp(&done); |
| 6735 | 6740 |
| 6736 // Save the array length. | 6741 // Save the array length. |
| 6737 __ bind(&non_trivial_array); | 6742 __ bind(&non_trivial_array); |
| 6738 __ mov(array_length_operand, array_length); | 6743 __ mov(array_length_operand, array_length); |
| 6739 | 6744 |
| 6740 // Save the FixedArray containing array's elements. | 6745 // Save the FixedArray containing array's elements. |
| 6741 // End of array's live range. | 6746 // End of array's live range. |
| 6742 elements = array; | 6747 elements = array; |
| 6743 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset)); | 6748 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset)); |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6934 FieldOperand(string, SeqAsciiString::kHeaderSize)); | 6939 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 6935 __ CopyBytes(string, result_pos, string_length, scratch); | 6940 __ CopyBytes(string, result_pos, string_length, scratch); |
| 6936 __ add(Operand(index), Immediate(1)); | 6941 __ add(Operand(index), Immediate(1)); |
| 6937 | 6942 |
| 6938 __ cmp(index, array_length_operand); | 6943 __ cmp(index, array_length_operand); |
| 6939 __ j(less, &loop_3); // End while (index < length). | 6944 __ j(less, &loop_3); // End while (index < length). |
| 6940 __ jmp(&done); | 6945 __ jmp(&done); |
| 6941 | 6946 |
| 6942 | 6947 |
| 6943 __ bind(&bailout); | 6948 __ bind(&bailout); |
| 6944 __ mov(result_operand, Factory::undefined_value()); | 6949 __ mov(result_operand, FACTORY->undefined_value()); |
| 6945 __ bind(&done); | 6950 __ bind(&done); |
| 6946 __ mov(eax, result_operand); | 6951 __ mov(eax, result_operand); |
| 6947 // Drop temp values from the stack, and restore context register. | 6952 // Drop temp values from the stack, and restore context register. |
| 6948 __ add(Operand(esp), Immediate(2 * kPointerSize)); | 6953 __ add(Operand(esp), Immediate(2 * kPointerSize)); |
| 6949 | 6954 |
| 6950 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 6955 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 6951 frame_->Drop(1); | 6956 frame_->Drop(1); |
| 6952 frame_->Push(&array_result); | 6957 frame_->Push(&array_result); |
| 6953 } | 6958 } |
| 6954 | 6959 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 6975 void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { | 6980 void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { |
| 6976 // This generates a fast version of: | 6981 // This generates a fast version of: |
| 6977 // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') | 6982 // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') |
| 6978 ASSERT(args->length() == 1); | 6983 ASSERT(args->length() == 1); |
| 6979 Load(args->at(0)); | 6984 Load(args->at(0)); |
| 6980 Result obj = frame_->Pop(); | 6985 Result obj = frame_->Pop(); |
| 6981 obj.ToRegister(); | 6986 obj.ToRegister(); |
| 6982 | 6987 |
| 6983 __ test(obj.reg(), Immediate(kSmiTagMask)); | 6988 __ test(obj.reg(), Immediate(kSmiTagMask)); |
| 6984 destination()->false_target()->Branch(zero); | 6989 destination()->false_target()->Branch(zero); |
| 6985 __ cmp(obj.reg(), Factory::null_value()); | 6990 __ cmp(obj.reg(), FACTORY->null_value()); |
| 6986 destination()->true_target()->Branch(equal); | 6991 destination()->true_target()->Branch(equal); |
| 6987 | 6992 |
| 6988 Result map = allocator()->Allocate(); | 6993 Result map = allocator()->Allocate(); |
| 6989 ASSERT(map.is_valid()); | 6994 ASSERT(map.is_valid()); |
| 6990 __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset)); | 6995 __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset)); |
| 6991 // Undetectable objects behave like undefined when tested with typeof. | 6996 // Undetectable objects behave like undefined when tested with typeof. |
| 6992 __ test_b(FieldOperand(map.reg(), Map::kBitFieldOffset), | 6997 __ test_b(FieldOperand(map.reg(), Map::kBitFieldOffset), |
| 6993 1 << Map::kIsUndetectable); | 6998 1 << Map::kIsUndetectable); |
| 6994 destination()->false_target()->Branch(not_zero); | 6999 destination()->false_target()->Branch(not_zero); |
| 6995 // Do a range test for JSObject type. We can't use | 7000 // Do a range test for JSObject type. We can't use |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7046 | 7051 |
| 7047 // Check that map is loaded as expected. | 7052 // Check that map is loaded as expected. |
| 7048 if (FLAG_debug_code) { | 7053 if (FLAG_debug_code) { |
| 7049 __ cmp(map_result_, FieldOperand(object_, HeapObject::kMapOffset)); | 7054 __ cmp(map_result_, FieldOperand(object_, HeapObject::kMapOffset)); |
| 7050 __ Assert(equal, "Map not in expected register"); | 7055 __ Assert(equal, "Map not in expected register"); |
| 7051 } | 7056 } |
| 7052 | 7057 |
| 7053 // Check for fast case object. Generate false result for slow case object. | 7058 // Check for fast case object. Generate false result for slow case object. |
| 7054 __ mov(scratch1_, FieldOperand(object_, JSObject::kPropertiesOffset)); | 7059 __ mov(scratch1_, FieldOperand(object_, JSObject::kPropertiesOffset)); |
| 7055 __ mov(scratch1_, FieldOperand(scratch1_, HeapObject::kMapOffset)); | 7060 __ mov(scratch1_, FieldOperand(scratch1_, HeapObject::kMapOffset)); |
| 7056 __ cmp(scratch1_, Factory::hash_table_map()); | 7061 __ cmp(scratch1_, FACTORY->hash_table_map()); |
| 7057 __ j(equal, &false_result); | 7062 __ j(equal, &false_result); |
| 7058 | 7063 |
| 7059 // Look for valueOf symbol in the descriptor array, and indicate false if | 7064 // Look for valueOf symbol in the descriptor array, and indicate false if |
| 7060 // found. The type is not checked, so if it is a transition it is a false | 7065 // found. The type is not checked, so if it is a transition it is a false |
| 7061 // negative. | 7066 // negative. |
| 7062 __ mov(map_result_, | 7067 __ mov(map_result_, |
| 7063 FieldOperand(map_result_, Map::kInstanceDescriptorsOffset)); | 7068 FieldOperand(map_result_, Map::kInstanceDescriptorsOffset)); |
| 7064 __ mov(scratch1_, FieldOperand(map_result_, FixedArray::kLengthOffset)); | 7069 __ mov(scratch1_, FieldOperand(map_result_, FixedArray::kLengthOffset)); |
| 7065 // map_result_: descriptor array | 7070 // map_result_: descriptor array |
| 7066 // scratch1_: length of descriptor array | 7071 // scratch1_: length of descriptor array |
| 7067 // Calculate the end of the descriptor array. | 7072 // Calculate the end of the descriptor array. |
| 7068 STATIC_ASSERT(kSmiTag == 0); | 7073 STATIC_ASSERT(kSmiTag == 0); |
| 7069 STATIC_ASSERT(kSmiTagSize == 1); | 7074 STATIC_ASSERT(kSmiTagSize == 1); |
| 7070 STATIC_ASSERT(kPointerSize == 4); | 7075 STATIC_ASSERT(kPointerSize == 4); |
| 7071 __ lea(scratch1_, | 7076 __ lea(scratch1_, |
| 7072 Operand(map_result_, scratch1_, times_2, FixedArray::kHeaderSize)); | 7077 Operand(map_result_, scratch1_, times_2, FixedArray::kHeaderSize)); |
| 7073 // Calculate location of the first key name. | 7078 // Calculate location of the first key name. |
| 7074 __ add(Operand(map_result_), | 7079 __ add(Operand(map_result_), |
| 7075 Immediate(FixedArray::kHeaderSize + | 7080 Immediate(FixedArray::kHeaderSize + |
| 7076 DescriptorArray::kFirstIndex * kPointerSize)); | 7081 DescriptorArray::kFirstIndex * kPointerSize)); |
| 7077 // Loop through all the keys in the descriptor array. If one of these is the | 7082 // Loop through all the keys in the descriptor array. If one of these is the |
| 7078 // symbol valueOf the result is false. | 7083 // symbol valueOf the result is false. |
| 7079 Label entry, loop; | 7084 Label entry, loop; |
| 7080 __ jmp(&entry); | 7085 __ jmp(&entry); |
| 7081 __ bind(&loop); | 7086 __ bind(&loop); |
| 7082 __ mov(scratch2_, FieldOperand(map_result_, 0)); | 7087 __ mov(scratch2_, FieldOperand(map_result_, 0)); |
| 7083 __ cmp(scratch2_, Factory::value_of_symbol()); | 7088 __ cmp(scratch2_, FACTORY->value_of_symbol()); |
| 7084 __ j(equal, &false_result); | 7089 __ j(equal, &false_result); |
| 7085 __ add(Operand(map_result_), Immediate(kPointerSize)); | 7090 __ add(Operand(map_result_), Immediate(kPointerSize)); |
| 7086 __ bind(&entry); | 7091 __ bind(&entry); |
| 7087 __ cmp(map_result_, Operand(scratch1_)); | 7092 __ cmp(map_result_, Operand(scratch1_)); |
| 7088 __ j(not_equal, &loop); | 7093 __ j(not_equal, &loop); |
| 7089 | 7094 |
| 7090 // Reload map as register map_result_ was used as temporary above. | 7095 // Reload map as register map_result_ was used as temporary above. |
| 7091 __ mov(map_result_, FieldOperand(object_, HeapObject::kMapOffset)); | 7096 __ mov(map_result_, FieldOperand(object_, HeapObject::kMapOffset)); |
| 7092 | 7097 |
| 7093 // If a valueOf property is not found on the object check that it's | 7098 // If a valueOf property is not found on the object check that it's |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7288 // instance class name from there. | 7293 // instance class name from there. |
| 7289 __ mov(obj.reg(), | 7294 __ mov(obj.reg(), |
| 7290 FieldOperand(obj.reg(), JSFunction::kSharedFunctionInfoOffset)); | 7295 FieldOperand(obj.reg(), JSFunction::kSharedFunctionInfoOffset)); |
| 7291 __ mov(obj.reg(), | 7296 __ mov(obj.reg(), |
| 7292 FieldOperand(obj.reg(), SharedFunctionInfo::kInstanceClassNameOffset)); | 7297 FieldOperand(obj.reg(), SharedFunctionInfo::kInstanceClassNameOffset)); |
| 7293 frame_->Push(&obj); | 7298 frame_->Push(&obj); |
| 7294 leave.Jump(); | 7299 leave.Jump(); |
| 7295 | 7300 |
| 7296 // Functions have class 'Function'. | 7301 // Functions have class 'Function'. |
| 7297 function.Bind(); | 7302 function.Bind(); |
| 7298 frame_->Push(Factory::function_class_symbol()); | 7303 frame_->Push(FACTORY->function_class_symbol()); |
| 7299 leave.Jump(); | 7304 leave.Jump(); |
| 7300 | 7305 |
| 7301 // Objects with a non-function constructor have class 'Object'. | 7306 // Objects with a non-function constructor have class 'Object'. |
| 7302 non_function_constructor.Bind(); | 7307 non_function_constructor.Bind(); |
| 7303 frame_->Push(Factory::Object_symbol()); | 7308 frame_->Push(FACTORY->Object_symbol()); |
| 7304 leave.Jump(); | 7309 leave.Jump(); |
| 7305 | 7310 |
| 7306 // Non-JS objects have class null. | 7311 // Non-JS objects have class null. |
| 7307 null.Bind(); | 7312 null.Bind(); |
| 7308 frame_->Push(Factory::null_value()); | 7313 frame_->Push(FACTORY->null_value()); |
| 7309 | 7314 |
| 7310 // All done. | 7315 // All done. |
| 7311 leave.Bind(); | 7316 leave.Bind(); |
| 7312 } | 7317 } |
| 7313 | 7318 |
| 7314 | 7319 |
| 7315 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 7320 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 7316 ASSERT(args->length() == 1); | 7321 ASSERT(args->length() == 1); |
| 7317 JumpTarget leave; | 7322 JumpTarget leave; |
| 7318 Load(args->at(0)); // Load the object. | 7323 Load(args->at(0)); // Load the object. |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7440 | 7445 |
| 7441 __ bind(&heapnumber_allocated); | 7446 __ bind(&heapnumber_allocated); |
| 7442 | 7447 |
| 7443 __ PrepareCallCFunction(0, ebx); | 7448 __ PrepareCallCFunction(0, ebx); |
| 7444 __ CallCFunction(ExternalReference::random_uint32_function(), 0); | 7449 __ CallCFunction(ExternalReference::random_uint32_function(), 0); |
| 7445 | 7450 |
| 7446 // Convert 32 random bits in eax to 0.(32 random bits) in a double | 7451 // Convert 32 random bits in eax to 0.(32 random bits) in a double |
| 7447 // by computing: | 7452 // by computing: |
| 7448 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). | 7453 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). |
| 7449 // This is implemented on both SSE2 and FPU. | 7454 // This is implemented on both SSE2 and FPU. |
| 7450 if (CpuFeatures::IsSupported(SSE2)) { | 7455 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 7451 CpuFeatures::Scope fscope(SSE2); | 7456 CpuFeatures::Scope fscope(SSE2); |
| 7452 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. | 7457 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. |
| 7453 __ movd(xmm1, Operand(ebx)); | 7458 __ movd(xmm1, Operand(ebx)); |
| 7454 __ movd(xmm0, Operand(eax)); | 7459 __ movd(xmm0, Operand(eax)); |
| 7455 __ cvtss2sd(xmm1, xmm1); | 7460 __ cvtss2sd(xmm1, xmm1); |
| 7456 __ pxor(xmm0, xmm1); | 7461 __ pxor(xmm0, xmm1); |
| 7457 __ subsd(xmm0, xmm1); | 7462 __ subsd(xmm0, xmm1); |
| 7458 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0); | 7463 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0); |
| 7459 } else { | 7464 } else { |
| 7460 // 0x4130000000000000 is 1.0 x 2^20 as a double. | 7465 // 0x4130000000000000 is 1.0 x 2^20 as a double. |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7657 } | 7662 } |
| 7658 | 7663 |
| 7659 | 7664 |
| 7660 void CodeGenerator::GenerateGetFromCache(ZoneList<Expression*>* args) { | 7665 void CodeGenerator::GenerateGetFromCache(ZoneList<Expression*>* args) { |
| 7661 ASSERT_EQ(2, args->length()); | 7666 ASSERT_EQ(2, args->length()); |
| 7662 | 7667 |
| 7663 ASSERT_NE(NULL, args->at(0)->AsLiteral()); | 7668 ASSERT_NE(NULL, args->at(0)->AsLiteral()); |
| 7664 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); | 7669 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); |
| 7665 | 7670 |
| 7666 Handle<FixedArray> jsfunction_result_caches( | 7671 Handle<FixedArray> jsfunction_result_caches( |
| 7667 Top::global_context()->jsfunction_result_caches()); | 7672 Isolate::Current()->global_context()->jsfunction_result_caches()); |
| 7668 if (jsfunction_result_caches->length() <= cache_id) { | 7673 if (jsfunction_result_caches->length() <= cache_id) { |
| 7669 __ Abort("Attempt to use undefined cache."); | 7674 __ Abort("Attempt to use undefined cache."); |
| 7670 frame_->Push(Factory::undefined_value()); | 7675 frame_->Push(FACTORY->undefined_value()); |
| 7671 return; | 7676 return; |
| 7672 } | 7677 } |
| 7673 | 7678 |
| 7674 Load(args->at(1)); | 7679 Load(args->at(1)); |
| 7675 Result key = frame_->Pop(); | 7680 Result key = frame_->Pop(); |
| 7676 key.ToRegister(); | 7681 key.ToRegister(); |
| 7677 | 7682 |
| 7678 Result cache = allocator()->Allocate(); | 7683 Result cache = allocator()->Allocate(); |
| 7679 ASSERT(cache.is_valid()); | 7684 ASSERT(cache.is_valid()); |
| 7680 __ mov(cache.reg(), ContextOperand(esi, Context::GLOBAL_INDEX)); | 7685 __ mov(cache.reg(), ContextOperand(esi, Context::GLOBAL_INDEX)); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7777 // has no indexed interceptor. | 7782 // has no indexed interceptor. |
| 7778 __ CmpObjectType(object.reg(), FIRST_JS_OBJECT_TYPE, tmp1.reg()); | 7783 __ CmpObjectType(object.reg(), FIRST_JS_OBJECT_TYPE, tmp1.reg()); |
| 7779 deferred->Branch(below); | 7784 deferred->Branch(below); |
| 7780 __ test_b(FieldOperand(tmp1.reg(), Map::kBitFieldOffset), | 7785 __ test_b(FieldOperand(tmp1.reg(), Map::kBitFieldOffset), |
| 7781 KeyedLoadIC::kSlowCaseBitFieldMask); | 7786 KeyedLoadIC::kSlowCaseBitFieldMask); |
| 7782 deferred->Branch(not_zero); | 7787 deferred->Branch(not_zero); |
| 7783 | 7788 |
| 7784 // Check the object's elements are in fast case and writable. | 7789 // Check the object's elements are in fast case and writable. |
| 7785 __ mov(tmp1.reg(), FieldOperand(object.reg(), JSObject::kElementsOffset)); | 7790 __ mov(tmp1.reg(), FieldOperand(object.reg(), JSObject::kElementsOffset)); |
| 7786 __ cmp(FieldOperand(tmp1.reg(), HeapObject::kMapOffset), | 7791 __ cmp(FieldOperand(tmp1.reg(), HeapObject::kMapOffset), |
| 7787 Immediate(Factory::fixed_array_map())); | 7792 Immediate(FACTORY->fixed_array_map())); |
| 7788 deferred->Branch(not_equal); | 7793 deferred->Branch(not_equal); |
| 7789 | 7794 |
| 7790 // Smi-tagging is equivalent to multiplying by 2. | 7795 // Smi-tagging is equivalent to multiplying by 2. |
| 7791 STATIC_ASSERT(kSmiTag == 0); | 7796 STATIC_ASSERT(kSmiTag == 0); |
| 7792 STATIC_ASSERT(kSmiTagSize == 1); | 7797 STATIC_ASSERT(kSmiTagSize == 1); |
| 7793 | 7798 |
| 7794 // Check that both indices are smis. | 7799 // Check that both indices are smis. |
| 7795 __ mov(tmp2.reg(), index1.reg()); | 7800 __ mov(tmp2.reg(), index1.reg()); |
| 7796 __ or_(tmp2.reg(), Operand(index2.reg())); | 7801 __ or_(tmp2.reg(), Operand(index2.reg())); |
| 7797 __ test(tmp2.reg(), Immediate(kSmiTagMask)); | 7802 __ test(tmp2.reg(), Immediate(kSmiTagMask)); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 7818 __ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done); | 7823 __ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done); |
| 7819 // Possible optimization: do a check that both values are Smis | 7824 // Possible optimization: do a check that both values are Smis |
| 7820 // (or them and test against Smi mask.) | 7825 // (or them and test against Smi mask.) |
| 7821 | 7826 |
| 7822 __ mov(tmp2.reg(), tmp1.reg()); | 7827 __ mov(tmp2.reg(), tmp1.reg()); |
| 7823 __ RecordWriteHelper(tmp2.reg(), index1.reg(), object.reg()); | 7828 __ RecordWriteHelper(tmp2.reg(), index1.reg(), object.reg()); |
| 7824 __ RecordWriteHelper(tmp1.reg(), index2.reg(), object.reg()); | 7829 __ RecordWriteHelper(tmp1.reg(), index2.reg(), object.reg()); |
| 7825 __ bind(&done); | 7830 __ bind(&done); |
| 7826 | 7831 |
| 7827 deferred->BindExit(); | 7832 deferred->BindExit(); |
| 7828 frame_->Push(Factory::undefined_value()); | 7833 frame_->Push(FACTORY->undefined_value()); |
| 7829 } | 7834 } |
| 7830 | 7835 |
| 7831 | 7836 |
| 7832 void CodeGenerator::GenerateCallFunction(ZoneList<Expression*>* args) { | 7837 void CodeGenerator::GenerateCallFunction(ZoneList<Expression*>* args) { |
| 7833 Comment cmnt(masm_, "[ GenerateCallFunction"); | 7838 Comment cmnt(masm_, "[ GenerateCallFunction"); |
| 7834 | 7839 |
| 7835 ASSERT(args->length() >= 2); | 7840 ASSERT(args->length() >= 2); |
| 7836 | 7841 |
| 7837 int n_args = args->length() - 2; // for receiver and function. | 7842 int n_args = args->length() - 2; // for receiver and function. |
| 7838 Load(args->at(0)); // receiver | 7843 Load(args->at(0)); // receiver |
| 7839 for (int i = 0; i < n_args; i++) { | 7844 for (int i = 0; i < n_args; i++) { |
| 7840 Load(args->at(i + 1)); | 7845 Load(args->at(i + 1)); |
| 7841 } | 7846 } |
| 7842 Load(args->at(n_args + 1)); // function | 7847 Load(args->at(n_args + 1)); // function |
| 7843 Result result = frame_->CallJSFunction(n_args); | 7848 Result result = frame_->CallJSFunction(n_args); |
| 7844 frame_->Push(&result); | 7849 frame_->Push(&result); |
| 7845 } | 7850 } |
| 7846 | 7851 |
| 7847 | 7852 |
| 7848 // Generates the Math.pow method. Only handles special cases and | 7853 // Generates the Math.pow method. Only handles special cases and |
| 7849 // branches to the runtime system for everything else. Please note | 7854 // branches to the runtime system for everything else. Please note |
| 7850 // that this function assumes that the callsite has executed ToNumber | 7855 // that this function assumes that the callsite has executed ToNumber |
| 7851 // on both arguments. | 7856 // on both arguments. |
| 7852 void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { | 7857 void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { |
| 7853 ASSERT(args->length() == 2); | 7858 ASSERT(args->length() == 2); |
| 7854 Load(args->at(0)); | 7859 Load(args->at(0)); |
| 7855 Load(args->at(1)); | 7860 Load(args->at(1)); |
| 7856 if (!CpuFeatures::IsSupported(SSE2)) { | 7861 if (!Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 7857 Result res = frame_->CallRuntime(Runtime::kMath_pow, 2); | 7862 Result res = frame_->CallRuntime(Runtime::kMath_pow, 2); |
| 7858 frame_->Push(&res); | 7863 frame_->Push(&res); |
| 7859 } else { | 7864 } else { |
| 7860 CpuFeatures::Scope use_sse2(SSE2); | 7865 CpuFeatures::Scope use_sse2(SSE2); |
| 7861 Label allocate_return; | 7866 Label allocate_return; |
| 7862 // Load the two operands while leaving the values on the frame. | 7867 // Load the two operands while leaving the values on the frame. |
| 7863 frame()->Dup(); | 7868 frame()->Dup(); |
| 7864 Result exponent = frame()->Pop(); | 7869 Result exponent = frame()->Pop(); |
| 7865 exponent.ToRegister(); | 7870 exponent.ToRegister(); |
| 7866 frame()->Spill(exponent.reg()); | 7871 frame()->Spill(exponent.reg()); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 7887 __ j(not_zero, &base_nonsmi); | 7892 __ j(not_zero, &base_nonsmi); |
| 7888 | 7893 |
| 7889 // Optimized version when y is an integer. | 7894 // Optimized version when y is an integer. |
| 7890 Label powi; | 7895 Label powi; |
| 7891 __ SmiUntag(base.reg()); | 7896 __ SmiUntag(base.reg()); |
| 7892 __ cvtsi2sd(xmm0, Operand(base.reg())); | 7897 __ cvtsi2sd(xmm0, Operand(base.reg())); |
| 7893 __ jmp(&powi); | 7898 __ jmp(&powi); |
| 7894 // exponent is smi and base is a heapnumber. | 7899 // exponent is smi and base is a heapnumber. |
| 7895 __ bind(&base_nonsmi); | 7900 __ bind(&base_nonsmi); |
| 7896 __ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset), | 7901 __ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset), |
| 7897 Factory::heap_number_map()); | 7902 FACTORY->heap_number_map()); |
| 7898 call_runtime.Branch(not_equal); | 7903 call_runtime.Branch(not_equal); |
| 7899 | 7904 |
| 7900 __ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset)); | 7905 __ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset)); |
| 7901 | 7906 |
| 7902 // Optimized version of pow if y is an integer. | 7907 // Optimized version of pow if y is an integer. |
| 7903 __ bind(&powi); | 7908 __ bind(&powi); |
| 7904 __ SmiUntag(exponent.reg()); | 7909 __ SmiUntag(exponent.reg()); |
| 7905 | 7910 |
| 7906 // Save exponent in base as we need to check if exponent is negative later. | 7911 // Save exponent in base as we need to check if exponent is negative later. |
| 7907 // We know that base and exponent are in different registers. | 7912 // We know that base and exponent are in different registers. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 7938 __ ucomisd(xmm0, xmm1); | 7943 __ ucomisd(xmm0, xmm1); |
| 7939 call_runtime.Branch(equal); | 7944 call_runtime.Branch(equal); |
| 7940 __ divsd(xmm3, xmm1); | 7945 __ divsd(xmm3, xmm1); |
| 7941 __ movsd(xmm1, xmm3); | 7946 __ movsd(xmm1, xmm3); |
| 7942 __ jmp(&allocate_return); | 7947 __ jmp(&allocate_return); |
| 7943 | 7948 |
| 7944 // exponent (or both) is a heapnumber - no matter what we should now work | 7949 // exponent (or both) is a heapnumber - no matter what we should now work |
| 7945 // on doubles. | 7950 // on doubles. |
| 7946 __ bind(&exponent_nonsmi); | 7951 __ bind(&exponent_nonsmi); |
| 7947 __ cmp(FieldOperand(exponent.reg(), HeapObject::kMapOffset), | 7952 __ cmp(FieldOperand(exponent.reg(), HeapObject::kMapOffset), |
| 7948 Factory::heap_number_map()); | 7953 FACTORY->heap_number_map()); |
| 7949 call_runtime.Branch(not_equal); | 7954 call_runtime.Branch(not_equal); |
| 7950 __ movdbl(xmm1, FieldOperand(exponent.reg(), HeapNumber::kValueOffset)); | 7955 __ movdbl(xmm1, FieldOperand(exponent.reg(), HeapNumber::kValueOffset)); |
| 7951 // Test if exponent is nan. | 7956 // Test if exponent is nan. |
| 7952 __ ucomisd(xmm1, xmm1); | 7957 __ ucomisd(xmm1, xmm1); |
| 7953 call_runtime.Branch(parity_even); | 7958 call_runtime.Branch(parity_even); |
| 7954 | 7959 |
| 7955 Label base_not_smi; | 7960 Label base_not_smi; |
| 7956 Label handle_special_cases; | 7961 Label handle_special_cases; |
| 7957 __ test(base.reg(), Immediate(kSmiTagMask)); | 7962 __ test(base.reg(), Immediate(kSmiTagMask)); |
| 7958 __ j(not_zero, &base_not_smi); | 7963 __ j(not_zero, &base_not_smi); |
| 7959 __ SmiUntag(base.reg()); | 7964 __ SmiUntag(base.reg()); |
| 7960 __ cvtsi2sd(xmm0, Operand(base.reg())); | 7965 __ cvtsi2sd(xmm0, Operand(base.reg())); |
| 7961 __ jmp(&handle_special_cases); | 7966 __ jmp(&handle_special_cases); |
| 7962 __ bind(&base_not_smi); | 7967 __ bind(&base_not_smi); |
| 7963 __ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset), | 7968 __ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset), |
| 7964 Factory::heap_number_map()); | 7969 FACTORY->heap_number_map()); |
| 7965 call_runtime.Branch(not_equal); | 7970 call_runtime.Branch(not_equal); |
| 7966 __ mov(answer.reg(), FieldOperand(base.reg(), HeapNumber::kExponentOffset)); | 7971 __ mov(answer.reg(), FieldOperand(base.reg(), HeapNumber::kExponentOffset)); |
| 7967 __ and_(answer.reg(), HeapNumber::kExponentMask); | 7972 __ and_(answer.reg(), HeapNumber::kExponentMask); |
| 7968 __ cmp(Operand(answer.reg()), Immediate(HeapNumber::kExponentMask)); | 7973 __ cmp(Operand(answer.reg()), Immediate(HeapNumber::kExponentMask)); |
| 7969 // base is NaN or +/-Infinity | 7974 // base is NaN or +/-Infinity |
| 7970 call_runtime.Branch(greater_equal); | 7975 call_runtime.Branch(greater_equal); |
| 7971 __ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset)); | 7976 __ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset)); |
| 7972 | 7977 |
| 7973 // base is in xmm0 and exponent is in xmm1. | 7978 // base is in xmm0 and exponent is in xmm1. |
| 7974 __ bind(&handle_special_cases); | 7979 __ bind(&handle_special_cases); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8063 frame_->Push(&result); | 8068 frame_->Push(&result); |
| 8064 } | 8069 } |
| 8065 | 8070 |
| 8066 | 8071 |
| 8067 // Generates the Math.sqrt method. Please note - this function assumes that | 8072 // Generates the Math.sqrt method. Please note - this function assumes that |
| 8068 // the callsite has executed ToNumber on the argument. | 8073 // the callsite has executed ToNumber on the argument. |
| 8069 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { | 8074 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { |
| 8070 ASSERT_EQ(args->length(), 1); | 8075 ASSERT_EQ(args->length(), 1); |
| 8071 Load(args->at(0)); | 8076 Load(args->at(0)); |
| 8072 | 8077 |
| 8073 if (!CpuFeatures::IsSupported(SSE2)) { | 8078 if (!Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 8074 Result result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); | 8079 Result result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); |
| 8075 frame()->Push(&result); | 8080 frame()->Push(&result); |
| 8076 } else { | 8081 } else { |
| 8077 CpuFeatures::Scope use_sse2(SSE2); | 8082 CpuFeatures::Scope use_sse2(SSE2); |
| 8078 // Leave original value on the frame if we need to call runtime. | 8083 // Leave original value on the frame if we need to call runtime. |
| 8079 frame()->Dup(); | 8084 frame()->Dup(); |
| 8080 Result result = frame()->Pop(); | 8085 Result result = frame()->Pop(); |
| 8081 result.ToRegister(); | 8086 result.ToRegister(); |
| 8082 frame()->Spill(result.reg()); | 8087 frame()->Spill(result.reg()); |
| 8083 Label runtime; | 8088 Label runtime; |
| 8084 Label non_smi; | 8089 Label non_smi; |
| 8085 Label load_done; | 8090 Label load_done; |
| 8086 JumpTarget end; | 8091 JumpTarget end; |
| 8087 | 8092 |
| 8088 __ test(result.reg(), Immediate(kSmiTagMask)); | 8093 __ test(result.reg(), Immediate(kSmiTagMask)); |
| 8089 __ j(not_zero, &non_smi); | 8094 __ j(not_zero, &non_smi); |
| 8090 __ SmiUntag(result.reg()); | 8095 __ SmiUntag(result.reg()); |
| 8091 __ cvtsi2sd(xmm0, Operand(result.reg())); | 8096 __ cvtsi2sd(xmm0, Operand(result.reg())); |
| 8092 __ jmp(&load_done); | 8097 __ jmp(&load_done); |
| 8093 __ bind(&non_smi); | 8098 __ bind(&non_smi); |
| 8094 __ cmp(FieldOperand(result.reg(), HeapObject::kMapOffset), | 8099 __ cmp(FieldOperand(result.reg(), HeapObject::kMapOffset), |
| 8095 Factory::heap_number_map()); | 8100 FACTORY->heap_number_map()); |
| 8096 __ j(not_equal, &runtime); | 8101 __ j(not_equal, &runtime); |
| 8097 __ movdbl(xmm0, FieldOperand(result.reg(), HeapNumber::kValueOffset)); | 8102 __ movdbl(xmm0, FieldOperand(result.reg(), HeapNumber::kValueOffset)); |
| 8098 | 8103 |
| 8099 __ bind(&load_done); | 8104 __ bind(&load_done); |
| 8100 __ sqrtsd(xmm0, xmm0); | 8105 __ sqrtsd(xmm0, xmm0); |
| 8101 // A copy of the virtual frame to allow us to go to runtime after the | 8106 // A copy of the virtual frame to allow us to go to runtime after the |
| 8102 // JumpTarget jump. | 8107 // JumpTarget jump. |
| 8103 Result scratch = allocator()->Allocate(); | 8108 Result scratch = allocator()->Allocate(); |
| 8104 VirtualFrame* clone = new VirtualFrame(frame()); | 8109 VirtualFrame* clone = new VirtualFrame(frame()); |
| 8105 __ AllocateHeapNumber(result.reg(), scratch.reg(), no_reg, &runtime); | 8110 __ AllocateHeapNumber(result.reg(), scratch.reg(), no_reg, &runtime); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8191 | 8196 |
| 8192 | 8197 |
| 8193 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 8198 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 8194 ASSERT(!in_safe_int32_mode()); | 8199 ASSERT(!in_safe_int32_mode()); |
| 8195 if (CheckForInlineRuntimeCall(node)) { | 8200 if (CheckForInlineRuntimeCall(node)) { |
| 8196 return; | 8201 return; |
| 8197 } | 8202 } |
| 8198 | 8203 |
| 8199 ZoneList<Expression*>* args = node->arguments(); | 8204 ZoneList<Expression*>* args = node->arguments(); |
| 8200 Comment cmnt(masm_, "[ CallRuntime"); | 8205 Comment cmnt(masm_, "[ CallRuntime"); |
| 8201 Runtime::Function* function = node->function(); | 8206 const Runtime::Function* function = node->function(); |
| 8202 | 8207 |
| 8203 if (function == NULL) { | 8208 if (function == NULL) { |
| 8204 // Push the builtins object found in the current global object. | 8209 // Push the builtins object found in the current global object. |
| 8205 Result temp = allocator()->Allocate(); | 8210 Result temp = allocator()->Allocate(); |
| 8206 ASSERT(temp.is_valid()); | 8211 ASSERT(temp.is_valid()); |
| 8207 __ mov(temp.reg(), GlobalObjectOperand()); | 8212 __ mov(temp.reg(), GlobalObjectOperand()); |
| 8208 __ mov(temp.reg(), FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset)); | 8213 __ mov(temp.reg(), FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset)); |
| 8209 frame_->Push(&temp); | 8214 frame_->Push(&temp); |
| 8210 } | 8215 } |
| 8211 | 8216 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8274 // variable. Sync the virtual frame eagerly so we can push the | 8279 // variable. Sync the virtual frame eagerly so we can push the |
| 8275 // arguments directly into place. | 8280 // arguments directly into place. |
| 8276 frame_->SyncRange(0, frame_->element_count() - 1); | 8281 frame_->SyncRange(0, frame_->element_count() - 1); |
| 8277 frame_->EmitPush(esi); | 8282 frame_->EmitPush(esi); |
| 8278 frame_->EmitPush(Immediate(variable->name())); | 8283 frame_->EmitPush(Immediate(variable->name())); |
| 8279 Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); | 8284 Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); |
| 8280 frame_->Push(&answer); | 8285 frame_->Push(&answer); |
| 8281 } else { | 8286 } else { |
| 8282 // Default: Result of deleting non-global, not dynamically | 8287 // Default: Result of deleting non-global, not dynamically |
| 8283 // introduced variables is false. | 8288 // introduced variables is false. |
| 8284 frame_->Push(Factory::false_value()); | 8289 frame_->Push(FACTORY->false_value()); |
| 8285 } | 8290 } |
| 8286 } else { | 8291 } else { |
| 8287 // Default: Result of deleting expressions is true. | 8292 // Default: Result of deleting expressions is true. |
| 8288 Load(node->expression()); // may have side-effects | 8293 Load(node->expression()); // may have side-effects |
| 8289 frame_->SetElementAt(0, Factory::true_value()); | 8294 frame_->SetElementAt(0, FACTORY->true_value()); |
| 8290 } | 8295 } |
| 8291 | 8296 |
| 8292 } else if (op == Token::TYPEOF) { | 8297 } else if (op == Token::TYPEOF) { |
| 8293 // Special case for loading the typeof expression; see comment on | 8298 // Special case for loading the typeof expression; see comment on |
| 8294 // LoadTypeofExpression(). | 8299 // LoadTypeofExpression(). |
| 8295 LoadTypeofExpression(node->expression()); | 8300 LoadTypeofExpression(node->expression()); |
| 8296 Result answer = frame_->CallRuntime(Runtime::kTypeof, 1); | 8301 Result answer = frame_->CallRuntime(Runtime::kTypeof, 1); |
| 8297 frame_->Push(&answer); | 8302 frame_->Push(&answer); |
| 8298 | 8303 |
| 8299 } else if (op == Token::VOID) { | 8304 } else if (op == Token::VOID) { |
| 8300 Expression* expression = node->expression(); | 8305 Expression* expression = node->expression(); |
| 8301 if (expression && expression->AsLiteral() && ( | 8306 if (expression && expression->AsLiteral() && ( |
| 8302 expression->AsLiteral()->IsTrue() || | 8307 expression->AsLiteral()->IsTrue() || |
| 8303 expression->AsLiteral()->IsFalse() || | 8308 expression->AsLiteral()->IsFalse() || |
| 8304 expression->AsLiteral()->handle()->IsNumber() || | 8309 expression->AsLiteral()->handle()->IsNumber() || |
| 8305 expression->AsLiteral()->handle()->IsString() || | 8310 expression->AsLiteral()->handle()->IsString() || |
| 8306 expression->AsLiteral()->handle()->IsJSRegExp() || | 8311 expression->AsLiteral()->handle()->IsJSRegExp() || |
| 8307 expression->AsLiteral()->IsNull())) { | 8312 expression->AsLiteral()->IsNull())) { |
| 8308 // Omit evaluating the value of the primitive literal. | 8313 // Omit evaluating the value of the primitive literal. |
| 8309 // It will be discarded anyway, and can have no side effect. | 8314 // It will be discarded anyway, and can have no side effect. |
| 8310 frame_->Push(Factory::undefined_value()); | 8315 frame_->Push(FACTORY->undefined_value()); |
| 8311 } else { | 8316 } else { |
| 8312 Load(node->expression()); | 8317 Load(node->expression()); |
| 8313 frame_->SetElementAt(0, Factory::undefined_value()); | 8318 frame_->SetElementAt(0, FACTORY->undefined_value()); |
| 8314 } | 8319 } |
| 8315 | 8320 |
| 8316 } else { | 8321 } else { |
| 8317 if (in_safe_int32_mode()) { | 8322 if (in_safe_int32_mode()) { |
| 8318 Visit(node->expression()); | 8323 Visit(node->expression()); |
| 8319 Result value = frame_->Pop(); | 8324 Result value = frame_->Pop(); |
| 8320 ASSERT(value.is_untagged_int32()); | 8325 ASSERT(value.is_untagged_int32()); |
| 8321 // Registers containing an int32 value are not multiply used. | 8326 // Registers containing an int32 value are not multiply used. |
| 8322 ASSERT(!value.is_register() || !frame_->is_used(value.reg())); | 8327 ASSERT(!value.is_register() || !frame_->is_used(value.reg())); |
| 8323 value.ToRegister(); | 8328 value.ToRegister(); |
| (...skipping 781 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9105 (operation != NULL && operation->op() == Token::TYPEOF) && | 9110 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 9106 (right->AsLiteral() != NULL && | 9111 (right->AsLiteral() != NULL && |
| 9107 right->AsLiteral()->handle()->IsString())) { | 9112 right->AsLiteral()->handle()->IsString())) { |
| 9108 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 9113 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 9109 | 9114 |
| 9110 // Load the operand and move it to a register. | 9115 // Load the operand and move it to a register. |
| 9111 LoadTypeofExpression(operation->expression()); | 9116 LoadTypeofExpression(operation->expression()); |
| 9112 Result answer = frame_->Pop(); | 9117 Result answer = frame_->Pop(); |
| 9113 answer.ToRegister(); | 9118 answer.ToRegister(); |
| 9114 | 9119 |
| 9115 if (check->Equals(Heap::number_symbol())) { | 9120 if (check->Equals(HEAP->number_symbol())) { |
| 9116 __ test(answer.reg(), Immediate(kSmiTagMask)); | 9121 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 9117 destination()->true_target()->Branch(zero); | 9122 destination()->true_target()->Branch(zero); |
| 9118 frame_->Spill(answer.reg()); | 9123 frame_->Spill(answer.reg()); |
| 9119 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 9124 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
| 9120 __ cmp(answer.reg(), Factory::heap_number_map()); | 9125 __ cmp(answer.reg(), FACTORY->heap_number_map()); |
| 9121 answer.Unuse(); | 9126 answer.Unuse(); |
| 9122 destination()->Split(equal); | 9127 destination()->Split(equal); |
| 9123 | 9128 |
| 9124 } else if (check->Equals(Heap::string_symbol())) { | 9129 } else if (check->Equals(HEAP->string_symbol())) { |
| 9125 __ test(answer.reg(), Immediate(kSmiTagMask)); | 9130 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 9126 destination()->false_target()->Branch(zero); | 9131 destination()->false_target()->Branch(zero); |
| 9127 | 9132 |
| 9128 // It can be an undetectable string object. | 9133 // It can be an undetectable string object. |
| 9129 Result temp = allocator()->Allocate(); | 9134 Result temp = allocator()->Allocate(); |
| 9130 ASSERT(temp.is_valid()); | 9135 ASSERT(temp.is_valid()); |
| 9131 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 9136 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
| 9132 __ test_b(FieldOperand(temp.reg(), Map::kBitFieldOffset), | 9137 __ test_b(FieldOperand(temp.reg(), Map::kBitFieldOffset), |
| 9133 1 << Map::kIsUndetectable); | 9138 1 << Map::kIsUndetectable); |
| 9134 destination()->false_target()->Branch(not_zero); | 9139 destination()->false_target()->Branch(not_zero); |
| 9135 __ CmpInstanceType(temp.reg(), FIRST_NONSTRING_TYPE); | 9140 __ CmpInstanceType(temp.reg(), FIRST_NONSTRING_TYPE); |
| 9136 temp.Unuse(); | 9141 temp.Unuse(); |
| 9137 answer.Unuse(); | 9142 answer.Unuse(); |
| 9138 destination()->Split(below); | 9143 destination()->Split(below); |
| 9139 | 9144 |
| 9140 } else if (check->Equals(Heap::boolean_symbol())) { | 9145 } else if (check->Equals(HEAP->boolean_symbol())) { |
| 9141 __ cmp(answer.reg(), Factory::true_value()); | 9146 __ cmp(answer.reg(), FACTORY->true_value()); |
| 9142 destination()->true_target()->Branch(equal); | 9147 destination()->true_target()->Branch(equal); |
| 9143 __ cmp(answer.reg(), Factory::false_value()); | 9148 __ cmp(answer.reg(), FACTORY->false_value()); |
| 9144 answer.Unuse(); | 9149 answer.Unuse(); |
| 9145 destination()->Split(equal); | 9150 destination()->Split(equal); |
| 9146 | 9151 |
| 9147 } else if (check->Equals(Heap::undefined_symbol())) { | 9152 } else if (check->Equals(HEAP->undefined_symbol())) { |
| 9148 __ cmp(answer.reg(), Factory::undefined_value()); | 9153 __ cmp(answer.reg(), FACTORY->undefined_value()); |
| 9149 destination()->true_target()->Branch(equal); | 9154 destination()->true_target()->Branch(equal); |
| 9150 | 9155 |
| 9151 __ test(answer.reg(), Immediate(kSmiTagMask)); | 9156 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 9152 destination()->false_target()->Branch(zero); | 9157 destination()->false_target()->Branch(zero); |
| 9153 | 9158 |
| 9154 // It can be an undetectable object. | 9159 // It can be an undetectable object. |
| 9155 frame_->Spill(answer.reg()); | 9160 frame_->Spill(answer.reg()); |
| 9156 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 9161 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
| 9157 __ test_b(FieldOperand(answer.reg(), Map::kBitFieldOffset), | 9162 __ test_b(FieldOperand(answer.reg(), Map::kBitFieldOffset), |
| 9158 1 << Map::kIsUndetectable); | 9163 1 << Map::kIsUndetectable); |
| 9159 answer.Unuse(); | 9164 answer.Unuse(); |
| 9160 destination()->Split(not_zero); | 9165 destination()->Split(not_zero); |
| 9161 | 9166 |
| 9162 } else if (check->Equals(Heap::function_symbol())) { | 9167 } else if (check->Equals(HEAP->function_symbol())) { |
| 9163 __ test(answer.reg(), Immediate(kSmiTagMask)); | 9168 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 9164 destination()->false_target()->Branch(zero); | 9169 destination()->false_target()->Branch(zero); |
| 9165 frame_->Spill(answer.reg()); | 9170 frame_->Spill(answer.reg()); |
| 9166 __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); | 9171 __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); |
| 9167 destination()->true_target()->Branch(equal); | 9172 destination()->true_target()->Branch(equal); |
| 9168 // Regular expressions are callable so typeof == 'function'. | 9173 // Regular expressions are callable so typeof == 'function'. |
| 9169 __ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE); | 9174 __ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE); |
| 9170 answer.Unuse(); | 9175 answer.Unuse(); |
| 9171 destination()->Split(equal); | 9176 destination()->Split(equal); |
| 9172 } else if (check->Equals(Heap::object_symbol())) { | 9177 } else if (check->Equals(HEAP->object_symbol())) { |
| 9173 __ test(answer.reg(), Immediate(kSmiTagMask)); | 9178 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 9174 destination()->false_target()->Branch(zero); | 9179 destination()->false_target()->Branch(zero); |
| 9175 __ cmp(answer.reg(), Factory::null_value()); | 9180 __ cmp(answer.reg(), FACTORY->null_value()); |
| 9176 destination()->true_target()->Branch(equal); | 9181 destination()->true_target()->Branch(equal); |
| 9177 | 9182 |
| 9178 Result map = allocator()->Allocate(); | 9183 Result map = allocator()->Allocate(); |
| 9179 ASSERT(map.is_valid()); | 9184 ASSERT(map.is_valid()); |
| 9180 // Regular expressions are typeof == 'function', not 'object'. | 9185 // Regular expressions are typeof == 'function', not 'object'. |
| 9181 __ CmpObjectType(answer.reg(), JS_REGEXP_TYPE, map.reg()); | 9186 __ CmpObjectType(answer.reg(), JS_REGEXP_TYPE, map.reg()); |
| 9182 destination()->false_target()->Branch(equal); | 9187 destination()->false_target()->Branch(equal); |
| 9183 | 9188 |
| 9184 // It can be an undetectable object. | 9189 // It can be an undetectable object. |
| 9185 __ test_b(FieldOperand(map.reg(), Map::kBitFieldOffset), | 9190 __ test_b(FieldOperand(map.reg(), Map::kBitFieldOffset), |
| (...skipping 22 matching lines...) Expand all Loading... |
| 9208 if (check->value() == 2147483648.0) { // 0x80000000. | 9213 if (check->value() == 2147483648.0) { // 0x80000000. |
| 9209 Load(left); | 9214 Load(left); |
| 9210 left_already_loaded = true; | 9215 left_already_loaded = true; |
| 9211 Result lhs = frame_->Pop(); | 9216 Result lhs = frame_->Pop(); |
| 9212 lhs.ToRegister(); | 9217 lhs.ToRegister(); |
| 9213 __ test(lhs.reg(), Immediate(kSmiTagMask)); | 9218 __ test(lhs.reg(), Immediate(kSmiTagMask)); |
| 9214 destination()->true_target()->Branch(zero); // All Smis are less. | 9219 destination()->true_target()->Branch(zero); // All Smis are less. |
| 9215 Result scratch = allocator()->Allocate(); | 9220 Result scratch = allocator()->Allocate(); |
| 9216 ASSERT(scratch.is_valid()); | 9221 ASSERT(scratch.is_valid()); |
| 9217 __ mov(scratch.reg(), FieldOperand(lhs.reg(), HeapObject::kMapOffset)); | 9222 __ mov(scratch.reg(), FieldOperand(lhs.reg(), HeapObject::kMapOffset)); |
| 9218 __ cmp(scratch.reg(), Factory::heap_number_map()); | 9223 __ cmp(scratch.reg(), FACTORY->heap_number_map()); |
| 9219 JumpTarget not_a_number; | 9224 JumpTarget not_a_number; |
| 9220 not_a_number.Branch(not_equal, &lhs); | 9225 not_a_number.Branch(not_equal, &lhs); |
| 9221 __ mov(scratch.reg(), | 9226 __ mov(scratch.reg(), |
| 9222 FieldOperand(lhs.reg(), HeapNumber::kExponentOffset)); | 9227 FieldOperand(lhs.reg(), HeapNumber::kExponentOffset)); |
| 9223 __ cmp(Operand(scratch.reg()), Immediate(0xfff00000)); | 9228 __ cmp(Operand(scratch.reg()), Immediate(0xfff00000)); |
| 9224 not_a_number.Branch(above_equal, &lhs); // It's a negative NaN or -Inf. | 9229 not_a_number.Branch(above_equal, &lhs); // It's a negative NaN or -Inf. |
| 9225 const uint32_t borderline_exponent = | 9230 const uint32_t borderline_exponent = |
| 9226 (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; | 9231 (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; |
| 9227 __ cmp(Operand(scratch.reg()), Immediate(borderline_exponent)); | 9232 __ cmp(Operand(scratch.reg()), Immediate(borderline_exponent)); |
| 9228 scratch.Unuse(); | 9233 scratch.Unuse(); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9295 } | 9300 } |
| 9296 | 9301 |
| 9297 | 9302 |
| 9298 void CodeGenerator::VisitCompareToNull(CompareToNull* node) { | 9303 void CodeGenerator::VisitCompareToNull(CompareToNull* node) { |
| 9299 ASSERT(!in_safe_int32_mode()); | 9304 ASSERT(!in_safe_int32_mode()); |
| 9300 Comment cmnt(masm_, "[ CompareToNull"); | 9305 Comment cmnt(masm_, "[ CompareToNull"); |
| 9301 | 9306 |
| 9302 Load(node->expression()); | 9307 Load(node->expression()); |
| 9303 Result operand = frame_->Pop(); | 9308 Result operand = frame_->Pop(); |
| 9304 operand.ToRegister(); | 9309 operand.ToRegister(); |
| 9305 __ cmp(operand.reg(), Factory::null_value()); | 9310 __ cmp(operand.reg(), FACTORY->null_value()); |
| 9306 if (node->is_strict()) { | 9311 if (node->is_strict()) { |
| 9307 operand.Unuse(); | 9312 operand.Unuse(); |
| 9308 destination()->Split(equal); | 9313 destination()->Split(equal); |
| 9309 } else { | 9314 } else { |
| 9310 // The 'null' value is only equal to 'undefined' if using non-strict | 9315 // The 'null' value is only equal to 'undefined' if using non-strict |
| 9311 // comparisons. | 9316 // comparisons. |
| 9312 destination()->true_target()->Branch(equal); | 9317 destination()->true_target()->Branch(equal); |
| 9313 __ cmp(operand.reg(), Factory::undefined_value()); | 9318 __ cmp(operand.reg(), FACTORY->undefined_value()); |
| 9314 destination()->true_target()->Branch(equal); | 9319 destination()->true_target()->Branch(equal); |
| 9315 __ test(operand.reg(), Immediate(kSmiTagMask)); | 9320 __ test(operand.reg(), Immediate(kSmiTagMask)); |
| 9316 destination()->false_target()->Branch(equal); | 9321 destination()->false_target()->Branch(equal); |
| 9317 | 9322 |
| 9318 // It can be an undetectable object. | 9323 // It can be an undetectable object. |
| 9319 // Use a scratch register in preference to spilling operand.reg(). | 9324 // Use a scratch register in preference to spilling operand.reg(). |
| 9320 Result temp = allocator()->Allocate(); | 9325 Result temp = allocator()->Allocate(); |
| 9321 ASSERT(temp.is_valid()); | 9326 ASSERT(temp.is_valid()); |
| 9322 __ mov(temp.reg(), | 9327 __ mov(temp.reg(), |
| 9323 FieldOperand(operand.reg(), HeapObject::kMapOffset)); | 9328 FieldOperand(operand.reg(), HeapObject::kMapOffset)); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9376 bool is_contextual_; | 9381 bool is_contextual_; |
| 9377 bool is_dont_delete_; | 9382 bool is_dont_delete_; |
| 9378 }; | 9383 }; |
| 9379 | 9384 |
| 9380 | 9385 |
| 9381 void DeferredReferenceGetNamedValue::Generate() { | 9386 void DeferredReferenceGetNamedValue::Generate() { |
| 9382 if (!receiver_.is(eax)) { | 9387 if (!receiver_.is(eax)) { |
| 9383 __ mov(eax, receiver_); | 9388 __ mov(eax, receiver_); |
| 9384 } | 9389 } |
| 9385 __ Set(ecx, Immediate(name_)); | 9390 __ Set(ecx, Immediate(name_)); |
| 9386 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 9391 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 9392 Builtins::LoadIC_Initialize)); |
| 9387 RelocInfo::Mode mode = is_contextual_ | 9393 RelocInfo::Mode mode = is_contextual_ |
| 9388 ? RelocInfo::CODE_TARGET_CONTEXT | 9394 ? RelocInfo::CODE_TARGET_CONTEXT |
| 9389 : RelocInfo::CODE_TARGET; | 9395 : RelocInfo::CODE_TARGET; |
| 9390 __ call(ic, mode); | 9396 __ call(ic, mode); |
| 9391 // The call must be followed by: | 9397 // The call must be followed by: |
| 9392 // - a test eax instruction to indicate that the inobject property | 9398 // - a test eax instruction to indicate that the inobject property |
| 9393 // case was inlined. | 9399 // case was inlined. |
| 9394 // - a mov ecx or mov edx instruction to indicate that the | 9400 // - a mov ecx or mov edx instruction to indicate that the |
| 9395 // contextual property load was inlined. | 9401 // contextual property load was inlined. |
| 9396 // | 9402 // |
| 9397 // Store the delta to the map check instruction here in the test | 9403 // Store the delta to the map check instruction here in the test |
| 9398 // instruction. Use masm_-> instead of the __ macro since the | 9404 // instruction. Use masm_-> instead of the __ macro since the |
| 9399 // latter can't return a value. | 9405 // latter can't return a value. |
| 9400 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 9406 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
| 9401 // Here we use masm_-> instead of the __ macro because this is the | 9407 // Here we use masm_-> instead of the __ macro because this is the |
| 9402 // instruction that gets patched and coverage code gets in the way. | 9408 // instruction that gets patched and coverage code gets in the way. |
| 9403 if (is_contextual_) { | 9409 if (is_contextual_) { |
| 9404 masm_->mov(is_dont_delete_ ? edx : ecx, -delta_to_patch_site); | 9410 masm_->mov(is_dont_delete_ ? edx : ecx, -delta_to_patch_site); |
| 9405 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1); | 9411 __ IncrementCounter(COUNTERS->named_load_global_inline_miss(), 1); |
| 9406 if (is_dont_delete_) { | 9412 if (is_dont_delete_) { |
| 9407 __ IncrementCounter(&Counters::dont_delete_hint_miss, 1); | 9413 __ IncrementCounter(COUNTERS->dont_delete_hint_miss(), 1); |
| 9408 } | 9414 } |
| 9409 } else { | 9415 } else { |
| 9410 masm_->test(eax, Immediate(-delta_to_patch_site)); | 9416 masm_->test(eax, Immediate(-delta_to_patch_site)); |
| 9411 __ IncrementCounter(&Counters::named_load_inline_miss, 1); | 9417 __ IncrementCounter(COUNTERS->named_load_inline_miss(), 1); |
| 9412 } | 9418 } |
| 9413 | 9419 |
| 9414 if (!dst_.is(eax)) __ mov(dst_, eax); | 9420 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 9415 } | 9421 } |
| 9416 | 9422 |
| 9417 | 9423 |
| 9418 class DeferredReferenceGetKeyedValue: public DeferredCode { | 9424 class DeferredReferenceGetKeyedValue: public DeferredCode { |
| 9419 public: | 9425 public: |
| 9420 explicit DeferredReferenceGetKeyedValue(Register dst, | 9426 explicit DeferredReferenceGetKeyedValue(Register dst, |
| 9421 Register receiver, | 9427 Register receiver, |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9455 } | 9461 } |
| 9456 } else { | 9462 } else { |
| 9457 __ xchg(edx, eax); | 9463 __ xchg(edx, eax); |
| 9458 } | 9464 } |
| 9459 // Calculate the delta from the IC call instruction to the map check | 9465 // Calculate the delta from the IC call instruction to the map check |
| 9460 // cmp instruction in the inlined version. This delta is stored in | 9466 // cmp instruction in the inlined version. This delta is stored in |
| 9461 // a test(eax, delta) instruction after the call so that we can find | 9467 // a test(eax, delta) instruction after the call so that we can find |
| 9462 // it in the IC initialization code and patch the cmp instruction. | 9468 // it in the IC initialization code and patch the cmp instruction. |
| 9463 // This means that we cannot allow test instructions after calls to | 9469 // This means that we cannot allow test instructions after calls to |
| 9464 // KeyedLoadIC stubs in other places. | 9470 // KeyedLoadIC stubs in other places. |
| 9465 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 9471 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 9472 Builtins::KeyedLoadIC_Initialize)); |
| 9466 __ call(ic, RelocInfo::CODE_TARGET); | 9473 __ call(ic, RelocInfo::CODE_TARGET); |
| 9467 // The delta from the start of the map-compare instruction to the | 9474 // The delta from the start of the map-compare instruction to the |
| 9468 // test instruction. We use masm_-> directly here instead of the __ | 9475 // test instruction. We use masm_-> directly here instead of the __ |
| 9469 // macro because the macro sometimes uses macro expansion to turn | 9476 // macro because the macro sometimes uses macro expansion to turn |
| 9470 // into something that can't return a value. This is encountered | 9477 // into something that can't return a value. This is encountered |
| 9471 // when doing generated code coverage tests. | 9478 // when doing generated code coverage tests. |
| 9472 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 9479 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
| 9473 // Here we use masm_-> instead of the __ macro because this is the | 9480 // Here we use masm_-> instead of the __ macro because this is the |
| 9474 // instruction that gets patched and coverage code gets in the way. | 9481 // instruction that gets patched and coverage code gets in the way. |
| 9475 masm_->test(eax, Immediate(-delta_to_patch_site)); | 9482 masm_->test(eax, Immediate(-delta_to_patch_site)); |
| 9476 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); | 9483 __ IncrementCounter(COUNTERS->keyed_load_inline_miss(), 1); |
| 9477 | 9484 |
| 9478 if (!dst_.is(eax)) __ mov(dst_, eax); | 9485 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 9479 } | 9486 } |
| 9480 | 9487 |
| 9481 | 9488 |
| 9482 class DeferredReferenceSetKeyedValue: public DeferredCode { | 9489 class DeferredReferenceSetKeyedValue: public DeferredCode { |
| 9483 public: | 9490 public: |
| 9484 DeferredReferenceSetKeyedValue(Register value, | 9491 DeferredReferenceSetKeyedValue(Register value, |
| 9485 Register key, | 9492 Register key, |
| 9486 Register receiver, | 9493 Register receiver, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 9502 Register value_; | 9509 Register value_; |
| 9503 Register key_; | 9510 Register key_; |
| 9504 Register receiver_; | 9511 Register receiver_; |
| 9505 Register scratch_; | 9512 Register scratch_; |
| 9506 Label patch_site_; | 9513 Label patch_site_; |
| 9507 StrictModeFlag strict_mode_; | 9514 StrictModeFlag strict_mode_; |
| 9508 }; | 9515 }; |
| 9509 | 9516 |
| 9510 | 9517 |
| 9511 void DeferredReferenceSetKeyedValue::Generate() { | 9518 void DeferredReferenceSetKeyedValue::Generate() { |
| 9512 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); | 9519 __ IncrementCounter(COUNTERS->keyed_store_inline_miss(), 1); |
| 9513 // Move value_ to eax, key_ to ecx, and receiver_ to edx. | 9520 // Move value_ to eax, key_ to ecx, and receiver_ to edx. |
| 9514 Register old_value = value_; | 9521 Register old_value = value_; |
| 9515 | 9522 |
| 9516 // First, move value to eax. | 9523 // First, move value to eax. |
| 9517 if (!value_.is(eax)) { | 9524 if (!value_.is(eax)) { |
| 9518 if (key_.is(eax)) { | 9525 if (key_.is(eax)) { |
| 9519 // Move key_ out of eax, preferably to ecx. | 9526 // Move key_ out of eax, preferably to ecx. |
| 9520 if (!value_.is(ecx) && !receiver_.is(ecx)) { | 9527 if (!value_.is(ecx) && !receiver_.is(ecx)) { |
| 9521 __ mov(ecx, key_); | 9528 __ mov(ecx, key_); |
| 9522 key_ = ecx; | 9529 key_ = ecx; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9556 } | 9563 } |
| 9557 } | 9564 } |
| 9558 } else { // Key is not in edx or ecx. | 9565 } else { // Key is not in edx or ecx. |
| 9559 if (!receiver_.is(edx)) { | 9566 if (!receiver_.is(edx)) { |
| 9560 __ mov(edx, receiver_); | 9567 __ mov(edx, receiver_); |
| 9561 } | 9568 } |
| 9562 __ mov(ecx, key_); | 9569 __ mov(ecx, key_); |
| 9563 } | 9570 } |
| 9564 | 9571 |
| 9565 // Call the IC stub. | 9572 // Call the IC stub. |
| 9566 Handle<Code> ic(Builtins::builtin( | 9573 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 9567 (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict | 9574 (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict |
| 9568 : Builtins::KeyedStoreIC_Initialize)); | 9575 : Builtins::KeyedStoreIC_Initialize)); |
| 9569 __ call(ic, RelocInfo::CODE_TARGET); | 9576 __ call(ic, RelocInfo::CODE_TARGET); |
| 9570 // The delta from the start of the map-compare instruction to the | 9577 // The delta from the start of the map-compare instruction to the |
| 9571 // test instruction. We use masm_-> directly here instead of the | 9578 // test instruction. We use masm_-> directly here instead of the |
| 9572 // __ macro because the macro sometimes uses macro expansion to turn | 9579 // __ macro because the macro sometimes uses macro expansion to turn |
| 9573 // into something that can't return a value. This is encountered | 9580 // into something that can't return a value. This is encountered |
| 9574 // when doing generated code coverage tests. | 9581 // when doing generated code coverage tests. |
| 9575 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 9582 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
| 9576 // Here we use masm_-> instead of the __ macro because this is the | 9583 // Here we use masm_-> instead of the __ macro because this is the |
| 9577 // instruction that gets patched and coverage code gets in the way. | 9584 // instruction that gets patched and coverage code gets in the way. |
| 9578 masm_->test(eax, Immediate(-delta_to_patch_site)); | 9585 masm_->test(eax, Immediate(-delta_to_patch_site)); |
| 9579 // Restore value (returned from store IC) register. | 9586 // Restore value (returned from store IC) register. |
| 9580 if (!old_value.is(eax)) __ mov(old_value, eax); | 9587 if (!old_value.is(eax)) __ mov(old_value, eax); |
| 9581 } | 9588 } |
| 9582 | 9589 |
| 9583 | 9590 |
| 9584 Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) { | 9591 Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) { |
| 9585 #ifdef DEBUG | 9592 #ifdef DEBUG |
| 9586 int original_height = frame()->height(); | 9593 int original_height = frame()->height(); |
| 9587 #endif | 9594 #endif |
| 9588 | 9595 |
| 9589 bool contextual_load_in_builtin = | 9596 bool contextual_load_in_builtin = |
| 9590 is_contextual && | 9597 is_contextual && |
| 9591 (Bootstrapper::IsActive() || | 9598 (Isolate::Current()->bootstrapper()->IsActive() || |
| 9592 (!info_->closure().is_null() && info_->closure()->IsBuiltin())); | 9599 (!info_->closure().is_null() && info_->closure()->IsBuiltin())); |
| 9593 | 9600 |
| 9594 Result result; | 9601 Result result; |
| 9595 // Do not inline in the global code or when not in loop. | 9602 // Do not inline in the global code or when not in loop. |
| 9596 if (scope()->is_global_scope() || | 9603 if (scope()->is_global_scope() || |
| 9597 loop_nesting() == 0 || | 9604 loop_nesting() == 0 || |
| 9598 contextual_load_in_builtin) { | 9605 contextual_load_in_builtin) { |
| 9599 Comment cmnt(masm(), "[ Load from named Property"); | 9606 Comment cmnt(masm(), "[ Load from named Property"); |
| 9600 frame()->Push(name); | 9607 frame()->Push(name); |
| 9601 | 9608 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 9627 // Check that the receiver is a heap object. | 9634 // Check that the receiver is a heap object. |
| 9628 __ test(receiver.reg(), Immediate(kSmiTagMask)); | 9635 __ test(receiver.reg(), Immediate(kSmiTagMask)); |
| 9629 deferred->Branch(zero); | 9636 deferred->Branch(zero); |
| 9630 } | 9637 } |
| 9631 | 9638 |
| 9632 __ bind(deferred->patch_site()); | 9639 __ bind(deferred->patch_site()); |
| 9633 // This is the map check instruction that will be patched (so we can't | 9640 // This is the map check instruction that will be patched (so we can't |
| 9634 // use the double underscore macro that may insert instructions). | 9641 // use the double underscore macro that may insert instructions). |
| 9635 // Initially use an invalid map to force a failure. | 9642 // Initially use an invalid map to force a failure. |
| 9636 masm()->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 9643 masm()->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
| 9637 Immediate(Factory::null_value())); | 9644 Immediate(FACTORY->null_value())); |
| 9638 // This branch is always a forwards branch so it's always a fixed size | 9645 // This branch is always a forwards branch so it's always a fixed size |
| 9639 // which allows the assert below to succeed and patching to work. | 9646 // which allows the assert below to succeed and patching to work. |
| 9640 deferred->Branch(not_equal); | 9647 deferred->Branch(not_equal); |
| 9641 | 9648 |
| 9642 // The delta from the patch label to the actual load must be | 9649 // The delta from the patch label to the actual load must be |
| 9643 // statically known. | 9650 // statically known. |
| 9644 ASSERT(masm()->SizeOfCodeGeneratedSince(deferred->patch_site()) == | 9651 ASSERT(masm()->SizeOfCodeGeneratedSince(deferred->patch_site()) == |
| 9645 LoadIC::kOffsetToLoadInstruction); | 9652 LoadIC::kOffsetToLoadInstruction); |
| 9646 | 9653 |
| 9647 if (is_contextual) { | 9654 if (is_contextual) { |
| 9648 // Load the (initialy invalid) cell and get its value. | 9655 // Load the (initialy invalid) cell and get its value. |
| 9649 masm()->mov(result.reg(), Factory::null_value()); | 9656 masm()->mov(result.reg(), FACTORY->null_value()); |
| 9650 if (FLAG_debug_code) { | 9657 if (FLAG_debug_code) { |
| 9651 __ cmp(FieldOperand(result.reg(), HeapObject::kMapOffset), | 9658 __ cmp(FieldOperand(result.reg(), HeapObject::kMapOffset), |
| 9652 Factory::global_property_cell_map()); | 9659 FACTORY->global_property_cell_map()); |
| 9653 __ Assert(equal, "Uninitialized inlined contextual load"); | 9660 __ Assert(equal, "Uninitialized inlined contextual load"); |
| 9654 } | 9661 } |
| 9655 __ mov(result.reg(), | 9662 __ mov(result.reg(), |
| 9656 FieldOperand(result.reg(), JSGlobalPropertyCell::kValueOffset)); | 9663 FieldOperand(result.reg(), JSGlobalPropertyCell::kValueOffset)); |
| 9664 __ cmp(result.reg(), FACTORY->the_hole_value()); |
| 9665 deferred->Branch(equal); |
| 9657 bool is_dont_delete = false; | 9666 bool is_dont_delete = false; |
| 9658 if (!info_->closure().is_null()) { | 9667 if (!info_->closure().is_null()) { |
| 9659 // When doing lazy compilation we can check if the global cell | 9668 // When doing lazy compilation we can check if the global cell |
| 9660 // already exists and use its "don't delete" status as a hint. | 9669 // already exists and use its "don't delete" status as a hint. |
| 9661 AssertNoAllocation no_gc; | 9670 AssertNoAllocation no_gc; |
| 9662 v8::internal::GlobalObject* global_object = | 9671 v8::internal::GlobalObject* global_object = |
| 9663 info_->closure()->context()->global(); | 9672 info_->closure()->context()->global(); |
| 9664 LookupResult lookup; | 9673 LookupResult lookup; |
| 9665 global_object->LocalLookupRealNamedProperty(*name, &lookup); | 9674 global_object->LocalLookupRealNamedProperty(*name, &lookup); |
| 9666 if (lookup.IsProperty() && lookup.type() == NORMAL) { | 9675 if (lookup.IsProperty() && lookup.type() == NORMAL) { |
| 9667 ASSERT(lookup.holder() == global_object); | 9676 ASSERT(lookup.holder() == global_object); |
| 9668 ASSERT(global_object->property_dictionary()->ValueAt( | 9677 ASSERT(global_object->property_dictionary()->ValueAt( |
| 9669 lookup.GetDictionaryEntry())->IsJSGlobalPropertyCell()); | 9678 lookup.GetDictionaryEntry())->IsJSGlobalPropertyCell()); |
| 9670 is_dont_delete = lookup.IsDontDelete(); | 9679 is_dont_delete = lookup.IsDontDelete(); |
| 9671 } | 9680 } |
| 9672 } | 9681 } |
| 9673 deferred->set_is_dont_delete(is_dont_delete); | 9682 deferred->set_is_dont_delete(is_dont_delete); |
| 9674 if (!is_dont_delete) { | 9683 if (!is_dont_delete) { |
| 9675 __ cmp(result.reg(), Factory::the_hole_value()); | 9684 __ cmp(result.reg(), FACTORY->the_hole_value()); |
| 9676 deferred->Branch(equal); | 9685 deferred->Branch(equal); |
| 9677 } else if (FLAG_debug_code) { | 9686 } else if (FLAG_debug_code) { |
| 9678 __ cmp(result.reg(), Factory::the_hole_value()); | 9687 __ cmp(result.reg(), FACTORY->the_hole_value()); |
| 9679 __ Check(not_equal, "DontDelete cells can't contain the hole"); | 9688 __ Check(not_equal, "DontDelete cells can't contain the hole"); |
| 9680 } | 9689 } |
| 9681 __ IncrementCounter(&Counters::named_load_global_inline, 1); | 9690 __ IncrementCounter(COUNTERS->named_load_global_inline(), 1); |
| 9682 if (is_dont_delete) { | 9691 if (is_dont_delete) { |
| 9683 __ IncrementCounter(&Counters::dont_delete_hint_hit, 1); | 9692 __ IncrementCounter(COUNTERS->dont_delete_hint_hit(), 1); |
| 9684 } | 9693 } |
| 9685 } else { | 9694 } else { |
| 9686 // The initial (invalid) offset has to be large enough to force a 32-bit | 9695 // The initial (invalid) offset has to be large enough to force a 32-bit |
| 9687 // instruction encoding to allow patching with an arbitrary offset. Use | 9696 // instruction encoding to allow patching with an arbitrary offset. Use |
| 9688 // kMaxInt (minus kHeapObjectTag). | 9697 // kMaxInt (minus kHeapObjectTag). |
| 9689 int offset = kMaxInt; | 9698 int offset = kMaxInt; |
| 9690 masm()->mov(result.reg(), FieldOperand(receiver.reg(), offset)); | 9699 masm()->mov(result.reg(), FieldOperand(receiver.reg(), offset)); |
| 9691 __ IncrementCounter(&Counters::named_load_inline, 1); | 9700 __ IncrementCounter(COUNTERS->named_load_inline(), 1); |
| 9692 } | 9701 } |
| 9693 | 9702 |
| 9694 deferred->BindExit(); | 9703 deferred->BindExit(); |
| 9695 } | 9704 } |
| 9696 ASSERT(frame()->height() == original_height - 1); | 9705 ASSERT(frame()->height() == original_height - 1); |
| 9697 return result; | 9706 return result; |
| 9698 } | 9707 } |
| 9699 | 9708 |
| 9700 | 9709 |
| 9701 Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) { | 9710 Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 9727 | 9736 |
| 9728 // Check that the receiver is a heap object. | 9737 // Check that the receiver is a heap object. |
| 9729 __ test(receiver.reg(), Immediate(kSmiTagMask)); | 9738 __ test(receiver.reg(), Immediate(kSmiTagMask)); |
| 9730 slow.Branch(zero, &value, &receiver); | 9739 slow.Branch(zero, &value, &receiver); |
| 9731 | 9740 |
| 9732 // This is the map check instruction that will be patched (so we can't | 9741 // This is the map check instruction that will be patched (so we can't |
| 9733 // use the double underscore macro that may insert instructions). | 9742 // use the double underscore macro that may insert instructions). |
| 9734 // Initially use an invalid map to force a failure. | 9743 // Initially use an invalid map to force a failure. |
| 9735 __ bind(&patch_site); | 9744 __ bind(&patch_site); |
| 9736 masm()->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 9745 masm()->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
| 9737 Immediate(Factory::null_value())); | 9746 Immediate(FACTORY->null_value())); |
| 9738 // This branch is always a forwards branch so it's always a fixed size | 9747 // This branch is always a forwards branch so it's always a fixed size |
| 9739 // which allows the assert below to succeed and patching to work. | 9748 // which allows the assert below to succeed and patching to work. |
| 9740 slow.Branch(not_equal, &value, &receiver); | 9749 slow.Branch(not_equal, &value, &receiver); |
| 9741 | 9750 |
| 9742 // The delta from the patch label to the store offset must be | 9751 // The delta from the patch label to the store offset must be |
| 9743 // statically known. | 9752 // statically known. |
| 9744 ASSERT(masm()->SizeOfCodeGeneratedSince(&patch_site) == | 9753 ASSERT(masm()->SizeOfCodeGeneratedSince(&patch_site) == |
| 9745 StoreIC::kOffsetToStoreInstruction); | 9754 StoreIC::kOffsetToStoreInstruction); |
| 9746 | 9755 |
| 9747 // The initial (invalid) offset has to be large enough to force a 32-bit | 9756 // The initial (invalid) offset has to be large enough to force a 32-bit |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9837 __ test(receiver.reg(), Immediate(kSmiTagMask)); | 9846 __ test(receiver.reg(), Immediate(kSmiTagMask)); |
| 9838 deferred->Branch(zero); | 9847 deferred->Branch(zero); |
| 9839 | 9848 |
| 9840 // Check that the receiver has the expected map. | 9849 // Check that the receiver has the expected map. |
| 9841 // Initially, use an invalid map. The map is patched in the IC | 9850 // Initially, use an invalid map. The map is patched in the IC |
| 9842 // initialization code. | 9851 // initialization code. |
| 9843 __ bind(deferred->patch_site()); | 9852 __ bind(deferred->patch_site()); |
| 9844 // Use masm-> here instead of the double underscore macro since extra | 9853 // Use masm-> here instead of the double underscore macro since extra |
| 9845 // coverage code can interfere with the patching. | 9854 // coverage code can interfere with the patching. |
| 9846 masm_->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 9855 masm_->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
| 9847 Immediate(Factory::null_value())); | 9856 Immediate(FACTORY->null_value())); |
| 9848 deferred->Branch(not_equal); | 9857 deferred->Branch(not_equal); |
| 9849 | 9858 |
| 9850 // Check that the key is a smi. | 9859 // Check that the key is a smi. |
| 9851 if (!key.is_smi()) { | 9860 if (!key.is_smi()) { |
| 9852 __ test(key.reg(), Immediate(kSmiTagMask)); | 9861 __ test(key.reg(), Immediate(kSmiTagMask)); |
| 9853 deferred->Branch(not_zero); | 9862 deferred->Branch(not_zero); |
| 9854 } else { | 9863 } else { |
| 9855 if (FLAG_debug_code) __ AbortIfNotSmi(key.reg()); | 9864 if (FLAG_debug_code) __ AbortIfNotSmi(key.reg()); |
| 9856 } | 9865 } |
| 9857 | 9866 |
| 9858 // Get the elements array from the receiver. | 9867 // Get the elements array from the receiver. |
| 9859 __ mov(elements.reg(), | 9868 __ mov(elements.reg(), |
| 9860 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); | 9869 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); |
| 9861 __ AssertFastElements(elements.reg()); | 9870 __ AssertFastElements(elements.reg()); |
| 9862 | 9871 |
| 9863 // Check that the key is within bounds. | 9872 // Check that the key is within bounds. |
| 9864 __ cmp(key.reg(), | 9873 __ cmp(key.reg(), |
| 9865 FieldOperand(elements.reg(), FixedArray::kLengthOffset)); | 9874 FieldOperand(elements.reg(), FixedArray::kLengthOffset)); |
| 9866 deferred->Branch(above_equal); | 9875 deferred->Branch(above_equal); |
| 9867 | 9876 |
| 9868 // Load and check that the result is not the hole. | 9877 // Load and check that the result is not the hole. |
| 9869 // Key holds a smi. | 9878 // Key holds a smi. |
| 9870 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 9879 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| 9871 __ mov(elements.reg(), | 9880 __ mov(elements.reg(), |
| 9872 FieldOperand(elements.reg(), | 9881 FieldOperand(elements.reg(), |
| 9873 key.reg(), | 9882 key.reg(), |
| 9874 times_2, | 9883 times_2, |
| 9875 FixedArray::kHeaderSize)); | 9884 FixedArray::kHeaderSize)); |
| 9876 result = elements; | 9885 result = elements; |
| 9877 __ cmp(Operand(result.reg()), Immediate(Factory::the_hole_value())); | 9886 __ cmp(Operand(result.reg()), Immediate(FACTORY->the_hole_value())); |
| 9878 deferred->Branch(equal); | 9887 deferred->Branch(equal); |
| 9879 __ IncrementCounter(&Counters::keyed_load_inline, 1); | 9888 __ IncrementCounter(COUNTERS->keyed_load_inline(), 1); |
| 9880 | 9889 |
| 9881 deferred->BindExit(); | 9890 deferred->BindExit(); |
| 9882 } else { | 9891 } else { |
| 9883 Comment cmnt(masm_, "[ Load from keyed Property"); | 9892 Comment cmnt(masm_, "[ Load from keyed Property"); |
| 9884 result = frame_->CallKeyedLoadIC(RelocInfo::CODE_TARGET); | 9893 result = frame_->CallKeyedLoadIC(RelocInfo::CODE_TARGET); |
| 9885 // Make sure that we do not have a test instruction after the | 9894 // Make sure that we do not have a test instruction after the |
| 9886 // call. A test instruction after the call is used to | 9895 // call. A test instruction after the call is used to |
| 9887 // indicate that we have generated an inline version of the | 9896 // indicate that we have generated an inline version of the |
| 9888 // keyed load. The explicit nop instruction is here because | 9897 // keyed load. The explicit nop instruction is here because |
| 9889 // the push that follows might be peep-hole optimized away. | 9898 // the push that follows might be peep-hole optimized away. |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9961 deferred->Branch(not_zero); | 9970 deferred->Branch(not_zero); |
| 9962 } | 9971 } |
| 9963 | 9972 |
| 9964 __ bind(&in_new_space); | 9973 __ bind(&in_new_space); |
| 9965 // Bind the deferred code patch site to be able to locate the fixed | 9974 // Bind the deferred code patch site to be able to locate the fixed |
| 9966 // array map comparison. When debugging, we patch this comparison to | 9975 // array map comparison. When debugging, we patch this comparison to |
| 9967 // always fail so that we will hit the IC call in the deferred code | 9976 // always fail so that we will hit the IC call in the deferred code |
| 9968 // which will allow the debugger to break for fast case stores. | 9977 // which will allow the debugger to break for fast case stores. |
| 9969 __ bind(deferred->patch_site()); | 9978 __ bind(deferred->patch_site()); |
| 9970 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), | 9979 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), |
| 9971 Immediate(Factory::fixed_array_map())); | 9980 Immediate(FACTORY->fixed_array_map())); |
| 9972 deferred->Branch(not_equal); | 9981 deferred->Branch(not_equal); |
| 9973 | 9982 |
| 9974 // Check that the key is within bounds. Both the key and the length of | 9983 // Check that the key is within bounds. Both the key and the length of |
| 9975 // the JSArray are smis (because the fixed array check above ensures the | 9984 // the JSArray are smis (because the fixed array check above ensures the |
| 9976 // elements are in fast case). Use unsigned comparison to handle negative | 9985 // elements are in fast case). Use unsigned comparison to handle negative |
| 9977 // keys. | 9986 // keys. |
| 9978 __ cmp(key.reg(), | 9987 __ cmp(key.reg(), |
| 9979 FieldOperand(receiver.reg(), JSArray::kLengthOffset)); | 9988 FieldOperand(receiver.reg(), JSArray::kLengthOffset)); |
| 9980 deferred->Branch(above_equal); | 9989 deferred->Branch(above_equal); |
| 9981 | 9990 |
| 9982 // Store the value. | 9991 // Store the value. |
| 9983 __ mov(FixedArrayElementOperand(tmp.reg(), key.reg()), result.reg()); | 9992 __ mov(FixedArrayElementOperand(tmp.reg(), key.reg()), result.reg()); |
| 9984 __ IncrementCounter(&Counters::keyed_store_inline, 1); | 9993 __ IncrementCounter(COUNTERS->keyed_store_inline(), 1); |
| 9985 | 9994 |
| 9986 deferred->BindExit(); | 9995 deferred->BindExit(); |
| 9987 } else { | 9996 } else { |
| 9988 result = frame()->CallKeyedStoreIC(strict_mode_flag()); | 9997 result = frame()->CallKeyedStoreIC(strict_mode_flag()); |
| 9989 // Make sure that we do not have a test instruction after the | 9998 // Make sure that we do not have a test instruction after the |
| 9990 // call. A test instruction after the call is used to | 9999 // call. A test instruction after the call is used to |
| 9991 // indicate that we have generated an inline version of the | 10000 // indicate that we have generated an inline version of the |
| 9992 // keyed store. | 10001 // keyed store. |
| 9993 __ nop(); | 10002 __ nop(); |
| 9994 } | 10003 } |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10177 int stack_offset = 0; // Update if we change the stack height. | 10186 int stack_offset = 0; // Update if we change the stack height. |
| 10178 | 10187 |
| 10179 if (FLAG_debug_code) { | 10188 if (FLAG_debug_code) { |
| 10180 __ cmp(Operand(esp, kSizeOffset + stack_offset), | 10189 __ cmp(Operand(esp, kSizeOffset + stack_offset), |
| 10181 Immediate(kMinComplexMemCopy)); | 10190 Immediate(kMinComplexMemCopy)); |
| 10182 Label ok; | 10191 Label ok; |
| 10183 __ j(greater_equal, &ok); | 10192 __ j(greater_equal, &ok); |
| 10184 __ int3(); | 10193 __ int3(); |
| 10185 __ bind(&ok); | 10194 __ bind(&ok); |
| 10186 } | 10195 } |
| 10187 if (CpuFeatures::IsSupported(SSE2)) { | 10196 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 10188 CpuFeatures::Scope enable(SSE2); | 10197 CpuFeatures::Scope enable(SSE2); |
| 10189 __ push(edi); | 10198 __ push(edi); |
| 10190 __ push(esi); | 10199 __ push(esi); |
| 10191 stack_offset += 2 * kPointerSize; | 10200 stack_offset += 2 * kPointerSize; |
| 10192 Register dst = edi; | 10201 Register dst = edi; |
| 10193 Register src = esi; | 10202 Register src = esi; |
| 10194 Register count = ecx; | 10203 Register count = ecx; |
| 10195 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset)); | 10204 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset)); |
| 10196 __ mov(src, Operand(esp, stack_offset + kSourceOffset)); | 10205 __ mov(src, Operand(esp, stack_offset + kSourceOffset)); |
| 10197 __ mov(count, Operand(esp, stack_offset + kSizeOffset)); | 10206 __ mov(count, Operand(esp, stack_offset + kSizeOffset)); |
| 10198 | 10207 |
| 10199 | 10208 |
| 10200 __ movdqu(xmm0, Operand(src, 0)); | 10209 __ movdqu(xmm0, Operand(src, 0)); |
| 10201 __ movdqu(Operand(dst, 0), xmm0); | 10210 __ movdqu(Operand(dst, 0), xmm0); |
| 10202 __ mov(edx, dst); | 10211 __ mov(edx, dst); |
| 10203 __ and_(edx, 0xF); | 10212 __ and_(edx, 0xF); |
| 10204 __ neg(edx); | 10213 __ neg(edx); |
| 10205 __ add(Operand(edx), Immediate(16)); | 10214 __ add(Operand(edx), Immediate(16)); |
| 10206 __ add(dst, Operand(edx)); | 10215 __ add(dst, Operand(edx)); |
| 10207 __ add(src, Operand(edx)); | 10216 __ add(src, Operand(edx)); |
| 10208 __ sub(Operand(count), edx); | 10217 __ sub(Operand(count), edx); |
| 10209 | 10218 |
| 10210 // edi is now aligned. Check if esi is also aligned. | 10219 // edi is now aligned. Check if esi is also aligned. |
| 10211 Label unaligned_source; | 10220 Label unaligned_source; |
| 10212 __ test(Operand(src), Immediate(0x0F)); | 10221 __ test(Operand(src), Immediate(0x0F)); |
| 10213 __ j(not_zero, &unaligned_source); | 10222 __ j(not_zero, &unaligned_source); |
| 10214 { | 10223 { |
| 10215 __ IncrementCounter(&Counters::memcopy_aligned, 1); | 10224 __ IncrementCounter(COUNTERS->memcopy_aligned(), 1); |
| 10216 // Copy loop for aligned source and destination. | 10225 // Copy loop for aligned source and destination. |
| 10217 __ mov(edx, count); | 10226 __ mov(edx, count); |
| 10218 Register loop_count = ecx; | 10227 Register loop_count = ecx; |
| 10219 Register count = edx; | 10228 Register count = edx; |
| 10220 __ shr(loop_count, 5); | 10229 __ shr(loop_count, 5); |
| 10221 { | 10230 { |
| 10222 // Main copy loop. | 10231 // Main copy loop. |
| 10223 Label loop; | 10232 Label loop; |
| 10224 __ bind(&loop); | 10233 __ bind(&loop); |
| 10225 __ prefetch(Operand(src, 0x20), 1); | 10234 __ prefetch(Operand(src, 0x20), 1); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 10253 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset)); | 10262 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset)); |
| 10254 __ pop(esi); | 10263 __ pop(esi); |
| 10255 __ pop(edi); | 10264 __ pop(edi); |
| 10256 __ ret(0); | 10265 __ ret(0); |
| 10257 } | 10266 } |
| 10258 __ Align(16); | 10267 __ Align(16); |
| 10259 { | 10268 { |
| 10260 // Copy loop for unaligned source and aligned destination. | 10269 // Copy loop for unaligned source and aligned destination. |
| 10261 // If source is not aligned, we can't read it as efficiently. | 10270 // If source is not aligned, we can't read it as efficiently. |
| 10262 __ bind(&unaligned_source); | 10271 __ bind(&unaligned_source); |
| 10263 __ IncrementCounter(&Counters::memcopy_unaligned, 1); | 10272 __ IncrementCounter(COUNTERS->memcopy_unaligned(), 1); |
| 10264 __ mov(edx, ecx); | 10273 __ mov(edx, ecx); |
| 10265 Register loop_count = ecx; | 10274 Register loop_count = ecx; |
| 10266 Register count = edx; | 10275 Register count = edx; |
| 10267 __ shr(loop_count, 5); | 10276 __ shr(loop_count, 5); |
| 10268 { | 10277 { |
| 10269 // Main copy loop | 10278 // Main copy loop |
| 10270 Label loop; | 10279 Label loop; |
| 10271 __ bind(&loop); | 10280 __ bind(&loop); |
| 10272 __ prefetch(Operand(src, 0x20), 1); | 10281 __ prefetch(Operand(src, 0x20), 1); |
| 10273 __ movdqu(xmm0, Operand(src, 0x00)); | 10282 __ movdqu(xmm0, Operand(src, 0x00)); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 10297 __ movdqu(xmm0, Operand(src, count, times_1, -0x10)); | 10306 __ movdqu(xmm0, Operand(src, count, times_1, -0x10)); |
| 10298 __ movdqu(Operand(dst, count, times_1, -0x10), xmm0); | 10307 __ movdqu(Operand(dst, count, times_1, -0x10), xmm0); |
| 10299 | 10308 |
| 10300 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset)); | 10309 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset)); |
| 10301 __ pop(esi); | 10310 __ pop(esi); |
| 10302 __ pop(edi); | 10311 __ pop(edi); |
| 10303 __ ret(0); | 10312 __ ret(0); |
| 10304 } | 10313 } |
| 10305 | 10314 |
| 10306 } else { | 10315 } else { |
| 10307 __ IncrementCounter(&Counters::memcopy_noxmm, 1); | 10316 __ IncrementCounter(COUNTERS->memcopy_noxmm(), 1); |
| 10308 // SSE2 not supported. Unlikely to happen in practice. | 10317 // SSE2 not supported. Unlikely to happen in practice. |
| 10309 __ push(edi); | 10318 __ push(edi); |
| 10310 __ push(esi); | 10319 __ push(esi); |
| 10311 stack_offset += 2 * kPointerSize; | 10320 stack_offset += 2 * kPointerSize; |
| 10312 __ cld(); | 10321 __ cld(); |
| 10313 Register dst = edi; | 10322 Register dst = edi; |
| 10314 Register src = esi; | 10323 Register src = esi; |
| 10315 Register count = ecx; | 10324 Register count = ecx; |
| 10316 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset)); | 10325 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset)); |
| 10317 __ mov(src, Operand(esp, stack_offset + kSourceOffset)); | 10326 __ mov(src, Operand(esp, stack_offset + kSourceOffset)); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10358 memcpy(chunk->GetStartAddress(), desc.buffer, desc.instr_size); | 10367 memcpy(chunk->GetStartAddress(), desc.buffer, desc.instr_size); |
| 10359 CPU::FlushICache(chunk->GetStartAddress(), desc.instr_size); | 10368 CPU::FlushICache(chunk->GetStartAddress(), desc.instr_size); |
| 10360 return FUNCTION_CAST<MemCopyFunction>(chunk->GetStartAddress()); | 10369 return FUNCTION_CAST<MemCopyFunction>(chunk->GetStartAddress()); |
| 10361 } | 10370 } |
| 10362 | 10371 |
| 10363 #undef __ | 10372 #undef __ |
| 10364 | 10373 |
| 10365 } } // namespace v8::internal | 10374 } } // namespace v8::internal |
| 10366 | 10375 |
| 10367 #endif // V8_TARGET_ARCH_IA32 | 10376 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |