| Index: src/ia32/lithium-codegen-ia32.cc
 | 
| diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
 | 
| index d344e3361792870169a47c2098ad999d2d96068e..dfced7c221335f060f7c333e02c0ec38bb7516d8 100644
 | 
| --- a/src/ia32/lithium-codegen-ia32.cc
 | 
| +++ b/src/ia32/lithium-codegen-ia32.cc
 | 
| @@ -77,6 +77,8 @@ bool LCodeGen::GenerateCode() {
 | 
|    // the frame (that is done in GeneratePrologue).
 | 
|    FrameScope frame_scope(masm_, StackFrame::MANUAL);
 | 
|  
 | 
| +  support_aligned_spilled_doubles_ = info()->IsOptimizing();
 | 
| +
 | 
|    dynamic_frame_alignment_ = info()->IsOptimizing() &&
 | 
|        ((chunk()->num_double_slots() > 2 &&
 | 
|          !chunk()->graph()->is_recursive()) ||
 | 
| @@ -153,7 +155,7 @@ bool LCodeGen::GeneratePrologue() {
 | 
|        __ bind(&ok);
 | 
|      }
 | 
|  
 | 
| -    if (dynamic_frame_alignment_) {
 | 
| +    if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
 | 
|        // Move state of dynamic frame alignment into edx.
 | 
|        __ mov(edx, Immediate(kNoAlignmentPadding));
 | 
|  
 | 
| @@ -212,12 +214,16 @@ bool LCodeGen::GeneratePrologue() {
 | 
|        }
 | 
|      } else {
 | 
|        if (FLAG_debug_code) {
 | 
| +        __ sub(Operand(esp), Immediate(slots * kPointerSize));
 | 
| +        __ push(eax);
 | 
|          __ mov(Operand(eax), Immediate(slots));
 | 
|          Label loop;
 | 
|          __ bind(&loop);
 | 
| -        __ push(Immediate(kSlotsZapValue));
 | 
| +        __ mov(MemOperand(esp, eax, times_4, 0),
 | 
| +               Immediate(kSlotsZapValue));
 | 
|          __ dec(eax);
 | 
|          __ j(not_zero, &loop);
 | 
| +        __ pop(eax);
 | 
|        } else {
 | 
|          __ sub(Operand(esp), Immediate(slots * kPointerSize));
 | 
|  #ifdef _MSC_VER
 | 
| @@ -233,15 +239,29 @@ bool LCodeGen::GeneratePrologue() {
 | 
|  #endif
 | 
|        }
 | 
|  
 | 
| -      // Store dynamic frame alignment state in the first local.
 | 
| -      if (dynamic_frame_alignment_) {
 | 
| -        __ mov(Operand(ebp,
 | 
| -                       JavaScriptFrameConstants::kDynamicAlignmentStateOffset),
 | 
| -               edx);
 | 
| -      } else {
 | 
| -        __ mov(Operand(ebp,
 | 
| -                       JavaScriptFrameConstants::kDynamicAlignmentStateOffset),
 | 
| -               Immediate(kNoAlignmentPadding));
 | 
| +      if (support_aligned_spilled_doubles_) {
 | 
| +        Comment(";;; Store dynamic frame alignment tag for spilled doubles");
 | 
| +        // Store dynamic frame alignment state in the first local.
 | 
| +        int offset = JavaScriptFrameConstants::kDynamicAlignmentStateOffset;
 | 
| +        if (dynamic_frame_alignment_) {
 | 
| +          __ mov(Operand(ebp, offset), edx);
 | 
| +        } else {
 | 
| +          __ mov(Operand(ebp, offset), Immediate(kNoAlignmentPadding));
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
 | 
| +      Comment(";;; Save clobbered callee double registers");
 | 
| +      CpuFeatures::Scope scope(SSE2);
 | 
| +      int count = 0;
 | 
| +      BitVector* doubles = chunk()->allocated_double_registers();
 | 
| +      BitVector::Iterator save_iterator(doubles);
 | 
| +      while (!save_iterator.Done()) {
 | 
| +        __ movdbl(MemOperand(esp, count * kDoubleSize),
 | 
| +                  XMMRegister::FromAllocationIndex(save_iterator.Current()));
 | 
| +        save_iterator.Advance();
 | 
| +        count++;
 | 
|        }
 | 
|      }
 | 
|    }
 | 
| @@ -740,10 +760,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* fun,
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
 | 
| -                                       int argc,
 | 
| -                                       LInstruction* instr,
 | 
| -                                       LOperand* context) {
 | 
| +void LCodeGen::LoadContextFromDeferred(LOperand* context) {
 | 
|    if (context->IsRegister()) {
 | 
|      if (!ToRegister(context).is(esi)) {
 | 
|        __ mov(esi, ToRegister(context));
 | 
| @@ -757,6 +774,13 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
 | 
|    } else {
 | 
|      UNREACHABLE();
 | 
|    }
 | 
| +}
 | 
| +
 | 
| +void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
 | 
| +                                       int argc,
 | 
| +                                       LInstruction* instr,
 | 
| +                                       LOperand* context) {
 | 
| +  LoadContextFromDeferred(context);
 | 
|  
 | 
|    __ CallRuntimeSaveDoubles(id);
 | 
|    RecordSafepointWithRegisters(
 | 
| @@ -2644,6 +2668,19 @@ void LCodeGen::DoReturn(LReturn* instr) {
 | 
|      __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
 | 
|      __ CallRuntime(Runtime::kTraceExit, 1);
 | 
|    }
 | 
| +  if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
 | 
| +    ASSERT(NeedsEagerFrame());
 | 
| +    CpuFeatures::Scope scope(SSE2);
 | 
| +    BitVector* doubles = chunk()->allocated_double_registers();
 | 
| +    BitVector::Iterator save_iterator(doubles);
 | 
| +    int count = 0;
 | 
| +    while (!save_iterator.Done()) {
 | 
| +      __ movdbl(XMMRegister::FromAllocationIndex(save_iterator.Current()),
 | 
| +                MemOperand(esp, count * kDoubleSize));
 | 
| +      save_iterator.Advance();
 | 
| +      count++;
 | 
| +    }
 | 
| +  }
 | 
|    if (dynamic_frame_alignment_) {
 | 
|      // Fetch the state of the dynamic frame alignment.
 | 
|      __ mov(edx, Operand(ebp,
 | 
| @@ -4305,9 +4342,16 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
 | 
| +  Register object = ToRegister(instr->object());
 | 
| +  Register temp = ToRegister(instr->temp());
 | 
| +  __ TestJSArrayForAllocationSiteInfo(object, temp);
 | 
| +  DeoptimizeIf(equal, instr->environment());
 | 
| +}
 | 
| +
 | 
| +
 | 
|  void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
 | 
|    Register object_reg = ToRegister(instr->object());
 | 
| -  Register new_map_reg = ToRegister(instr->new_map_temp());
 | 
|  
 | 
|    Handle<Map> from_map = instr->original_map();
 | 
|    Handle<Map> to_map = instr->transitioned_map();
 | 
| @@ -4322,7 +4366,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
 | 
|    __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
 | 
|    __ j(not_equal, ¬_applicable, branch_distance);
 | 
|    if (is_simple_map_transition) {
 | 
| -    Register object_reg = ToRegister(instr->object());
 | 
| +    Register new_map_reg = ToRegister(instr->new_map_temp());
 | 
|      Handle<Map> map = instr->hydrogen()->transitioned_map();
 | 
|      __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
 | 
|             Immediate(map));
 | 
| @@ -4331,8 +4375,23 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
 | 
|      __ RecordWriteForMap(object_reg, to_map, new_map_reg,
 | 
|                           ToRegister(instr->temp()),
 | 
|                           kDontSaveFPRegs);
 | 
| +  } else if (FLAG_compiled_transitions) {
 | 
| +    PushSafepointRegistersScope scope(this);
 | 
| +    if (!object_reg.is(eax)) {
 | 
| +      __ push(object_reg);
 | 
| +    }
 | 
| +    LoadContextFromDeferred(instr->context());
 | 
| +    if (!object_reg.is(eax)) {
 | 
| +      __ pop(eax);
 | 
| +    }
 | 
| +    __ mov(ebx, to_map);
 | 
| +    TransitionElementsKindStub stub(from_kind, to_kind);
 | 
| +    __ CallStub(&stub);
 | 
| +    RecordSafepointWithRegisters(
 | 
| +        instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
 | 
|    } else if (IsFastSmiElementsKind(from_kind) &&
 | 
|               IsFastDoubleElementsKind(to_kind)) {
 | 
| +    Register new_map_reg = ToRegister(instr->new_map_temp());
 | 
|      __ mov(new_map_reg, to_map);
 | 
|      Register fixed_object_reg = ToRegister(instr->temp());
 | 
|      ASSERT(fixed_object_reg.is(edx));
 | 
| @@ -4342,6 +4401,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
 | 
|               RelocInfo::CODE_TARGET, instr);
 | 
|    } else if (IsFastDoubleElementsKind(from_kind) &&
 | 
|               IsFastObjectElementsKind(to_kind)) {
 | 
| +    Register new_map_reg = ToRegister(instr->new_map_temp());
 | 
|      __ mov(new_map_reg, to_map);
 | 
|      Register fixed_object_reg = ToRegister(instr->temp());
 | 
|      ASSERT(fixed_object_reg.is(edx));
 | 
| @@ -4638,6 +4698,62 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
 | 
|  
 | 
|    Register reg = ToRegister(instr->result());
 | 
|  
 | 
| +  bool convert_hole = false;
 | 
| +  HValue* change_input = instr->hydrogen()->value();
 | 
| +  if (change_input->IsLoadKeyed()) {
 | 
| +    HLoadKeyed* load = HLoadKeyed::cast(change_input);
 | 
| +    convert_hole = load->UsesMustHandleHole();
 | 
| +  }
 | 
| +
 | 
| +  Label no_special_nan_handling;
 | 
| +  Label done;
 | 
| +  if (convert_hole) {
 | 
| +    bool use_sse2 = CpuFeatures::IsSupported(SSE2);
 | 
| +    if (use_sse2) {
 | 
| +      CpuFeatures::Scope scope(SSE2);
 | 
| +      XMMRegister input_reg = ToDoubleRegister(instr->value());
 | 
| +      __ ucomisd(input_reg, input_reg);
 | 
| +    } else {
 | 
| +      if (!IsX87TopOfStack(instr->value())) {
 | 
| +        __ fld_d(ToOperand(instr->value()));
 | 
| +      }
 | 
| +      __ fld(0);
 | 
| +      __ fld(0);
 | 
| +      __ FCmp();
 | 
| +    }
 | 
| +
 | 
| +    __ j(parity_odd, &no_special_nan_handling);
 | 
| +    __ sub(esp, Immediate(kDoubleSize));
 | 
| +    if (use_sse2) {
 | 
| +      CpuFeatures::Scope scope(SSE2);
 | 
| +      XMMRegister input_reg = ToDoubleRegister(instr->value());
 | 
| +      __ movdbl(MemOperand(esp, 0), input_reg);
 | 
| +    } else {
 | 
| +      __ fld(0);
 | 
| +      __ fstp_d(MemOperand(esp, 0));
 | 
| +    }
 | 
| +    __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
 | 
| +           Immediate(kHoleNanUpper32));
 | 
| +    Label canonicalize;
 | 
| +    __ j(not_equal, &canonicalize);
 | 
| +    __ add(esp, Immediate(kDoubleSize));
 | 
| +    __ mov(reg, factory()->the_hole_value());
 | 
| +    __ jmp(&done);
 | 
| +    __ bind(&canonicalize);
 | 
| +    __ add(esp, Immediate(kDoubleSize));
 | 
| +    ExternalReference nan =
 | 
| +        ExternalReference::address_of_canonical_non_hole_nan();
 | 
| +    if (use_sse2) {
 | 
| +      CpuFeatures::Scope scope(SSE2);
 | 
| +      XMMRegister input_reg = ToDoubleRegister(instr->value());
 | 
| +      __ movdbl(input_reg, Operand::StaticVariable(nan));
 | 
| +    } else {
 | 
| +      __ fstp(0);
 | 
| +      __ fld_d(Operand::StaticVariable(nan));
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  __ bind(&no_special_nan_handling);
 | 
|    DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
 | 
|    if (FLAG_inline_new) {
 | 
|      Register tmp = ToRegister(instr->temp());
 | 
| @@ -4656,6 +4772,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
 | 
|      }
 | 
|      __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
 | 
|    }
 | 
| +  __ bind(&done);
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -4706,44 +4823,59 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
 | 
|                                  XMMRegister result_reg,
 | 
|                                  bool deoptimize_on_undefined,
 | 
|                                  bool deoptimize_on_minus_zero,
 | 
| -                                LEnvironment* env) {
 | 
| +                                LEnvironment* env,
 | 
| +                                NumberUntagDMode mode) {
 | 
|    Label load_smi, done;
 | 
|  
 | 
| -  // Smi check.
 | 
| -  __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
 | 
| +  if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
 | 
| +    // Smi check.
 | 
| +    __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
 | 
|  
 | 
| -  // Heap number map check.
 | 
| -  __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
 | 
| -         factory()->heap_number_map());
 | 
| -  if (deoptimize_on_undefined) {
 | 
| -    DeoptimizeIf(not_equal, env);
 | 
| -  } else {
 | 
| -    Label heap_number;
 | 
| -    __ j(equal, &heap_number, Label::kNear);
 | 
| +    // Heap number map check.
 | 
| +    __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
 | 
| +           factory()->heap_number_map());
 | 
| +    if (deoptimize_on_undefined) {
 | 
| +      DeoptimizeIf(not_equal, env);
 | 
| +    } else {
 | 
| +      Label heap_number;
 | 
| +      __ j(equal, &heap_number, Label::kNear);
 | 
|  
 | 
| -    __ cmp(input_reg, factory()->undefined_value());
 | 
| -    DeoptimizeIf(not_equal, env);
 | 
| +      __ cmp(input_reg, factory()->undefined_value());
 | 
| +      DeoptimizeIf(not_equal, env);
 | 
|  
 | 
| -    // Convert undefined to NaN.
 | 
| -    ExternalReference nan =
 | 
| -        ExternalReference::address_of_canonical_non_hole_nan();
 | 
| -    __ movdbl(result_reg, Operand::StaticVariable(nan));
 | 
| -    __ jmp(&done, Label::kNear);
 | 
| +      // Convert undefined to NaN.
 | 
| +      ExternalReference nan =
 | 
| +          ExternalReference::address_of_canonical_non_hole_nan();
 | 
| +      __ movdbl(result_reg, Operand::StaticVariable(nan));
 | 
| +      __ jmp(&done, Label::kNear);
 | 
|  
 | 
| -    __ bind(&heap_number);
 | 
| -  }
 | 
| -  // Heap number to XMM conversion.
 | 
| -  __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
 | 
| -  if (deoptimize_on_minus_zero) {
 | 
| -    XMMRegister xmm_scratch = xmm0;
 | 
| -    __ xorps(xmm_scratch, xmm_scratch);
 | 
| -    __ ucomisd(result_reg, xmm_scratch);
 | 
| -    __ j(not_zero, &done, Label::kNear);
 | 
| -    __ movmskpd(temp_reg, result_reg);
 | 
| -    __ test_b(temp_reg, 1);
 | 
| -    DeoptimizeIf(not_zero, env);
 | 
| +      __ bind(&heap_number);
 | 
| +    }
 | 
| +    // Heap number to XMM conversion.
 | 
| +    __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
 | 
| +    if (deoptimize_on_minus_zero) {
 | 
| +      XMMRegister xmm_scratch = xmm0;
 | 
| +      __ xorps(xmm_scratch, xmm_scratch);
 | 
| +      __ ucomisd(result_reg, xmm_scratch);
 | 
| +      __ j(not_zero, &done, Label::kNear);
 | 
| +      __ movmskpd(temp_reg, result_reg);
 | 
| +      __ test_b(temp_reg, 1);
 | 
| +      DeoptimizeIf(not_zero, env);
 | 
| +    }
 | 
| +    __ jmp(&done, Label::kNear);
 | 
| +  } else if (mode == NUMBER_CANDIDATE_IS_SMI_OR_HOLE) {
 | 
| +    __ test(input_reg, Immediate(kSmiTagMask));
 | 
| +    DeoptimizeIf(not_equal, env);
 | 
| +  } else if (mode == NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE) {
 | 
| +    __ test(input_reg, Immediate(kSmiTagMask));
 | 
| +    __ j(zero, &load_smi);
 | 
| +    ExternalReference hole_nan_reference =
 | 
| +        ExternalReference::address_of_the_hole_nan();
 | 
| +    __ movdbl(result_reg, Operand::StaticVariable(hole_nan_reference));
 | 
| +    __ jmp(&done, Label::kNear);
 | 
| +  } else {
 | 
| +    ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
 | 
|    }
 | 
| -  __ jmp(&done, Label::kNear);
 | 
|  
 | 
|    // Smi to XMM conversion
 | 
|    __ bind(&load_smi);
 | 
| @@ -4889,12 +5021,30 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
 | 
|          instr->hydrogen()->deoptimize_on_minus_zero();
 | 
|      Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
 | 
|  
 | 
| +    NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
 | 
| +    HValue* value = instr->hydrogen()->value();
 | 
| +    if (value->type().IsSmi()) {
 | 
| +      if (value->IsLoadKeyed()) {
 | 
| +        HLoadKeyed* load = HLoadKeyed::cast(value);
 | 
| +        if (load->UsesMustHandleHole()) {
 | 
| +          if (load->hole_mode() == ALLOW_RETURN_HOLE) {
 | 
| +            mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE;
 | 
| +          } else {
 | 
| +            mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE;
 | 
| +          }
 | 
| +        } else {
 | 
| +          mode = NUMBER_CANDIDATE_IS_SMI;
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
|      EmitNumberUntagD(input_reg,
 | 
|                       temp_reg,
 | 
|                       result_reg,
 | 
|                       instr->hydrogen()->deoptimize_on_undefined(),
 | 
|                       deoptimize_on_minus_zero,
 | 
| -                     instr->environment());
 | 
| +                     instr->environment(),
 | 
| +                     mode);
 | 
|    } else {
 | 
|      UNIMPLEMENTED();
 | 
|    }
 | 
| @@ -5287,6 +5437,60 @@ void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void LCodeGen::DoAllocate(LAllocate* instr) {
 | 
| +  class DeferredAllocate: public LDeferredCode {
 | 
| +   public:
 | 
| +    DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
 | 
| +        : LDeferredCode(codegen), instr_(instr) { }
 | 
| +    virtual void Generate() { codegen()->DoDeferredAllocate(instr_); }
 | 
| +    virtual LInstruction* instr() { return instr_; }
 | 
| +   private:
 | 
| +    LAllocate* instr_;
 | 
| +  };
 | 
| +
 | 
| +  DeferredAllocate* deferred =
 | 
| +      new(zone()) DeferredAllocate(this, instr);
 | 
| +
 | 
| +  Register size = ToRegister(instr->size());
 | 
| +  Register result = ToRegister(instr->result());
 | 
| +  Register temp = ToRegister(instr->temp());
 | 
| +
 | 
| +  HAllocate* original_instr = instr->hydrogen();
 | 
| +  if (original_instr->size()->IsConstant()) {
 | 
| +    UNREACHABLE();
 | 
| +  } else {
 | 
| +    // Allocate memory for the object.
 | 
| +    AllocationFlags flags = TAG_OBJECT;
 | 
| +    if (original_instr->MustAllocateDoubleAligned()) {
 | 
| +      flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
 | 
| +    }
 | 
| +    __ AllocateInNewSpace(size, result, temp, no_reg,
 | 
| +                          deferred->entry(), flags);
 | 
| +  }
 | 
| +
 | 
| +  __ bind(deferred->exit());
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
 | 
| +  Register size = ToRegister(instr->size());
 | 
| +  Register result = ToRegister(instr->result());
 | 
| +
 | 
| +  __ SmiTag(size);
 | 
| +  PushSafepointRegistersScope scope(this);
 | 
| +  // TODO(3095996): Get rid of this. For now, we need to make the
 | 
| +  // result register contain a valid pointer because it is already
 | 
| +  // contained in the register pointer map.
 | 
| +  if (!size.is(result)) {
 | 
| +    __ StoreToSafepointRegisterSlot(result, size);
 | 
| +  }
 | 
| +  __ push(size);
 | 
| +  CallRuntimeFromDeferred(
 | 
| +      Runtime::kAllocateInNewSpace, 1, instr, instr->context());
 | 
| +  __ StoreToSafepointRegisterSlot(result, eax);
 | 
| +}
 | 
| +
 | 
| +
 | 
|  void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
 | 
|    ASSERT(ToRegister(instr->context()).is(esi));
 | 
|    Handle<FixedArray> literals(instr->environment()->closure()->literals());
 | 
| 
 |