~ubuntu-branches/ubuntu/saucy/libv8/saucy

« back to all changes in this revision

Viewing changes to src/x64/lithium-codegen-x64.cc

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2012-04-07 16:26:13 UTC
  • mfrom: (15.1.27 sid)
  • Revision ID: package-import@ubuntu.com-20120407162613-dqo1m6w9r3fh8tst
Tags: 3.8.9.16-3
* mipsel build fixes :
  + v8_use_mips_abi_hardfloat=false, this lowers EABI requirements.
  + v8_can_use_fpu_instructions=false, detect if FPU is present.
  + set -Wno-unused-but-set-variable only on mipsel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2011 the V8 project authors. All rights reserved.
 
1
// Copyright 2012 the V8 project authors. All rights reserved.
2
2
// Redistribution and use in source and binary forms, with or without
3
3
// modification, are permitted provided that the following conditions are
4
4
// met:
368
368
 
369
369
  WriteTranslation(environment->outer(), translation);
370
370
  int closure_id = DefineDeoptimizationLiteral(environment->closure());
371
 
  translation->BeginFrame(environment->ast_id(), closure_id, height);
 
371
  if (environment->is_arguments_adaptor()) {
 
372
    translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
 
373
  } else {
 
374
    translation->BeginJSFrame(environment->ast_id(), closure_id, height);
 
375
  }
372
376
  for (int i = 0; i < translation_size; ++i) {
373
377
    LOperand* value = environment->values()->at(i);
374
378
    // spilled_registers_ and spilled_double_registers_ are either
504
508
    // |>------------  translation_size ------------<|
505
509
 
506
510
    int frame_count = 0;
 
511
    int jsframe_count = 0;
507
512
    for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
508
513
      ++frame_count;
 
514
      if (!e->is_arguments_adaptor()) {
 
515
        ++jsframe_count;
 
516
      }
509
517
    }
510
 
    Translation translation(&translations_, frame_count);
 
518
    Translation translation(&translations_, frame_count, jsframe_count);
511
519
    WriteTranslation(environment, &translation);
512
520
    int deoptimization_index = deoptimizations_.length();
513
521
    int pc_offset = masm()->pc_offset();
1154
1162
 
1155
1163
 
1156
1164
void LCodeGen::DoConstantT(LConstantT* instr) {
1157
 
  ASSERT(instr->result()->IsRegister());
1158
 
  __ Move(ToRegister(instr->result()), instr->value());
 
1165
  Handle<Object> value = instr->value();
 
1166
  if (value->IsSmi()) {
 
1167
    __ Move(ToRegister(instr->result()), value);
 
1168
  } else {
 
1169
    __ LoadHeapObject(ToRegister(instr->result()),
 
1170
                      Handle<HeapObject>::cast(value));
 
1171
  }
1159
1172
}
1160
1173
 
1161
1174
 
1750
1763
 
1751
1764
 
1752
1765
// Branches to a label or falls through with the answer in the z flag.
1753
 
// Trashes the temp register and possibly input (if it and temp are aliased).
 
1766
// Trashes the temp register.
1754
1767
void LCodeGen::EmitClassOfTest(Label* is_true,
1755
1768
                               Label* is_false,
1756
1769
                               Handle<String> class_name,
1757
1770
                               Register input,
1758
1771
                               Register temp,
1759
 
                               Register scratch) {
 
1772
                               Register temp2) {
 
1773
  ASSERT(!input.is(temp));
 
1774
  ASSERT(!input.is(temp2));
 
1775
  ASSERT(!temp.is(temp2));
 
1776
 
1760
1777
  __ JumpIfSmi(input, is_false);
1761
1778
 
1762
1779
  if (class_name->IsEqualTo(CStrVector("Function"))) {
1777
1794
    // Faster code path to avoid two compares: subtract lower bound from the
1778
1795
    // actual type and do a signed compare with the width of the type range.
1779
1796
    __ movq(temp, FieldOperand(input, HeapObject::kMapOffset));
1780
 
    __ movq(scratch, FieldOperand(temp, Map::kInstanceTypeOffset));
1781
 
    __ subb(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
1782
 
    __ cmpb(scratch,
1783
 
            Immediate(static_cast<int8_t>(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
1784
 
                                          FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)));
 
1797
    __ movzxbl(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
 
1798
    __ subq(temp2, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
 
1799
    __ cmpq(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
 
1800
                             FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
1785
1801
    __ j(above, is_false);
1786
1802
  }
1787
1803
 
1933
1949
    InstanceofStub stub(flags);
1934
1950
 
1935
1951
    __ push(ToRegister(instr->InputAt(0)));
1936
 
    __ Push(instr->function());
 
1952
    __ PushHeapObject(instr->function());
1937
1953
 
1938
1954
    static const int kAdditionalDelta = 10;
1939
1955
    int delta =
2003
2019
 
2004
2020
void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
2005
2021
  Register result = ToRegister(instr->result());
2006
 
  if (result.is(rax)) {
2007
 
    __ load_rax(instr->hydrogen()->cell().location(),
2008
 
                RelocInfo::GLOBAL_PROPERTY_CELL);
2009
 
  } else {
2010
 
    __ movq(result, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL);
2011
 
    __ movq(result, Operand(result, 0));
2012
 
  }
 
2022
  __ LoadGlobalCell(result, instr->hydrogen()->cell());
2013
2023
  if (instr->hydrogen()->RequiresHoleCheck()) {
2014
2024
    __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2015
2025
    DeoptimizeIf(equal, instr->environment());
2030
2040
 
2031
2041
 
2032
2042
void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
2033
 
  Register object = ToRegister(instr->TempAt(0));
2034
 
  Register address = ToRegister(instr->TempAt(1));
2035
 
  Register value = ToRegister(instr->InputAt(0));
2036
 
  ASSERT(!value.is(object));
2037
 
  Handle<JSGlobalPropertyCell> cell_handle(instr->hydrogen()->cell());
2038
 
 
2039
 
  __ movq(address, cell_handle, RelocInfo::GLOBAL_PROPERTY_CELL);
 
2043
  Register value = ToRegister(instr->value());
 
2044
  Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
2040
2045
 
2041
2046
  // If the cell we are storing to contains the hole it could have
2042
2047
  // been deleted from the property dictionary. In that case, we need
2043
2048
  // to update the property details in the property dictionary to mark
2044
2049
  // it as no longer deleted. We deoptimize in that case.
2045
2050
  if (instr->hydrogen()->RequiresHoleCheck()) {
2046
 
    __ CompareRoot(Operand(address, 0), Heap::kTheHoleValueRootIndex);
 
2051
    // We have a temp because CompareRoot might clobber kScratchRegister.
 
2052
    Register cell = ToRegister(instr->TempAt(0));
 
2053
    ASSERT(!value.is(cell));
 
2054
    __ movq(cell, cell_handle, RelocInfo::GLOBAL_PROPERTY_CELL);
 
2055
    __ CompareRoot(Operand(cell, 0), Heap::kTheHoleValueRootIndex);
2047
2056
    DeoptimizeIf(equal, instr->environment());
 
2057
    // Store the value.
 
2058
    __ movq(Operand(cell, 0), value);
 
2059
  } else {
 
2060
    // Store the value.
 
2061
    __ movq(kScratchRegister, cell_handle, RelocInfo::GLOBAL_PROPERTY_CELL);
 
2062
    __ movq(Operand(kScratchRegister, 0), value);
2048
2063
  }
2049
 
 
2050
 
  // Store the value.
2051
 
  __ movq(Operand(address, 0), value);
2052
2064
  // Cells are always rescanned, so no write barrier here.
2053
2065
}
2054
2066
 
2069
2081
  Register context = ToRegister(instr->context());
2070
2082
  Register result = ToRegister(instr->result());
2071
2083
  __ movq(result, ContextOperand(context, instr->slot_index()));
 
2084
  if (instr->hydrogen()->RequiresHoleCheck()) {
 
2085
    __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
 
2086
    if (instr->hydrogen()->DeoptimizesOnHole()) {
 
2087
      DeoptimizeIf(equal, instr->environment());
 
2088
    } else {
 
2089
      Label is_not_hole;
 
2090
      __ j(not_equal, &is_not_hole, Label::kNear);
 
2091
      __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
 
2092
      __ bind(&is_not_hole);
 
2093
    }
 
2094
  }
2072
2095
}
2073
2096
 
2074
2097
 
2075
2098
void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2076
2099
  Register context = ToRegister(instr->context());
2077
2100
  Register value = ToRegister(instr->value());
2078
 
  __ movq(ContextOperand(context, instr->slot_index()), value);
 
2101
 
 
2102
  Operand target = ContextOperand(context, instr->slot_index());
 
2103
 
 
2104
  Label skip_assignment;
 
2105
  if (instr->hydrogen()->RequiresHoleCheck()) {
 
2106
    __ CompareRoot(target, Heap::kTheHoleValueRootIndex);
 
2107
    if (instr->hydrogen()->DeoptimizesOnHole()) {
 
2108
      DeoptimizeIf(equal, instr->environment());
 
2109
    } else {
 
2110
      __ j(not_equal, &skip_assignment);
 
2111
    }
 
2112
  }
 
2113
  __ movq(target, value);
 
2114
 
2079
2115
  if (instr->hydrogen()->NeedsWriteBarrier()) {
2080
2116
    HType type = instr->hydrogen()->value()->type();
2081
2117
    SmiCheck check_needed =
2090
2126
                              EMIT_REMEMBERED_SET,
2091
2127
                              check_needed);
2092
2128
  }
 
2129
 
 
2130
  __ bind(&skip_assignment);
2093
2131
}
2094
2132
 
2095
2133
 
2111
2149
                                               Handle<String> name) {
2112
2150
  LookupResult lookup(isolate());
2113
2151
  type->LookupInDescriptors(NULL, *name, &lookup);
2114
 
  ASSERT(lookup.IsProperty() &&
 
2152
  ASSERT(lookup.IsFound() &&
2115
2153
         (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
2116
2154
  if (lookup.type() == FIELD) {
2117
2155
    int index = lookup.GetLocalFieldIndexFromMap(*type);
2127
2165
    }
2128
2166
  } else {
2129
2167
    Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
2130
 
    LoadHeapObject(result, Handle<HeapObject>::cast(function));
 
2168
    __ LoadHeapObject(result, function);
2131
2169
  }
2132
2170
}
2133
2171
 
2534
2572
  RecordPosition(pointers->position());
2535
2573
  SafepointGenerator safepoint_generator(
2536
2574
      this, pointers, Safepoint::kLazyDeopt);
2537
 
  v8::internal::ParameterCount actual(rax);
 
2575
  ParameterCount actual(rax);
2538
2576
  __ InvokeFunction(function, actual, CALL_FUNCTION,
2539
2577
                    safepoint_generator, CALL_AS_METHOD);
2540
2578
  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2549
2587
 
2550
2588
void LCodeGen::DoThisFunction(LThisFunction* instr) {
2551
2589
  Register result = ToRegister(instr->result());
2552
 
  LoadHeapObject(result, instr->hydrogen()->closure());
 
2590
  __ LoadHeapObject(result, instr->hydrogen()->closure());
2553
2591
}
2554
2592
 
2555
2593
 
2584
2622
                                 int arity,
2585
2623
                                 LInstruction* instr,
2586
2624
                                 CallKind call_kind) {
2587
 
  // Change context if needed.
2588
 
  bool change_context =
2589
 
      (info()->closure()->context() != function->context()) ||
2590
 
      scope()->contains_with() ||
2591
 
      (scope()->num_heap_slots() > 0);
2592
 
  if (change_context) {
2593
 
    __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
2594
 
  }
2595
 
 
2596
 
  // Set rax to arguments count if adaption is not needed. Assumes that rax
2597
 
  // is available to write to at this point.
2598
 
  if (!function->NeedsArgumentsAdaption()) {
2599
 
    __ Set(rax, arity);
2600
 
  }
 
2625
  bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
 
2626
      function->shared()->formal_parameter_count() == arity;
2601
2627
 
2602
2628
  LPointerMap* pointers = instr->pointer_map();
2603
2629
  RecordPosition(pointers->position());
2604
2630
 
2605
 
  // Invoke function.
2606
 
  __ SetCallKind(rcx, call_kind);
2607
 
  if (*function == *info()->closure()) {
2608
 
    __ CallSelf();
 
2631
  if (can_invoke_directly) {
 
2632
    __ LoadHeapObject(rdi, function);
 
2633
 
 
2634
    // Change context if needed.
 
2635
    bool change_context =
 
2636
        (info()->closure()->context() != function->context()) ||
 
2637
        scope()->contains_with() ||
 
2638
        (scope()->num_heap_slots() > 0);
 
2639
    if (change_context) {
 
2640
      __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
 
2641
    }
 
2642
 
 
2643
    // Set rax to arguments count if adaption is not needed. Assumes that rax
 
2644
    // is available to write to at this point.
 
2645
    if (!function->NeedsArgumentsAdaption()) {
 
2646
      __ Set(rax, arity);
 
2647
    }
 
2648
 
 
2649
    // Invoke function.
 
2650
    __ SetCallKind(rcx, call_kind);
 
2651
    if (*function == *info()->closure()) {
 
2652
      __ CallSelf();
 
2653
    } else {
 
2654
      __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset));
 
2655
    }
 
2656
 
 
2657
    // Set up deoptimization.
 
2658
    RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
2609
2659
  } else {
2610
 
    __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset));
 
2660
    // We need to adapt arguments.
 
2661
    SafepointGenerator generator(
 
2662
        this, pointers, Safepoint::kLazyDeopt);
 
2663
    ParameterCount count(arity);
 
2664
    __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
2611
2665
  }
2612
2666
 
2613
 
  // Setup deoptimization.
2614
 
  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
2615
 
 
2616
2667
  // Restore context.
2617
2668
  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2618
2669
}
2620
2671
 
2621
2672
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
2622
2673
  ASSERT(ToRegister(instr->result()).is(rax));
2623
 
  __ Move(rdi, instr->function());
2624
2674
  CallKnownFunction(instr->function(),
2625
2675
                    instr->arity(),
2626
2676
                    instr,
2835
2885
  XMMRegister xmm_scratch = xmm0;
2836
2886
  XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
2837
2887
  ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
 
2888
 
 
2889
  // Note that according to ECMA-262 15.8.2.13:
 
2890
  // Math.pow(-Infinity, 0.5) == Infinity
 
2891
  // Math.sqrt(-Infinity) == NaN
 
2892
  Label done, sqrt;
 
2893
  // Check base for -Infinity.  According to IEEE-754, double-precision
 
2894
  // -Infinity has the highest 12 bits set and the lowest 52 bits cleared.
 
2895
  __ movq(kScratchRegister, V8_INT64_C(0xFFF0000000000000), RelocInfo::NONE);
 
2896
  __ movq(xmm_scratch, kScratchRegister);
 
2897
  __ ucomisd(xmm_scratch, input_reg);
 
2898
  // Comparing -Infinity with NaN results in "unordered", which sets the
 
2899
  // zero flag as if both were equal.  However, it also sets the carry flag.
 
2900
  __ j(not_equal, &sqrt, Label::kNear);
 
2901
  __ j(carry, &sqrt, Label::kNear);
 
2902
  // If input is -Infinity, return Infinity.
 
2903
  __ xorps(input_reg, input_reg);
 
2904
  __ subsd(input_reg, xmm_scratch);
 
2905
  __ jmp(&done, Label::kNear);
 
2906
 
 
2907
  // Square root.
 
2908
  __ bind(&sqrt);
2838
2909
  __ xorps(xmm_scratch, xmm_scratch);
2839
2910
  __ addsd(input_reg, xmm_scratch);  // Convert -0 to +0.
2840
2911
  __ sqrtsd(input_reg, input_reg);
 
2912
  __ bind(&done);
2841
2913
}
2842
2914
 
2843
2915
 
2844
2916
void LCodeGen::DoPower(LPower* instr) {
2845
 
  LOperand* left = instr->InputAt(0);
2846
 
  XMMRegister left_reg = ToDoubleRegister(left);
2847
 
  ASSERT(!left_reg.is(xmm1));
2848
 
  LOperand* right = instr->InputAt(1);
2849
 
  XMMRegister result_reg = ToDoubleRegister(instr->result());
2850
2917
  Representation exponent_type = instr->hydrogen()->right()->representation();
2851
 
  if (exponent_type.IsDouble()) {
2852
 
    __ PrepareCallCFunction(2);
2853
 
    // Move arguments to correct registers
2854
 
    __ movaps(xmm0, left_reg);
2855
 
    ASSERT(ToDoubleRegister(right).is(xmm1));
2856
 
    __ CallCFunction(
2857
 
        ExternalReference::power_double_double_function(isolate()), 2);
 
2918
  // Having marked this as a call, we can use any registers.
 
2919
  // Just make sure that the input/output registers are the expected ones.
 
2920
 
 
2921
  // Choose register conforming to calling convention (when bailing out).
 
2922
#ifdef _WIN64
 
2923
  Register exponent = rdx;
 
2924
#else
 
2925
  Register exponent = rdi;
 
2926
#endif
 
2927
  ASSERT(!instr->InputAt(1)->IsRegister() ||
 
2928
         ToRegister(instr->InputAt(1)).is(exponent));
 
2929
  ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
 
2930
         ToDoubleRegister(instr->InputAt(1)).is(xmm1));
 
2931
  ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm2));
 
2932
  ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
 
2933
 
 
2934
  if (exponent_type.IsTagged()) {
 
2935
    Label no_deopt;
 
2936
    __ JumpIfSmi(exponent, &no_deopt);
 
2937
    __ CmpObjectType(exponent, HEAP_NUMBER_TYPE, rcx);
 
2938
    DeoptimizeIf(not_equal, instr->environment());
 
2939
    __ bind(&no_deopt);
 
2940
    MathPowStub stub(MathPowStub::TAGGED);
 
2941
    __ CallStub(&stub);
2858
2942
  } else if (exponent_type.IsInteger32()) {
2859
 
    __ PrepareCallCFunction(2);
2860
 
    // Move arguments to correct registers: xmm0 and edi (not rdi).
2861
 
    // On Windows, the registers are xmm0 and edx.
2862
 
    __ movaps(xmm0, left_reg);
 
2943
    MathPowStub stub(MathPowStub::INTEGER);
 
2944
    __ CallStub(&stub);
 
2945
  } else {
 
2946
    ASSERT(exponent_type.IsDouble());
 
2947
    MathPowStub stub(MathPowStub::DOUBLE);
 
2948
    __ CallStub(&stub);
 
2949
  }
 
2950
}
 
2951
 
 
2952
 
 
2953
void LCodeGen::DoRandom(LRandom* instr) {
 
2954
  // Having marked this instruction as a call we can use any
 
2955
  // registers.
 
2956
  ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
 
2957
 
 
2958
  // Choose the right register for the first argument depending on
 
2959
  // calling convention.
2863
2960
#ifdef _WIN64
2864
 
    ASSERT(ToRegister(right).is(rdx));
 
2961
  ASSERT(ToRegister(instr->InputAt(0)).is(rcx));
 
2962
  Register global_object = rcx;
2865
2963
#else
2866
 
    ASSERT(ToRegister(right).is(rdi));
 
2964
  ASSERT(ToRegister(instr->InputAt(0)).is(rdi));
 
2965
  Register global_object = rdi;
2867
2966
#endif
2868
 
    __ CallCFunction(
2869
 
        ExternalReference::power_double_int_function(isolate()), 2);
2870
 
  } else {
2871
 
    ASSERT(exponent_type.IsTagged());
2872
 
    Register right_reg = ToRegister(right);
2873
 
 
2874
 
    Label non_smi, call;
2875
 
    __ JumpIfNotSmi(right_reg, &non_smi);
2876
 
    __ SmiToInteger32(right_reg, right_reg);
2877
 
    __ cvtlsi2sd(xmm1, right_reg);
2878
 
    __ jmp(&call);
2879
 
 
2880
 
    __ bind(&non_smi);
2881
 
    __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , kScratchRegister);
2882
 
    DeoptimizeIf(not_equal, instr->environment());
2883
 
    __ movsd(xmm1, FieldOperand(right_reg, HeapNumber::kValueOffset));
2884
 
 
2885
 
    __ bind(&call);
2886
 
    __ PrepareCallCFunction(2);
2887
 
    // Move arguments to correct registers xmm0 and xmm1.
2888
 
    __ movaps(xmm0, left_reg);
2889
 
    // Right argument is already in xmm1.
2890
 
    __ CallCFunction(
2891
 
        ExternalReference::power_double_double_function(isolate()), 2);
2892
 
  }
2893
 
  // Return value is in xmm0.
2894
 
  __ movaps(result_reg, xmm0);
2895
 
  // Restore context register.
 
2967
 
 
2968
  __ PrepareCallCFunction(1);
 
2969
  __ movq(global_object,
 
2970
          FieldOperand(global_object, GlobalObject::kGlobalContextOffset));
 
2971
  __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
2896
2972
  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
 
2973
 
 
2974
  // Convert 32 random bits in rax to 0.(32 random bits) in a double
 
2975
  // by computing:
 
2976
  // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
 
2977
  __ movl(rcx, Immediate(0x49800000));  // 1.0 x 2^20 as single.
 
2978
  __ movd(xmm2, rcx);
 
2979
  __ movd(xmm1, rax);
 
2980
  __ cvtss2sd(xmm2, xmm2);
 
2981
  __ xorps(xmm1, xmm2);
 
2982
  __ subsd(xmm1, xmm2);
2897
2983
}
2898
2984
 
2899
2985
 
3028
3114
 
3029
3115
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3030
3116
  ASSERT(ToRegister(instr->result()).is(rax));
3031
 
  __ Move(rdi, instr->target());
3032
3117
  CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
3033
3118
}
3034
3119
 
3171
3256
  Register elements = ToRegister(instr->object());
3172
3257
  Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3173
3258
 
3174
 
  // This instruction cannot handle the FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
3175
 
  // conversion, so it deopts in that case.
3176
 
  if (instr->hydrogen()->ValueNeedsSmiCheck()) {
3177
 
    Condition cc = masm()->CheckSmi(value);
3178
 
    DeoptimizeIf(NegateCondition(cc), instr->environment());
3179
 
  }
3180
 
 
3181
3259
  // Do the store.
3182
3260
  if (instr->key()->IsConstantOperand()) {
3183
3261
    ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3488
3566
void LCodeGen::EmitNumberUntagD(Register input_reg,
3489
3567
                                XMMRegister result_reg,
3490
3568
                                bool deoptimize_on_undefined,
 
3569
                                bool deoptimize_on_minus_zero,
3491
3570
                                LEnvironment* env) {
3492
3571
  Label load_smi, done;
3493
3572
 
3515
3594
  }
3516
3595
  // Heap number to XMM conversion.
3517
3596
  __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
 
3597
  if (deoptimize_on_minus_zero) {
 
3598
    XMMRegister xmm_scratch = xmm0;
 
3599
    __ xorps(xmm_scratch, xmm_scratch);
 
3600
    __ ucomisd(xmm_scratch, result_reg);
 
3601
    __ j(not_equal, &done, Label::kNear);
 
3602
    __ movmskpd(kScratchRegister, result_reg);
 
3603
    __ testq(kScratchRegister, Immediate(1));
 
3604
    DeoptimizeIf(not_zero, env);
 
3605
  }
3518
3606
  __ jmp(&done, Label::kNear);
3519
3607
 
3520
3608
  // Smi to XMM conversion
3606
3694
 
3607
3695
  EmitNumberUntagD(input_reg, result_reg,
3608
3696
                   instr->hydrogen()->deoptimize_on_undefined(),
 
3697
                   instr->hydrogen()->deoptimize_on_minus_zero(),
3609
3698
                   instr->environment());
3610
3699
}
3611
3700
 
3711
3800
 
3712
3801
 
3713
3802
void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
3714
 
  ASSERT(instr->InputAt(0)->IsRegister());
3715
 
  Register reg = ToRegister(instr->InputAt(0));
3716
 
  __ Cmp(reg, instr->hydrogen()->target());
 
3803
  Register reg = ToRegister(instr->value());
 
3804
  Handle<JSFunction> target = instr->hydrogen()->target();
 
3805
  if (isolate()->heap()->InNewSpace(*target)) {
 
3806
    Handle<JSGlobalPropertyCell> cell =
 
3807
        isolate()->factory()->NewJSGlobalPropertyCell(target);
 
3808
    __ movq(kScratchRegister, cell, RelocInfo::GLOBAL_PROPERTY_CELL);
 
3809
    __ cmpq(reg, Operand(kScratchRegister, 0));
 
3810
  } else {
 
3811
    __ Cmp(reg, target);
 
3812
  }
3717
3813
  DeoptimizeIf(not_equal, instr->environment());
3718
3814
}
3719
3815
 
