| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 bool LCodeGen::GenerateCode() { | 70 bool LCodeGen::GenerateCode() { |
| 71 HPhase phase("Z_Code generation", chunk()); | 71 HPhase phase("Z_Code generation", chunk()); |
| 72 ASSERT(is_unused()); | 72 ASSERT(is_unused()); |
| 73 status_ = GENERATING; | 73 status_ = GENERATING; |
| 74 | 74 |
| 75 // Open a frame scope to indicate that there is a frame on the stack. The | 75 // Open a frame scope to indicate that there is a frame on the stack. The |
| 76 // MANUAL indicates that the scope shouldn't actually generate code to set up | 76 // MANUAL indicates that the scope shouldn't actually generate code to set up |
| 77 // the frame (that is done in GeneratePrologue). | 77 // the frame (that is done in GeneratePrologue). |
| 78 FrameScope frame_scope(masm_, StackFrame::MANUAL); | 78 FrameScope frame_scope(masm_, StackFrame::MANUAL); |
| 79 | 79 |
| 80 support_aligned_spilled_doubles_ = info()->IsOptimizing(); |
| 81 |
| 80 dynamic_frame_alignment_ = info()->IsOptimizing() && | 82 dynamic_frame_alignment_ = info()->IsOptimizing() && |
| 81 ((chunk()->num_double_slots() > 2 && | 83 ((chunk()->num_double_slots() > 2 && |
| 82 !chunk()->graph()->is_recursive()) || | 84 !chunk()->graph()->is_recursive()) || |
| 83 !info()->osr_ast_id().IsNone()); | 85 !info()->osr_ast_id().IsNone()); |
| 84 | 86 |
| 85 return GeneratePrologue() && | 87 return GeneratePrologue() && |
| 86 GenerateBody() && | 88 GenerateBody() && |
| 87 GenerateDeferredCode() && | 89 GenerateDeferredCode() && |
| 88 GenerateJumpTable() && | 90 GenerateJumpTable() && |
| 89 GenerateSafepointTable(); | 91 GenerateSafepointTable(); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 Label ok; | 148 Label ok; |
| 147 __ test(ecx, Operand(ecx)); | 149 __ test(ecx, Operand(ecx)); |
| 148 __ j(zero, &ok, Label::kNear); | 150 __ j(zero, &ok, Label::kNear); |
| 149 // +1 for return address. | 151 // +1 for return address. |
| 150 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; | 152 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; |
| 151 __ mov(Operand(esp, receiver_offset), | 153 __ mov(Operand(esp, receiver_offset), |
| 152 Immediate(isolate()->factory()->undefined_value())); | 154 Immediate(isolate()->factory()->undefined_value())); |
| 153 __ bind(&ok); | 155 __ bind(&ok); |
| 154 } | 156 } |
| 155 | 157 |
| 156 if (dynamic_frame_alignment_) { | 158 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) { |
| 157 // Move state of dynamic frame alignment into edx. | 159 // Move state of dynamic frame alignment into edx. |
| 158 __ mov(edx, Immediate(kNoAlignmentPadding)); | 160 __ mov(edx, Immediate(kNoAlignmentPadding)); |
| 159 | 161 |
| 160 Label do_not_pad, align_loop; | 162 Label do_not_pad, align_loop; |
| 161 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize); | 163 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize); |
| 162 // Align esp + 4 to a multiple of 2 * kPointerSize. | 164 // Align esp + 4 to a multiple of 2 * kPointerSize. |
| 163 __ test(esp, Immediate(kPointerSize)); | 165 __ test(esp, Immediate(kPointerSize)); |
| 164 __ j(not_zero, &do_not_pad, Label::kNear); | 166 __ j(not_zero, &do_not_pad, Label::kNear); |
| 165 __ push(Immediate(0)); | 167 __ push(Immediate(0)); |
| 166 __ mov(ebx, esp); | 168 __ mov(ebx, esp); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 ASSERT(slots != 0 || !info()->IsOptimizing()); | 207 ASSERT(slots != 0 || !info()->IsOptimizing()); |
| 206 if (slots > 0) { | 208 if (slots > 0) { |
| 207 if (slots == 1) { | 209 if (slots == 1) { |
| 208 if (dynamic_frame_alignment_) { | 210 if (dynamic_frame_alignment_) { |
| 209 __ push(edx); | 211 __ push(edx); |
| 210 } else { | 212 } else { |
| 211 __ push(Immediate(kNoAlignmentPadding)); | 213 __ push(Immediate(kNoAlignmentPadding)); |
| 212 } | 214 } |
| 213 } else { | 215 } else { |
| 214 if (FLAG_debug_code) { | 216 if (FLAG_debug_code) { |
| 217 __ sub(Operand(esp), Immediate(slots * kPointerSize)); |
| 218 __ push(eax); |
| 215 __ mov(Operand(eax), Immediate(slots)); | 219 __ mov(Operand(eax), Immediate(slots)); |
| 216 Label loop; | 220 Label loop; |
| 217 __ bind(&loop); | 221 __ bind(&loop); |
| 218 __ push(Immediate(kSlotsZapValue)); | 222 __ mov(MemOperand(esp, eax, times_4, 0), |
| 223 Immediate(kSlotsZapValue)); |
| 219 __ dec(eax); | 224 __ dec(eax); |
| 220 __ j(not_zero, &loop); | 225 __ j(not_zero, &loop); |
| 226 __ pop(eax); |
| 221 } else { | 227 } else { |
| 222 __ sub(Operand(esp), Immediate(slots * kPointerSize)); | 228 __ sub(Operand(esp), Immediate(slots * kPointerSize)); |
| 223 #ifdef _MSC_VER | 229 #ifdef _MSC_VER |
| 224 // On windows, you may not access the stack more than one page below | 230 // On windows, you may not access the stack more than one page below |
| 225 // the most recently mapped page. To make the allocated area randomly | 231 // the most recently mapped page. To make the allocated area randomly |
| 226 // accessible, we write to each page in turn (the value is irrelevant). | 232 // accessible, we write to each page in turn (the value is irrelevant). |
| 227 const int kPageSize = 4 * KB; | 233 const int kPageSize = 4 * KB; |
| 228 for (int offset = slots * kPointerSize - kPageSize; | 234 for (int offset = slots * kPointerSize - kPageSize; |
| 229 offset > 0; | 235 offset > 0; |
| 230 offset -= kPageSize) { | 236 offset -= kPageSize) { |
| 231 __ mov(Operand(esp, offset), eax); | 237 __ mov(Operand(esp, offset), eax); |
| 232 } | 238 } |
| 233 #endif | 239 #endif |
| 234 } | 240 } |
| 235 | 241 |
| 236 // Store dynamic frame alignment state in the first local. | 242 if (support_aligned_spilled_doubles_) { |
| 237 if (dynamic_frame_alignment_) { | 243 Comment(";;; Store dynamic frame alignment tag for spilled doubles"); |
| 238 __ mov(Operand(ebp, | 244 // Store dynamic frame alignment state in the first local. |
| 239 JavaScriptFrameConstants::kDynamicAlignmentStateOffset), | 245 int offset = JavaScriptFrameConstants::kDynamicAlignmentStateOffset; |
| 240 edx); | 246 if (dynamic_frame_alignment_) { |
| 241 } else { | 247 __ mov(Operand(ebp, offset), edx); |
| 242 __ mov(Operand(ebp, | 248 } else { |
| 243 JavaScriptFrameConstants::kDynamicAlignmentStateOffset), | 249 __ mov(Operand(ebp, offset), Immediate(kNoAlignmentPadding)); |
| 244 Immediate(kNoAlignmentPadding)); | 250 } |
| 251 } |
| 252 } |
| 253 |
| 254 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) { |
| 255 Comment(";;; Save clobbered callee double registers"); |
| 256 CpuFeatures::Scope scope(SSE2); |
| 257 int count = 0; |
| 258 BitVector* doubles = chunk()->allocated_double_registers(); |
| 259 BitVector::Iterator save_iterator(doubles); |
| 260 while (!save_iterator.Done()) { |
| 261 __ movdbl(MemOperand(esp, count * kDoubleSize), |
| 262 XMMRegister::FromAllocationIndex(save_iterator.Current())); |
| 263 save_iterator.Advance(); |
| 264 count++; |
| 245 } | 265 } |
| 246 } | 266 } |
| 247 } | 267 } |
| 248 | 268 |
| 249 // Possibly allocate a local context. | 269 // Possibly allocate a local context. |
| 250 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 270 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 251 if (heap_slots > 0) { | 271 if (heap_slots > 0) { |
| 252 Comment(";;; Allocate local context"); | 272 Comment(";;; Allocate local context"); |
| 253 // Argument to NewContext is the function, which is still in edi. | 273 // Argument to NewContext is the function, which is still in edi. |
| 254 __ push(edi); | 274 __ push(edi); |
| (...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 733 RecordPosition(pointers->position()); | 753 RecordPosition(pointers->position()); |
| 734 | 754 |
| 735 __ CallRuntime(fun, argc); | 755 __ CallRuntime(fun, argc); |
| 736 | 756 |
| 737 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); | 757 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); |
| 738 | 758 |
| 739 ASSERT(info()->is_calling()); | 759 ASSERT(info()->is_calling()); |
| 740 } | 760 } |
| 741 | 761 |
| 742 | 762 |
| 743 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, | 763 void LCodeGen::LoadContextFromDeferred(LOperand* context) { |
| 744 int argc, | |
| 745 LInstruction* instr, | |
| 746 LOperand* context) { | |
| 747 if (context->IsRegister()) { | 764 if (context->IsRegister()) { |
| 748 if (!ToRegister(context).is(esi)) { | 765 if (!ToRegister(context).is(esi)) { |
| 749 __ mov(esi, ToRegister(context)); | 766 __ mov(esi, ToRegister(context)); |
| 750 } | 767 } |
| 751 } else if (context->IsStackSlot()) { | 768 } else if (context->IsStackSlot()) { |
| 752 __ mov(esi, ToOperand(context)); | 769 __ mov(esi, ToOperand(context)); |
| 753 } else if (context->IsConstantOperand()) { | 770 } else if (context->IsConstantOperand()) { |
| 754 HConstant* constant = | 771 HConstant* constant = |
| 755 chunk_->LookupConstant(LConstantOperand::cast(context)); | 772 chunk_->LookupConstant(LConstantOperand::cast(context)); |
| 756 __ LoadHeapObject(esi, Handle<Context>::cast(constant->handle())); | 773 __ LoadHeapObject(esi, Handle<Context>::cast(constant->handle())); |
| 757 } else { | 774 } else { |
| 758 UNREACHABLE(); | 775 UNREACHABLE(); |
| 759 } | 776 } |
| 777 } |
| 778 |
| 779 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, |
| 780 int argc, |
| 781 LInstruction* instr, |
| 782 LOperand* context) { |
| 783 LoadContextFromDeferred(context); |
| 760 | 784 |
| 761 __ CallRuntimeSaveDoubles(id); | 785 __ CallRuntimeSaveDoubles(id); |
| 762 RecordSafepointWithRegisters( | 786 RecordSafepointWithRegisters( |
| 763 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); | 787 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); |
| 764 | 788 |
| 765 ASSERT(info()->is_calling()); | 789 ASSERT(info()->is_calling()); |
| 766 } | 790 } |
| 767 | 791 |
| 768 | 792 |
| 769 void LCodeGen::RegisterEnvironmentForDeoptimization( | 793 void LCodeGen::RegisterEnvironmentForDeoptimization( |
| (...skipping 1867 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2637 void LCodeGen::DoReturn(LReturn* instr) { | 2661 void LCodeGen::DoReturn(LReturn* instr) { |
| 2638 if (FLAG_trace && info()->IsOptimizing()) { | 2662 if (FLAG_trace && info()->IsOptimizing()) { |
| 2639 // Preserve the return value on the stack and rely on the runtime call | 2663 // Preserve the return value on the stack and rely on the runtime call |
| 2640 // to return the value in the same register. We're leaving the code | 2664 // to return the value in the same register. We're leaving the code |
| 2641 // managed by the register allocator and tearing down the frame, it's | 2665 // managed by the register allocator and tearing down the frame, it's |
| 2642 // safe to write to the context register. | 2666 // safe to write to the context register. |
| 2643 __ push(eax); | 2667 __ push(eax); |
| 2644 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2668 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2645 __ CallRuntime(Runtime::kTraceExit, 1); | 2669 __ CallRuntime(Runtime::kTraceExit, 1); |
| 2646 } | 2670 } |
| 2671 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) { |
| 2672 ASSERT(NeedsEagerFrame()); |
| 2673 CpuFeatures::Scope scope(SSE2); |
| 2674 BitVector* doubles = chunk()->allocated_double_registers(); |
| 2675 BitVector::Iterator save_iterator(doubles); |
| 2676 int count = 0; |
| 2677 while (!save_iterator.Done()) { |
| 2678 __ movdbl(XMMRegister::FromAllocationIndex(save_iterator.Current()), |
| 2679 MemOperand(esp, count * kDoubleSize)); |
| 2680 save_iterator.Advance(); |
| 2681 count++; |
| 2682 } |
| 2683 } |
| 2647 if (dynamic_frame_alignment_) { | 2684 if (dynamic_frame_alignment_) { |
| 2648 // Fetch the state of the dynamic frame alignment. | 2685 // Fetch the state of the dynamic frame alignment. |
| 2649 __ mov(edx, Operand(ebp, | 2686 __ mov(edx, Operand(ebp, |
| 2650 JavaScriptFrameConstants::kDynamicAlignmentStateOffset)); | 2687 JavaScriptFrameConstants::kDynamicAlignmentStateOffset)); |
| 2651 } | 2688 } |
| 2652 if (NeedsEagerFrame()) { | 2689 if (NeedsEagerFrame()) { |
| 2653 __ mov(esp, ebp); | 2690 __ mov(esp, ebp); |
| 2654 __ pop(ebp); | 2691 __ pop(ebp); |
| 2655 } | 2692 } |
| 2656 if (dynamic_frame_alignment_) { | 2693 if (dynamic_frame_alignment_) { |
| (...skipping 1641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4298 ASSERT(ToRegister(instr->key()).is(ecx)); | 4335 ASSERT(ToRegister(instr->key()).is(ecx)); |
| 4299 ASSERT(ToRegister(instr->value()).is(eax)); | 4336 ASSERT(ToRegister(instr->value()).is(eax)); |
| 4300 | 4337 |
| 4301 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) | 4338 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) |
| 4302 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 4339 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 4303 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 4340 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 4304 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 4341 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 4305 } | 4342 } |
| 4306 | 4343 |
| 4307 | 4344 |
| 4345 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { |
| 4346 Register object = ToRegister(instr->object()); |
| 4347 Register temp = ToRegister(instr->temp()); |
| 4348 __ TestJSArrayForAllocationSiteInfo(object, temp); |
| 4349 DeoptimizeIf(equal, instr->environment()); |
| 4350 } |
| 4351 |
| 4352 |
| 4308 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { | 4353 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { |
| 4309 Register object_reg = ToRegister(instr->object()); | 4354 Register object_reg = ToRegister(instr->object()); |
| 4310 Register new_map_reg = ToRegister(instr->new_map_temp()); | |
| 4311 | 4355 |
| 4312 Handle<Map> from_map = instr->original_map(); | 4356 Handle<Map> from_map = instr->original_map(); |
| 4313 Handle<Map> to_map = instr->transitioned_map(); | 4357 Handle<Map> to_map = instr->transitioned_map(); |
| 4314 ElementsKind from_kind = instr->from_kind(); | 4358 ElementsKind from_kind = instr->from_kind(); |
| 4315 ElementsKind to_kind = instr->to_kind(); | 4359 ElementsKind to_kind = instr->to_kind(); |
| 4316 | 4360 |
| 4317 Label not_applicable; | 4361 Label not_applicable; |
| 4318 bool is_simple_map_transition = | 4362 bool is_simple_map_transition = |
| 4319 IsSimpleMapChangeTransition(from_kind, to_kind); | 4363 IsSimpleMapChangeTransition(from_kind, to_kind); |
| 4320 Label::Distance branch_distance = | 4364 Label::Distance branch_distance = |
| 4321 is_simple_map_transition ? Label::kNear : Label::kFar; | 4365 is_simple_map_transition ? Label::kNear : Label::kFar; |
| 4322 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map); | 4366 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map); |
| 4323 __ j(not_equal, ¬_applicable, branch_distance); | 4367 __ j(not_equal, ¬_applicable, branch_distance); |
| 4324 if (is_simple_map_transition) { | 4368 if (is_simple_map_transition) { |
| 4325 Register object_reg = ToRegister(instr->object()); | 4369 Register new_map_reg = ToRegister(instr->new_map_temp()); |
| 4326 Handle<Map> map = instr->hydrogen()->transitioned_map(); | 4370 Handle<Map> map = instr->hydrogen()->transitioned_map(); |
| 4327 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), | 4371 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), |
| 4328 Immediate(map)); | 4372 Immediate(map)); |
| 4329 // Write barrier. | 4373 // Write barrier. |
| 4330 ASSERT_NE(instr->temp(), NULL); | 4374 ASSERT_NE(instr->temp(), NULL); |
| 4331 __ RecordWriteForMap(object_reg, to_map, new_map_reg, | 4375 __ RecordWriteForMap(object_reg, to_map, new_map_reg, |
| 4332 ToRegister(instr->temp()), | 4376 ToRegister(instr->temp()), |
| 4333 kDontSaveFPRegs); | 4377 kDontSaveFPRegs); |
| 4378 } else if (FLAG_compiled_transitions) { |
| 4379 PushSafepointRegistersScope scope(this); |
| 4380 if (!object_reg.is(eax)) { |
| 4381 __ push(object_reg); |
| 4382 } |
| 4383 LoadContextFromDeferred(instr->context()); |
| 4384 if (!object_reg.is(eax)) { |
| 4385 __ pop(eax); |
| 4386 } |
| 4387 __ mov(ebx, to_map); |
| 4388 TransitionElementsKindStub stub(from_kind, to_kind); |
| 4389 __ CallStub(&stub); |
| 4390 RecordSafepointWithRegisters( |
| 4391 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); |
| 4334 } else if (IsFastSmiElementsKind(from_kind) && | 4392 } else if (IsFastSmiElementsKind(from_kind) && |
| 4335 IsFastDoubleElementsKind(to_kind)) { | 4393 IsFastDoubleElementsKind(to_kind)) { |
| 4394 Register new_map_reg = ToRegister(instr->new_map_temp()); |
| 4336 __ mov(new_map_reg, to_map); | 4395 __ mov(new_map_reg, to_map); |
| 4337 Register fixed_object_reg = ToRegister(instr->temp()); | 4396 Register fixed_object_reg = ToRegister(instr->temp()); |
| 4338 ASSERT(fixed_object_reg.is(edx)); | 4397 ASSERT(fixed_object_reg.is(edx)); |
| 4339 ASSERT(new_map_reg.is(ebx)); | 4398 ASSERT(new_map_reg.is(ebx)); |
| 4340 __ mov(fixed_object_reg, object_reg); | 4399 __ mov(fixed_object_reg, object_reg); |
| 4341 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(), | 4400 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(), |
| 4342 RelocInfo::CODE_TARGET, instr); | 4401 RelocInfo::CODE_TARGET, instr); |
| 4343 } else if (IsFastDoubleElementsKind(from_kind) && | 4402 } else if (IsFastDoubleElementsKind(from_kind) && |
| 4344 IsFastObjectElementsKind(to_kind)) { | 4403 IsFastObjectElementsKind(to_kind)) { |
| 4404 Register new_map_reg = ToRegister(instr->new_map_temp()); |
| 4345 __ mov(new_map_reg, to_map); | 4405 __ mov(new_map_reg, to_map); |
| 4346 Register fixed_object_reg = ToRegister(instr->temp()); | 4406 Register fixed_object_reg = ToRegister(instr->temp()); |
| 4347 ASSERT(fixed_object_reg.is(edx)); | 4407 ASSERT(fixed_object_reg.is(edx)); |
| 4348 ASSERT(new_map_reg.is(ebx)); | 4408 ASSERT(new_map_reg.is(ebx)); |
| 4349 __ mov(fixed_object_reg, object_reg); | 4409 __ mov(fixed_object_reg, object_reg); |
| 4350 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(), | 4410 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(), |
| 4351 RelocInfo::CODE_TARGET, instr); | 4411 RelocInfo::CODE_TARGET, instr); |
| 4352 } else { | 4412 } else { |
| 4353 UNREACHABLE(); | 4413 UNREACHABLE(); |
| 4354 } | 4414 } |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4631 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) | 4691 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) |
| 4632 : LDeferredCode(codegen), instr_(instr) { } | 4692 : LDeferredCode(codegen), instr_(instr) { } |
| 4633 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } | 4693 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } |
| 4634 virtual LInstruction* instr() { return instr_; } | 4694 virtual LInstruction* instr() { return instr_; } |
| 4635 private: | 4695 private: |
| 4636 LNumberTagD* instr_; | 4696 LNumberTagD* instr_; |
| 4637 }; | 4697 }; |
| 4638 | 4698 |
| 4639 Register reg = ToRegister(instr->result()); | 4699 Register reg = ToRegister(instr->result()); |
| 4640 | 4700 |
| 4701 bool convert_hole = false; |
| 4702 HValue* change_input = instr->hydrogen()->value(); |
| 4703 if (change_input->IsLoadKeyed()) { |
| 4704 HLoadKeyed* load = HLoadKeyed::cast(change_input); |
| 4705 convert_hole = load->UsesMustHandleHole(); |
| 4706 } |
| 4707 |
| 4708 Label no_special_nan_handling; |
| 4709 Label done; |
| 4710 if (convert_hole) { |
| 4711 bool use_sse2 = CpuFeatures::IsSupported(SSE2); |
| 4712 if (use_sse2) { |
| 4713 CpuFeatures::Scope scope(SSE2); |
| 4714 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 4715 __ ucomisd(input_reg, input_reg); |
| 4716 } else { |
| 4717 if (!IsX87TopOfStack(instr->value())) { |
| 4718 __ fld_d(ToOperand(instr->value())); |
| 4719 } |
| 4720 __ fld(0); |
| 4721 __ fld(0); |
| 4722 __ FCmp(); |
| 4723 } |
| 4724 |
| 4725 __ j(parity_odd, &no_special_nan_handling); |
| 4726 __ sub(esp, Immediate(kDoubleSize)); |
| 4727 if (use_sse2) { |
| 4728 CpuFeatures::Scope scope(SSE2); |
| 4729 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 4730 __ movdbl(MemOperand(esp, 0), input_reg); |
| 4731 } else { |
| 4732 __ fld(0); |
| 4733 __ fstp_d(MemOperand(esp, 0)); |
| 4734 } |
| 4735 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)), |
| 4736 Immediate(kHoleNanUpper32)); |
| 4737 Label canonicalize; |
| 4738 __ j(not_equal, &canonicalize); |
| 4739 __ add(esp, Immediate(kDoubleSize)); |
| 4740 __ mov(reg, factory()->the_hole_value()); |
| 4741 __ jmp(&done); |
| 4742 __ bind(&canonicalize); |
| 4743 __ add(esp, Immediate(kDoubleSize)); |
| 4744 ExternalReference nan = |
| 4745 ExternalReference::address_of_canonical_non_hole_nan(); |
| 4746 if (use_sse2) { |
| 4747 CpuFeatures::Scope scope(SSE2); |
| 4748 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 4749 __ movdbl(input_reg, Operand::StaticVariable(nan)); |
| 4750 } else { |
| 4751 __ fstp(0); |
| 4752 __ fld_d(Operand::StaticVariable(nan)); |
| 4753 } |
| 4754 } |
| 4755 |
| 4756 __ bind(&no_special_nan_handling); |
| 4641 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); | 4757 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); |
| 4642 if (FLAG_inline_new) { | 4758 if (FLAG_inline_new) { |
| 4643 Register tmp = ToRegister(instr->temp()); | 4759 Register tmp = ToRegister(instr->temp()); |
| 4644 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry()); | 4760 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry()); |
| 4645 } else { | 4761 } else { |
| 4646 __ jmp(deferred->entry()); | 4762 __ jmp(deferred->entry()); |
| 4647 } | 4763 } |
| 4648 __ bind(deferred->exit()); | 4764 __ bind(deferred->exit()); |
| 4649 if (CpuFeatures::IsSupported(SSE2)) { | 4765 if (CpuFeatures::IsSupported(SSE2)) { |
| 4650 CpuFeatures::Scope scope(SSE2); | 4766 CpuFeatures::Scope scope(SSE2); |
| 4651 XMMRegister input_reg = ToDoubleRegister(instr->value()); | 4767 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 4652 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg); | 4768 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg); |
| 4653 } else { | 4769 } else { |
| 4654 if (!IsX87TopOfStack(instr->value())) { | 4770 if (!IsX87TopOfStack(instr->value())) { |
| 4655 __ fld_d(ToOperand(instr->value())); | 4771 __ fld_d(ToOperand(instr->value())); |
| 4656 } | 4772 } |
| 4657 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset)); | 4773 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset)); |
| 4658 } | 4774 } |
| 4775 __ bind(&done); |
| 4659 } | 4776 } |
| 4660 | 4777 |
| 4661 | 4778 |
| 4662 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { | 4779 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { |
| 4663 // TODO(3095996): Get rid of this. For now, we need to make the | 4780 // TODO(3095996): Get rid of this. For now, we need to make the |
| 4664 // result register contain a valid pointer because it is already | 4781 // result register contain a valid pointer because it is already |
| 4665 // contained in the register pointer map. | 4782 // contained in the register pointer map. |
| 4666 Register reg = ToRegister(instr->result()); | 4783 Register reg = ToRegister(instr->result()); |
| 4667 __ Set(reg, Immediate(0)); | 4784 __ Set(reg, Immediate(0)); |
| 4668 | 4785 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 4699 } | 4816 } |
| 4700 __ SmiUntag(ToRegister(input)); | 4817 __ SmiUntag(ToRegister(input)); |
| 4701 } | 4818 } |
| 4702 | 4819 |
| 4703 | 4820 |
| 4704 void LCodeGen::EmitNumberUntagD(Register input_reg, | 4821 void LCodeGen::EmitNumberUntagD(Register input_reg, |
| 4705 Register temp_reg, | 4822 Register temp_reg, |
| 4706 XMMRegister result_reg, | 4823 XMMRegister result_reg, |
| 4707 bool deoptimize_on_undefined, | 4824 bool deoptimize_on_undefined, |
| 4708 bool deoptimize_on_minus_zero, | 4825 bool deoptimize_on_minus_zero, |
| 4709 LEnvironment* env) { | 4826 LEnvironment* env, |
| 4827 NumberUntagDMode mode) { |
| 4710 Label load_smi, done; | 4828 Label load_smi, done; |
| 4711 | 4829 |
| 4712 // Smi check. | 4830 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { |
| 4713 __ JumpIfSmi(input_reg, &load_smi, Label::kNear); | 4831 // Smi check. |
| 4832 __ JumpIfSmi(input_reg, &load_smi, Label::kNear); |
| 4714 | 4833 |
| 4715 // Heap number map check. | 4834 // Heap number map check. |
| 4716 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 4835 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 4717 factory()->heap_number_map()); | 4836 factory()->heap_number_map()); |
| 4718 if (deoptimize_on_undefined) { | 4837 if (deoptimize_on_undefined) { |
| 4838 DeoptimizeIf(not_equal, env); |
| 4839 } else { |
| 4840 Label heap_number; |
| 4841 __ j(equal, &heap_number, Label::kNear); |
| 4842 |
| 4843 __ cmp(input_reg, factory()->undefined_value()); |
| 4844 DeoptimizeIf(not_equal, env); |
| 4845 |
| 4846 // Convert undefined to NaN. |
| 4847 ExternalReference nan = |
| 4848 ExternalReference::address_of_canonical_non_hole_nan(); |
| 4849 __ movdbl(result_reg, Operand::StaticVariable(nan)); |
| 4850 __ jmp(&done, Label::kNear); |
| 4851 |
| 4852 __ bind(&heap_number); |
| 4853 } |
| 4854 // Heap number to XMM conversion. |
| 4855 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 4856 if (deoptimize_on_minus_zero) { |
| 4857 XMMRegister xmm_scratch = xmm0; |
| 4858 __ xorps(xmm_scratch, xmm_scratch); |
| 4859 __ ucomisd(result_reg, xmm_scratch); |
| 4860 __ j(not_zero, &done, Label::kNear); |
| 4861 __ movmskpd(temp_reg, result_reg); |
| 4862 __ test_b(temp_reg, 1); |
| 4863 DeoptimizeIf(not_zero, env); |
| 4864 } |
| 4865 __ jmp(&done, Label::kNear); |
| 4866 } else if (mode == NUMBER_CANDIDATE_IS_SMI_OR_HOLE) { |
| 4867 __ test(input_reg, Immediate(kSmiTagMask)); |
| 4719 DeoptimizeIf(not_equal, env); | 4868 DeoptimizeIf(not_equal, env); |
| 4869 } else if (mode == NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE) { |
| 4870 __ test(input_reg, Immediate(kSmiTagMask)); |
| 4871 __ j(zero, &load_smi); |
| 4872 ExternalReference hole_nan_reference = |
| 4873 ExternalReference::address_of_the_hole_nan(); |
| 4874 __ movdbl(result_reg, Operand::StaticVariable(hole_nan_reference)); |
| 4875 __ jmp(&done, Label::kNear); |
| 4720 } else { | 4876 } else { |
| 4721 Label heap_number; | 4877 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI); |
| 4722 __ j(equal, &heap_number, Label::kNear); | |
| 4723 | |
| 4724 __ cmp(input_reg, factory()->undefined_value()); | |
| 4725 DeoptimizeIf(not_equal, env); | |
| 4726 | |
| 4727 // Convert undefined to NaN. | |
| 4728 ExternalReference nan = | |
| 4729 ExternalReference::address_of_canonical_non_hole_nan(); | |
| 4730 __ movdbl(result_reg, Operand::StaticVariable(nan)); | |
| 4731 __ jmp(&done, Label::kNear); | |
| 4732 | |
| 4733 __ bind(&heap_number); | |
| 4734 } | 4878 } |
| 4735 // Heap number to XMM conversion. | |
| 4736 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); | |
| 4737 if (deoptimize_on_minus_zero) { | |
| 4738 XMMRegister xmm_scratch = xmm0; | |
| 4739 __ xorps(xmm_scratch, xmm_scratch); | |
| 4740 __ ucomisd(result_reg, xmm_scratch); | |
| 4741 __ j(not_zero, &done, Label::kNear); | |
| 4742 __ movmskpd(temp_reg, result_reg); | |
| 4743 __ test_b(temp_reg, 1); | |
| 4744 DeoptimizeIf(not_zero, env); | |
| 4745 } | |
| 4746 __ jmp(&done, Label::kNear); | |
| 4747 | 4879 |
| 4748 // Smi to XMM conversion | 4880 // Smi to XMM conversion |
| 4749 __ bind(&load_smi); | 4881 __ bind(&load_smi); |
| 4750 __ SmiUntag(input_reg); // Untag smi before converting to float. | 4882 __ SmiUntag(input_reg); // Untag smi before converting to float. |
| 4751 __ cvtsi2sd(result_reg, Operand(input_reg)); | 4883 __ cvtsi2sd(result_reg, Operand(input_reg)); |
| 4752 __ SmiTag(input_reg); // Retag smi. | 4884 __ SmiTag(input_reg); // Retag smi. |
| 4753 __ bind(&done); | 4885 __ bind(&done); |
| 4754 } | 4886 } |
| 4755 | 4887 |
| 4756 | 4888 |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4882 | 5014 |
| 4883 if (CpuFeatures::IsSupported(SSE2)) { | 5015 if (CpuFeatures::IsSupported(SSE2)) { |
| 4884 CpuFeatures::Scope scope(SSE2); | 5016 CpuFeatures::Scope scope(SSE2); |
| 4885 Register input_reg = ToRegister(input); | 5017 Register input_reg = ToRegister(input); |
| 4886 XMMRegister result_reg = ToDoubleRegister(result); | 5018 XMMRegister result_reg = ToDoubleRegister(result); |
| 4887 | 5019 |
| 4888 bool deoptimize_on_minus_zero = | 5020 bool deoptimize_on_minus_zero = |
| 4889 instr->hydrogen()->deoptimize_on_minus_zero(); | 5021 instr->hydrogen()->deoptimize_on_minus_zero(); |
| 4890 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg; | 5022 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg; |
| 4891 | 5023 |
| 5024 NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED; |
| 5025 HValue* value = instr->hydrogen()->value(); |
| 5026 if (value->type().IsSmi()) { |
| 5027 if (value->IsLoadKeyed()) { |
| 5028 HLoadKeyed* load = HLoadKeyed::cast(value); |
| 5029 if (load->UsesMustHandleHole()) { |
| 5030 if (load->hole_mode() == ALLOW_RETURN_HOLE) { |
| 5031 mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE; |
| 5032 } else { |
| 5033 mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE; |
| 5034 } |
| 5035 } else { |
| 5036 mode = NUMBER_CANDIDATE_IS_SMI; |
| 5037 } |
| 5038 } |
| 5039 } |
| 5040 |
| 4892 EmitNumberUntagD(input_reg, | 5041 EmitNumberUntagD(input_reg, |
| 4893 temp_reg, | 5042 temp_reg, |
| 4894 result_reg, | 5043 result_reg, |
| 4895 instr->hydrogen()->deoptimize_on_undefined(), | 5044 instr->hydrogen()->deoptimize_on_undefined(), |
| 4896 deoptimize_on_minus_zero, | 5045 deoptimize_on_minus_zero, |
| 4897 instr->environment()); | 5046 instr->environment(), |
| 5047 mode); |
| 4898 } else { | 5048 } else { |
| 4899 UNIMPLEMENTED(); | 5049 UNIMPLEMENTED(); |
| 4900 } | 5050 } |
| 4901 } | 5051 } |
| 4902 | 5052 |
| 4903 | 5053 |
| 4904 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { | 5054 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { |
| 4905 LOperand* input = instr->value(); | 5055 LOperand* input = instr->value(); |
| 4906 ASSERT(input->IsDoubleRegister()); | 5056 ASSERT(input->IsDoubleRegister()); |
| 4907 LOperand* result = instr->result(); | 5057 LOperand* result = instr->result(); |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5280 __ Set(result, Immediate(0)); | 5430 __ Set(result, Immediate(0)); |
| 5281 | 5431 |
| 5282 PushSafepointRegistersScope scope(this); | 5432 PushSafepointRegistersScope scope(this); |
| 5283 __ push(Immediate(Smi::FromInt(instance_size))); | 5433 __ push(Immediate(Smi::FromInt(instance_size))); |
| 5284 CallRuntimeFromDeferred( | 5434 CallRuntimeFromDeferred( |
| 5285 Runtime::kAllocateInNewSpace, 1, instr, instr->context()); | 5435 Runtime::kAllocateInNewSpace, 1, instr, instr->context()); |
| 5286 __ StoreToSafepointRegisterSlot(result, eax); | 5436 __ StoreToSafepointRegisterSlot(result, eax); |
| 5287 } | 5437 } |
| 5288 | 5438 |
| 5289 | 5439 |
| 5440 void LCodeGen::DoAllocate(LAllocate* instr) { |
| 5441 class DeferredAllocate: public LDeferredCode { |
| 5442 public: |
| 5443 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) |
| 5444 : LDeferredCode(codegen), instr_(instr) { } |
| 5445 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } |
| 5446 virtual LInstruction* instr() { return instr_; } |
| 5447 private: |
| 5448 LAllocate* instr_; |
| 5449 }; |
| 5450 |
| 5451 DeferredAllocate* deferred = |
| 5452 new(zone()) DeferredAllocate(this, instr); |
| 5453 |
| 5454 Register size = ToRegister(instr->size()); |
| 5455 Register result = ToRegister(instr->result()); |
| 5456 Register temp = ToRegister(instr->temp()); |
| 5457 |
| 5458 HAllocate* original_instr = instr->hydrogen(); |
| 5459 if (original_instr->size()->IsConstant()) { |
| 5460 UNREACHABLE(); |
| 5461 } else { |
| 5462 // Allocate memory for the object. |
| 5463 AllocationFlags flags = TAG_OBJECT; |
| 5464 if (original_instr->MustAllocateDoubleAligned()) { |
| 5465 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT); |
| 5466 } |
| 5467 __ AllocateInNewSpace(size, result, temp, no_reg, |
| 5468 deferred->entry(), flags); |
| 5469 } |
| 5470 |
| 5471 __ bind(deferred->exit()); |
| 5472 } |
| 5473 |
| 5474 |
| 5475 void LCodeGen::DoDeferredAllocate(LAllocate* instr) { |
| 5476 Register size = ToRegister(instr->size()); |
| 5477 Register result = ToRegister(instr->result()); |
| 5478 |
| 5479 __ SmiTag(size); |
| 5480 PushSafepointRegistersScope scope(this); |
| 5481 // TODO(3095996): Get rid of this. For now, we need to make the |
| 5482 // result register contain a valid pointer because it is already |
| 5483 // contained in the register pointer map. |
| 5484 if (!size.is(result)) { |
| 5485 __ StoreToSafepointRegisterSlot(result, size); |
| 5486 } |
| 5487 __ push(size); |
| 5488 CallRuntimeFromDeferred( |
| 5489 Runtime::kAllocateInNewSpace, 1, instr, instr->context()); |
| 5490 __ StoreToSafepointRegisterSlot(result, eax); |
| 5491 } |
| 5492 |
| 5493 |
| 5290 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { | 5494 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { |
| 5291 ASSERT(ToRegister(instr->context()).is(esi)); | 5495 ASSERT(ToRegister(instr->context()).is(esi)); |
| 5292 Handle<FixedArray> literals(instr->environment()->closure()->literals()); | 5496 Handle<FixedArray> literals(instr->environment()->closure()->literals()); |
| 5293 ElementsKind boilerplate_elements_kind = | 5497 ElementsKind boilerplate_elements_kind = |
| 5294 instr->hydrogen()->boilerplate_elements_kind(); | 5498 instr->hydrogen()->boilerplate_elements_kind(); |
| 5295 AllocationSiteMode allocation_site_mode = | 5499 AllocationSiteMode allocation_site_mode = |
| 5296 instr->hydrogen()->allocation_site_mode(); | 5500 instr->hydrogen()->allocation_site_mode(); |
| 5297 | 5501 |
| 5298 // Deopt if the array literal boilerplate ElementsKind is of a type different | 5502 // Deopt if the array literal boilerplate ElementsKind is of a type different |
| 5299 // than the expected one. The check isn't necessary if the boilerplate has | 5503 // than the expected one. The check isn't necessary if the boilerplate has |
| (...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5974 FixedArray::kHeaderSize - kPointerSize)); | 6178 FixedArray::kHeaderSize - kPointerSize)); |
| 5975 __ bind(&done); | 6179 __ bind(&done); |
| 5976 } | 6180 } |
| 5977 | 6181 |
| 5978 | 6182 |
| 5979 #undef __ | 6183 #undef __ |
| 5980 | 6184 |
| 5981 } } // namespace v8::internal | 6185 } } // namespace v8::internal |
| 5982 | 6186 |
| 5983 #endif // V8_TARGET_ARCH_IA32 | 6187 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |