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());
2039
__ movq(address, cell_handle, RelocInfo::GLOBAL_PROPERTY_CELL);
2043
Register value = ToRegister(instr->value());
2044
Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
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());
2058
__ movq(Operand(cell, 0), value);
2061
__ movq(kScratchRegister, cell_handle, RelocInfo::GLOBAL_PROPERTY_CELL);
2062
__ movq(Operand(kScratchRegister, 0), value);
2051
__ movq(Operand(address, 0), value);
2052
2064
// Cells are always rescanned, so no write barrier here.
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());
2090
__ j(not_equal, &is_not_hole, Label::kNear);
2091
__ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2092
__ bind(&is_not_hole);
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);
2102
Operand target = ContextOperand(context, instr->slot_index());
2104
Label skip_assignment;
2105
if (instr->hydrogen()->RequiresHoleCheck()) {
2106
__ CompareRoot(target, Heap::kTheHoleValueRootIndex);
2107
if (instr->hydrogen()->DeoptimizesOnHole()) {
2108
DeoptimizeIf(equal, instr->environment());
2110
__ j(not_equal, &skip_assignment);
2113
__ movq(target, value);
2079
2115
if (instr->hydrogen()->NeedsWriteBarrier()) {
2080
2116
HType type = instr->hydrogen()->value()->type();
2081
2117
SmiCheck check_needed =
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));
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()) {
2625
bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
2626
function->shared()->formal_parameter_count() == arity;
2602
2628
LPointerMap* pointers = instr->pointer_map();
2603
2629
RecordPosition(pointers->position());
2606
__ SetCallKind(rcx, call_kind);
2607
if (*function == *info()->closure()) {
2631
if (can_invoke_directly) {
2632
__ LoadHeapObject(rdi, function);
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));
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()) {
2650
__ SetCallKind(rcx, call_kind);
2651
if (*function == *info()->closure()) {
2654
__ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset));
2657
// Set up deoptimization.
2658
RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
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);
2613
// Setup deoptimization.
2614
RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
2616
2667
// Restore context.
2617
2668
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2835
2885
XMMRegister xmm_scratch = xmm0;
2836
2886
XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
2837
2887
ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
2889
// Note that according to ECMA-262 15.8.2.13:
2890
// Math.pow(-Infinity, 0.5) == Infinity
2891
// Math.sqrt(-Infinity) == NaN
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);
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);
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));
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.
2921
// Choose register conforming to calling convention (when bailing out).
2923
Register exponent = rdx;
2925
Register exponent = rdi;
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));
2934
if (exponent_type.IsTagged()) {
2936
__ JumpIfSmi(exponent, &no_deopt);
2937
__ CmpObjectType(exponent, HEAP_NUMBER_TYPE, rcx);
2938
DeoptimizeIf(not_equal, instr->environment());
2940
MathPowStub stub(MathPowStub::TAGGED);
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);
2946
ASSERT(exponent_type.IsDouble());
2947
MathPowStub stub(MathPowStub::DOUBLE);
2953
void LCodeGen::DoRandom(LRandom* instr) {
2954
// Having marked this instruction as a call we can use any
2956
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
2958
// Choose the right register for the first argument depending on
2959
// calling convention.
2864
ASSERT(ToRegister(right).is(rdx));
2961
ASSERT(ToRegister(instr->InputAt(0)).is(rcx));
2962
Register global_object = rcx;
2866
ASSERT(ToRegister(right).is(rdi));
2964
ASSERT(ToRegister(instr->InputAt(0)).is(rdi));
2965
Register global_object = rdi;
2869
ExternalReference::power_double_int_function(isolate()), 2);
2871
ASSERT(exponent_type.IsTagged());
2872
Register right_reg = ToRegister(right);
2874
Label non_smi, call;
2875
__ JumpIfNotSmi(right_reg, &non_smi);
2876
__ SmiToInteger32(right_reg, right_reg);
2877
__ cvtlsi2sd(xmm1, right_reg);
2881
__ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , kScratchRegister);
2882
DeoptimizeIf(not_equal, instr->environment());
2883
__ movsd(xmm1, FieldOperand(right_reg, HeapNumber::kValueOffset));
2886
__ PrepareCallCFunction(2);
2887
// Move arguments to correct registers xmm0 and xmm1.
2888
__ movaps(xmm0, left_reg);
2889
// Right argument is already in xmm1.
2891
ExternalReference::power_double_double_function(isolate()), 2);
2893
// Return value is in xmm0.
2894
__ movaps(result_reg, xmm0);
2895
// Restore context register.
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));
2974
// Convert 32 random bits in rax to 0.(32 random bits) in a double
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.
2980
__ cvtss2sd(xmm2, xmm2);
2981
__ xorps(xmm1, xmm2);
2982
__ subsd(xmm1, xmm2);
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));
3811
__ Cmp(reg, target);
3717
3813
DeoptimizeIf(not_equal, instr->environment());
3817
void LCodeGen::DoCheckMapCommon(Register reg,
3819
CompareMapMode mode,
3820
LEnvironment* env) {
3822
__ CompareMap(reg, map, &success, mode);
3823
DeoptimizeIf(not_equal, env);
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());
3798
3892
Handle<JSObject> current_prototype = instr->prototype();
3800
3894
// Load prototype object.
3801
LoadHeapObject(reg, current_prototype);
3895
__ LoadHeapObject(reg, current_prototype);
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);
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());
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());
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();
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());
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()));
3833
3941
// Pick the right runtime function or stub to call.
3834
3942
int length = instr->hydrogen()->length();