3720
3816
 
 
3817
void LCodeGen::DoCheckMapCommon(Register reg,
 
3818
                                Handle<Map> map,
 
3819
                                CompareMapMode mode,
 
3820
                                LEnvironment* env) {
 
3821
  Label success;
 
3822
  __ CompareMap(reg, map, &success, mode);
 
3823
  DeoptimizeIf(not_equal, env);
 
3824
  __ bind(&success);
 
3825
}
 
3826
 
 
3827
 
3721
3828
void LCodeGen::DoCheckMap(LCheckMap* instr) {
3722
3829
  LOperand* input = instr->InputAt(0);
3723
3830
  ASSERT(input->IsRegister());
3724
3831
  Register reg = ToRegister(input);
3725
 
  __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
3726
 
         instr->hydrogen()->map());
3727
 
  DeoptimizeIf(not_equal, instr->environment());
 
3832
  Handle<Map> map = instr->hydrogen()->map();
 
3833
  DoCheckMapCommon(reg, map, instr->hydrogen()->mode(), instr->environment());
3728
3834
}
3729
3835
 
3730
3836
 
3779
3885
}
3780
3886
 
3781
3887
 
3782
 
void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
3783
 
  if (heap()->InNewSpace(*object)) {
3784
 
    Handle<JSGlobalPropertyCell> cell =
3785
 
        factory()->NewJSGlobalPropertyCell(object);
3786
 
    __ movq(result, cell, RelocInfo::GLOBAL_PROPERTY_CELL);
3787
 
    __ movq(result, Operand(result, 0));
3788
 
  } else {
3789
 
    __ Move(result, object);
3790
 
  }
3791
 
}
3792
 
 
3793
 
 
3794
3888
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
3795
3889
  Register reg = ToRegister(instr->TempAt(0));
3796
3890
 
3798
3892
  Handle<JSObject> current_prototype = instr->prototype();
3799
3893
 
3800
3894
  // Load prototype object.
3801
 
  LoadHeapObject(reg, current_prototype);
 
3895
  __ LoadHeapObject(reg, current_prototype);
3802
3896
 
3803
3897
  // Check prototype maps up to the holder.
3804
3898
  while (!current_prototype.is_identical_to(holder)) {
3805
 
    __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
3806
 
           Handle<Map>(current_prototype->map()));
3807
 
    DeoptimizeIf(not_equal, instr->environment());
 
3899
    DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
 
3900
                     ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
3808
3901
    current_prototype =
3809
3902
        Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
3810
3903
    // Load next prototype object.
3811
 
    LoadHeapObject(reg, current_prototype);
 
3904
    __ LoadHeapObject(reg, current_prototype);
3812
3905
  }
3813
3906
 
3814
3907
  // Check the holder map.
3815
 
  __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
3816
 
         Handle<Map>(current_prototype->map()));
3817
 
  DeoptimizeIf(not_equal, instr->environment());
 
3908
    DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
 
3909
                     ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
3818
3910
}
3819
3911
 
3820
3912
 
3821
3913
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
3822
 
  Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements();
3823
 
  ASSERT_EQ(2, constant_elements->length());
3824
 
  ElementsKind constant_elements_kind =
3825
 
      static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
3826
 
 
3827
 
  // Setup the parameters to the stub/runtime call.
 
3914
  Heap* heap = isolate()->heap();
 
3915
  ElementsKind boilerplate_elements_kind =
 
3916
      instr->hydrogen()->boilerplate_elements_kind();
 
3917
 
 
3918
  // Deopt if the array literal boilerplate ElementsKind is of a type different
 
3919
  // than the expected one. The check isn't necessary if the boilerplate has
 
3920
  // already been converted to FAST_ELEMENTS.
 
3921
  if (boilerplate_elements_kind != FAST_ELEMENTS) {
 
3922
    __ LoadHeapObject(rax, instr->hydrogen()->boilerplate_object());
 
3923
    __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
 
3924
    // Load the map's "bit field 2".
 
3925
    __ movb(rbx, FieldOperand(rbx, Map::kBitField2Offset));
 
3926
    // Retrieve elements_kind from bit field 2.
 
3927
    __ and_(rbx, Immediate(Map::kElementsKindMask));
 
3928
    __ cmpb(rbx, Immediate(boilerplate_elements_kind <<
 
3929
                           Map::kElementsKindShift));
 
3930
    DeoptimizeIf(not_equal, instr->environment());
 
3931
  }
 
3932
 
 
3933
  // Set up the parameters to the stub/runtime call.
3828
3934
  __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
3829
3935
  __ push(FieldOperand(rax, JSFunction::kLiteralsOffset));
3830
3936
  __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
3831
 
  __ Push(instr->hydrogen()->constant_elements());
 
3937
  // Boilerplate already exists, constant elements are never accessed.
 
3938
  // Pass an empty fixed array.
 
3939
  __ Push(Handle<FixedArray>(heap->empty_fixed_array()));
3832
3940
 
3833
3941
  // Pick the right runtime function or stub to call.
3834
3942
  int length = instr->hydrogen()->length();
3844
3952
    CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
3845
3953
  } else {
3846
3954
    FastCloneShallowArrayStub::Mode mode =
3847
 
        constant_elements_kind == FAST_DOUBLE_ELEMENTS
3848
 
        ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
3849
 
        : FastCloneShallowArrayStub::CLONE_ELEMENTS;
 
3955
        boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
 
3956
            ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
 
3957
            : FastCloneShallowArrayStub::CLONE_ELEMENTS;
3850
3958
    FastCloneShallowArrayStub stub(mode, length);
3851
3959
    CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3852
3960
  }
3885
3993
      Handle<JSObject> value_object = Handle<JSObject>::cast(value);
3886
3994
      __ lea(rcx, Operand(result, *offset));
3887
3995
      __ movq(FieldOperand(result, total_offset), rcx);
3888
 
      LoadHeapObject(source, value_object);
 
3996
      __ LoadHeapObject(source, value_object);
3889
3997
      EmitDeepCopy(value_object, result, source, offset);
3890
3998
    } else if (value->IsHeapObject()) {
3891
 
      LoadHeapObject(rcx, Handle<HeapObject>::cast(value));
 
3999
      __ LoadHeapObject(rcx, Handle<HeapObject>::cast(value));
3892
4000
      __ movq(FieldOperand(result, total_offset), rcx);
3893
4001
    } else {
3894
4002
      __ movq(rcx, value, RelocInfo::NONE);
3913
4021
 
3914
4022
  __ bind(&allocated);
3915
4023
  int offset = 0;
3916
 
  LoadHeapObject(rbx, instr->hydrogen()->boilerplate());
 
4024
  __ LoadHeapObject(rbx, instr->hydrogen()->boilerplate());
3917
4025
  EmitDeepCopy(instr->hydrogen()->boilerplate(), rax, rbx, &offset);
3918
4026
  ASSERT_EQ(size, offset);
3919
4027
}
3923
4031
  Handle<FixedArray> constant_properties =
3924
4032
      instr->hydrogen()->constant_properties();
3925
4033
 
3926
 
  // Setup the parameters to the stub/runtime call.
 
4034
  // Set up the parameters to the stub/runtime call.
3927
4035
  __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
3928
4036
  __ push(FieldOperand(rax, JSFunction::kLiteralsOffset));
3929
4037
  __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
4039
4147
void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
4040
4148
  ASSERT(!operand->IsDoubleRegister());
4041
4149
  if (operand->IsConstantOperand()) {
4042
 
    __ Push(ToHandle(LConstantOperand::cast(operand)));
 
4150
    Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
 
4151
    if (object->IsSmi()) {
 
4152
      __ Push(Handle<Smi>::cast(object));
 
4153
    } else {
 
4154
      __ PushHeapObject(Handle<HeapObject>::cast(object));
 
4155
    }
4043
4156
  } else if (operand->IsRegister()) {
4044
4157
    __ push(ToRegister(operand));
4045
4158
  } else {
4168
4281
  int current_pc = masm()->pc_offset();
4169
4282
  if (current_pc < last_lazy_deopt_pc_ + space_needed) {
4170
4283
    int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
4171
 
    while (padding_size > 0) {
4172
 
      int nop_size = padding_size > 9 ? 9 : padding_size;
4173
 
      __ nop(nop_size);
4174
 
      padding_size -= nop_size;
4175
 
    }
 
4284
    __ Nop(padding_size);
4176
4285
  }
4177
4286
}
4178
4287