blob: 1e14f83d9b2de1b523d3e87616cd738497bf09f6 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2013 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#if V8_TARGET_ARCH_X64
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/bootstrapper.h"
8#include "src/code-stubs.h"
9#include "src/codegen.h"
10#include "src/ic/handler-compiler.h"
11#include "src/ic/ic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012#include "src/ic/stub-cache.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/isolate.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014#include "src/regexp/jsregexp.h"
15#include "src/regexp/regexp-macro-assembler.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016#include "src/runtime/runtime.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017#include "src/x64/code-stubs-x64.h"
Kristian Monsen80d68ea2010-09-08 11:05:35 +010018
19namespace v8 {
20namespace internal {
21
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022
23static void InitializeArrayConstructorDescriptor(
24 Isolate* isolate, CodeStubDescriptor* descriptor,
25 int constant_stack_parameter_count) {
26 Address deopt_handler = Runtime::FunctionForId(
27 Runtime::kArrayConstructor)->entry;
28
29 if (constant_stack_parameter_count == 0) {
30 descriptor->Initialize(deopt_handler, constant_stack_parameter_count,
31 JS_FUNCTION_STUB_MODE);
32 } else {
33 descriptor->Initialize(rax, deopt_handler, constant_stack_parameter_count,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034 JS_FUNCTION_STUB_MODE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035 }
36}
37
38
39static void InitializeInternalArrayConstructorDescriptor(
40 Isolate* isolate, CodeStubDescriptor* descriptor,
41 int constant_stack_parameter_count) {
42 Address deopt_handler = Runtime::FunctionForId(
43 Runtime::kInternalArrayConstructor)->entry;
44
45 if (constant_stack_parameter_count == 0) {
46 descriptor->Initialize(deopt_handler, constant_stack_parameter_count,
47 JS_FUNCTION_STUB_MODE);
48 } else {
49 descriptor->Initialize(rax, deopt_handler, constant_stack_parameter_count,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000050 JS_FUNCTION_STUB_MODE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051 }
52}
53
54
55void ArrayNoArgumentConstructorStub::InitializeDescriptor(
56 CodeStubDescriptor* descriptor) {
57 InitializeArrayConstructorDescriptor(isolate(), descriptor, 0);
58}
59
60
61void ArraySingleArgumentConstructorStub::InitializeDescriptor(
62 CodeStubDescriptor* descriptor) {
63 InitializeArrayConstructorDescriptor(isolate(), descriptor, 1);
64}
65
66
67void ArrayNArgumentsConstructorStub::InitializeDescriptor(
68 CodeStubDescriptor* descriptor) {
69 InitializeArrayConstructorDescriptor(isolate(), descriptor, -1);
70}
71
72
73void InternalArrayNoArgumentConstructorStub::InitializeDescriptor(
74 CodeStubDescriptor* descriptor) {
75 InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 0);
76}
77
78
79void InternalArraySingleArgumentConstructorStub::InitializeDescriptor(
80 CodeStubDescriptor* descriptor) {
81 InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 1);
82}
83
84
85void InternalArrayNArgumentsConstructorStub::InitializeDescriptor(
86 CodeStubDescriptor* descriptor) {
87 InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, -1);
88}
89
90
Kristian Monsen80d68ea2010-09-08 11:05:35 +010091#define __ ACCESS_MASM(masm)
Steve Block1e0659c2011-05-24 12:43:12 +010092
Ben Murdochb8a8cc12014-11-26 15:28:44 +000093
94void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm,
95 ExternalReference miss) {
96 // Update the static counter each time a new code stub is generated.
97 isolate()->counters()->code_stubs()->Increment();
98
99 CallInterfaceDescriptor descriptor = GetCallInterfaceDescriptor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000100 int param_count = descriptor.GetRegisterParameterCount();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000101 {
102 // Call the runtime system in a fresh internal frame.
103 FrameScope scope(masm, StackFrame::INTERNAL);
104 DCHECK(param_count == 0 ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105 rax.is(descriptor.GetRegisterParameter(param_count - 1)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106 // Push arguments
107 for (int i = 0; i < param_count; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 __ Push(descriptor.GetRegisterParameter(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109 }
110 __ CallExternalReference(miss, param_count);
111 }
112
Steve Block1e0659c2011-05-24 12:43:12 +0100113 __ Ret();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000114}
115
116
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100117void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000118 __ PushCallerSaved(save_doubles() ? kSaveFPRegs : kDontSaveFPRegs);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100119 const int argument_count = 1;
120 __ PrepareCallCFunction(argument_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121 __ LoadAddress(arg_reg_1,
122 ExternalReference::isolate_address(isolate()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100123
124 AllowExternalCallThatCantCauseGC scope(masm);
125 __ CallCFunction(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126 ExternalReference::store_buffer_overflow_function(isolate()),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100127 argument_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128 __ PopCallerSaved(save_doubles() ? kSaveFPRegs : kDontSaveFPRegs);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100129 __ ret(0);
130}
131
132
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100133class FloatingPointHelper : public AllStatic {
134 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000135 enum ConvertUndefined {
136 CONVERT_UNDEFINED_TO_ZERO,
137 BAILOUT_ON_UNDEFINED
138 };
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100139 // Load the operands from rdx and rax into xmm0 and xmm1, as doubles.
140 // If the operands are not both numbers, jump to not_numbers.
141 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis.
142 // NumberOperands assumes both are smis or heap numbers.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100143 static void LoadSSE2UnknownOperands(MacroAssembler* masm,
144 Label* not_numbers);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100145};
146
147
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148void DoubleToIStub::Generate(MacroAssembler* masm) {
149 Register input_reg = this->source();
150 Register final_result_reg = this->destination();
151 DCHECK(is_truncating());
Ben Murdoch257744e2011-11-30 15:57:28 +0000152
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 Label check_negative, process_64_bits, done;
Ben Murdoch257744e2011-11-30 15:57:28 +0000154
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000155 int double_offset = offset();
Ben Murdoch257744e2011-11-30 15:57:28 +0000156
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000157 // Account for return address and saved regs if input is rsp.
158 if (input_reg.is(rsp)) double_offset += 3 * kRegisterSize;
Ben Murdoch257744e2011-11-30 15:57:28 +0000159
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000160 MemOperand mantissa_operand(MemOperand(input_reg, double_offset));
161 MemOperand exponent_operand(MemOperand(input_reg,
162 double_offset + kDoubleSize / 2));
Ben Murdoch257744e2011-11-30 15:57:28 +0000163
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164 Register scratch1;
165 Register scratch_candidates[3] = { rbx, rdx, rdi };
166 for (int i = 0; i < 3; i++) {
167 scratch1 = scratch_candidates[i];
168 if (!final_result_reg.is(scratch1) && !input_reg.is(scratch1)) break;
Steve Block1e0659c2011-05-24 12:43:12 +0100169 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100170
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171 // Since we must use rcx for shifts below, use some other register (rax)
172 // to calculate the result if ecx is the requested return register.
173 Register result_reg = final_result_reg.is(rcx) ? rax : final_result_reg;
174 // Save ecx if it isn't the return register and therefore volatile, or if it
175 // is the return register, then save the temp register we use in its stead
176 // for the result.
177 Register save_reg = final_result_reg.is(rcx) ? rax : rcx;
178 __ pushq(scratch1);
179 __ pushq(save_reg);
180
181 bool stash_exponent_copy = !input_reg.is(rsp);
182 __ movl(scratch1, mantissa_operand);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000183 __ Movsd(xmm0, mantissa_operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184 __ movl(rcx, exponent_operand);
185 if (stash_exponent_copy) __ pushq(rcx);
186
187 __ andl(rcx, Immediate(HeapNumber::kExponentMask));
188 __ shrl(rcx, Immediate(HeapNumber::kExponentShift));
189 __ leal(result_reg, MemOperand(rcx, -HeapNumber::kExponentBias));
190 __ cmpl(result_reg, Immediate(HeapNumber::kMantissaBits));
191 __ j(below, &process_64_bits);
192
193 // Result is entirely in lower 32-bits of mantissa
194 int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize;
195 __ subl(rcx, Immediate(delta));
196 __ xorl(result_reg, result_reg);
197 __ cmpl(rcx, Immediate(31));
198 __ j(above, &done);
199 __ shll_cl(scratch1);
200 __ jmp(&check_negative);
201
202 __ bind(&process_64_bits);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203 __ Cvttsd2siq(result_reg, xmm0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 __ jmp(&done, Label::kNear);
205
206 // If the double was negative, negate the integer result.
207 __ bind(&check_negative);
208 __ movl(result_reg, scratch1);
209 __ negl(result_reg);
210 if (stash_exponent_copy) {
211 __ cmpl(MemOperand(rsp, 0), Immediate(0));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100212 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213 __ cmpl(exponent_operand, Immediate(0));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100214 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 __ cmovl(greater, result_reg, scratch1);
Steve Block1e0659c2011-05-24 12:43:12 +0100216
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217 // Restore registers
Ben Murdochb0fe1622011-05-05 13:52:32 +0100218 __ bind(&done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219 if (stash_exponent_copy) {
220 __ addp(rsp, Immediate(kDoubleSize));
221 }
222 if (!final_result_reg.is(result_reg)) {
223 DCHECK(final_result_reg.is(rcx));
224 __ movl(final_result_reg, result_reg);
225 }
226 __ popq(save_reg);
227 __ popq(scratch1);
228 __ ret(0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100229}
230
231
232void FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm,
233 Label* not_numbers) {
234 Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, load_float_rax, done;
235 // Load operand in rdx into xmm0, or branch to not_numbers.
236 __ LoadRoot(rcx, Heap::kHeapNumberMapRootIndex);
237 __ JumpIfSmi(rdx, &load_smi_rdx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 __ cmpp(FieldOperand(rdx, HeapObject::kMapOffset), rcx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100239 __ j(not_equal, not_numbers); // Argument in rdx is not a number.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000240 __ Movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100241 // Load operand in rax into xmm1, or branch to not_numbers.
242 __ JumpIfSmi(rax, &load_smi_rax);
243
244 __ bind(&load_nonsmi_rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000245 __ cmpp(FieldOperand(rax, HeapObject::kMapOffset), rcx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100246 __ j(not_equal, not_numbers);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 __ Movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100248 __ jmp(&done);
249
250 __ bind(&load_smi_rdx);
251 __ SmiToInteger32(kScratchRegister, rdx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 __ Cvtlsi2sd(xmm0, kScratchRegister);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100253 __ JumpIfNotSmi(rax, &load_nonsmi_rax);
254
255 __ bind(&load_smi_rax);
256 __ SmiToInteger32(kScratchRegister, rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000257 __ Cvtlsi2sd(xmm1, kScratchRegister);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100258 __ bind(&done);
259}
260
261
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100262void MathPowStub::Generate(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263 const Register exponent = MathPowTaggedDescriptor::exponent();
264 DCHECK(exponent.is(rdx));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100265 const Register base = rax;
266 const Register scratch = rcx;
267 const XMMRegister double_result = xmm3;
268 const XMMRegister double_base = xmm2;
269 const XMMRegister double_exponent = xmm1;
270 const XMMRegister double_scratch = xmm4;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100271
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100272 Label call_runtime, done, exponent_not_smi, int_exponent;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100273
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100274 // Save 1 in double_result - we need this several times later on.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000275 __ movp(scratch, Immediate(1));
276 __ Cvtlsi2sd(double_result, scratch);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100277
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278 if (exponent_type() == ON_STACK) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100279 Label base_is_smi, unpack_exponent;
280 // The exponent and base are supplied as arguments on the stack.
281 // This can only happen if the stub is called from non-optimized code.
282 // Load input parameters from stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER);
284 __ movp(base, args.GetArgumentOperand(0));
285 __ movp(exponent, args.GetArgumentOperand(1));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100286 __ JumpIfSmi(base, &base_is_smi, Label::kNear);
287 __ CompareRoot(FieldOperand(base, HeapObject::kMapOffset),
288 Heap::kHeapNumberMapRootIndex);
289 __ j(not_equal, &call_runtime);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100290
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000291 __ Movsd(double_base, FieldOperand(base, HeapNumber::kValueOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100292 __ jmp(&unpack_exponent, Label::kNear);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100293
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100294 __ bind(&base_is_smi);
295 __ SmiToInteger32(base, base);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000296 __ Cvtlsi2sd(double_base, base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100297 __ bind(&unpack_exponent);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100298
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100299 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
300 __ SmiToInteger32(exponent, exponent);
301 __ jmp(&int_exponent);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100302
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100303 __ bind(&exponent_not_smi);
304 __ CompareRoot(FieldOperand(exponent, HeapObject::kMapOffset),
305 Heap::kHeapNumberMapRootIndex);
306 __ j(not_equal, &call_runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307 __ Movsd(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000308 } else if (exponent_type() == TAGGED) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100309 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
310 __ SmiToInteger32(exponent, exponent);
311 __ jmp(&int_exponent);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100312
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100313 __ bind(&exponent_not_smi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000314 __ Movsd(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100315 }
316
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000317 if (exponent_type() != INTEGER) {
318 Label fast_power, try_arithmetic_simplification;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100319 // Detect integer exponents stored as double.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320 __ DoubleToI(exponent, double_exponent, double_scratch,
321 TREAT_MINUS_ZERO_AS_ZERO, &try_arithmetic_simplification,
322 &try_arithmetic_simplification,
323 &try_arithmetic_simplification);
324 __ jmp(&int_exponent);
325
326 __ bind(&try_arithmetic_simplification);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000327 __ Cvttsd2si(exponent, double_exponent);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100328 // Skip to runtime if possibly NaN (indicated by the indefinite integer).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000329 __ cmpl(exponent, Immediate(0x1));
330 __ j(overflow, &call_runtime);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100331
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332 if (exponent_type() == ON_STACK) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100333 // Detect square root case. Crankshaft detects constant +/-0.5 at
334 // compile time and uses DoMathPowHalf instead. We then skip this check
335 // for non-constant cases of +/-0.5 as these hardly occur.
336 Label continue_sqrt, continue_rsqrt, not_plus_half;
337 // Test for 0.5.
338 // Load double_scratch with 0.5.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339 __ movq(scratch, V8_UINT64_C(0x3FE0000000000000));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000340 __ Movq(double_scratch, scratch);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100341 // Already ruled out NaNs for exponent.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342 __ Ucomisd(double_scratch, double_exponent);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100343 __ j(not_equal, &not_plus_half, Label::kNear);
344
345 // Calculates square root of base. Check for the special case of
346 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
347 // According to IEEE-754, double-precision -Infinity has the highest
348 // 12 bits set and the lowest 52 bits cleared.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000349 __ movq(scratch, V8_UINT64_C(0xFFF0000000000000));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000350 __ Movq(double_scratch, scratch);
351 __ Ucomisd(double_scratch, double_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100352 // Comparing -Infinity with NaN results in "unordered", which sets the
353 // zero flag as if both were equal. However, it also sets the carry flag.
354 __ j(not_equal, &continue_sqrt, Label::kNear);
355 __ j(carry, &continue_sqrt, Label::kNear);
356
357 // Set result to Infinity in the special case.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000358 __ Xorpd(double_result, double_result);
359 __ Subsd(double_result, double_scratch);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100360 __ jmp(&done);
361
362 __ bind(&continue_sqrt);
363 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000364 __ Xorpd(double_scratch, double_scratch);
365 __ Addsd(double_scratch, double_base); // Convert -0 to 0.
366 __ Sqrtsd(double_result, double_scratch);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100367 __ jmp(&done);
368
369 // Test for -0.5.
370 __ bind(&not_plus_half);
371 // Load double_scratch with -0.5 by substracting 1.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000372 __ Subsd(double_scratch, double_result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100373 // Already ruled out NaNs for exponent.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000374 __ Ucomisd(double_scratch, double_exponent);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100375 __ j(not_equal, &fast_power, Label::kNear);
376
377 // Calculates reciprocal of square root of base. Check for the special
378 // case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
379 // According to IEEE-754, double-precision -Infinity has the highest
380 // 12 bits set and the lowest 52 bits cleared.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000381 __ movq(scratch, V8_UINT64_C(0xFFF0000000000000));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000382 __ Movq(double_scratch, scratch);
383 __ Ucomisd(double_scratch, double_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100384 // Comparing -Infinity with NaN results in "unordered", which sets the
385 // zero flag as if both were equal. However, it also sets the carry flag.
386 __ j(not_equal, &continue_rsqrt, Label::kNear);
387 __ j(carry, &continue_rsqrt, Label::kNear);
388
389 // Set result to 0 in the special case.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000390 __ Xorpd(double_result, double_result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100391 __ jmp(&done);
392
393 __ bind(&continue_rsqrt);
394 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395 __ Xorpd(double_exponent, double_exponent);
396 __ Addsd(double_exponent, double_base); // Convert -0 to +0.
397 __ Sqrtsd(double_exponent, double_exponent);
398 __ Divsd(double_result, double_exponent);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100399 __ jmp(&done);
400 }
401
402 // Using FPU instructions to calculate power.
403 Label fast_power_failed;
404 __ bind(&fast_power);
405 __ fnclex(); // Clear flags to catch exceptions later.
406 // Transfer (B)ase and (E)xponent onto the FPU register stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000407 __ subp(rsp, Immediate(kDoubleSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000408 __ Movsd(Operand(rsp, 0), double_exponent);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100409 __ fld_d(Operand(rsp, 0)); // E
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410 __ Movsd(Operand(rsp, 0), double_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100411 __ fld_d(Operand(rsp, 0)); // B, E
412
413 // Exponent is in st(1) and base is in st(0)
414 // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B)
415 // FYL2X calculates st(1) * log2(st(0))
416 __ fyl2x(); // X
417 __ fld(0); // X, X
418 __ frndint(); // rnd(X), X
419 __ fsub(1); // rnd(X), X-rnd(X)
420 __ fxch(1); // X - rnd(X), rnd(X)
421 // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
422 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X)
423 __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000424 __ faddp(1); // 2^(X-rnd(X)), rnd(X)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100425 // FSCALE calculates st(0) * 2^st(1)
426 __ fscale(); // 2^X, rnd(X)
427 __ fstp(1);
428 // Bail out to runtime in case of exceptions in the status word.
429 __ fnstsw_ax();
430 __ testb(rax, Immediate(0x5F)); // Check for all but precision exception.
431 __ j(not_zero, &fast_power_failed, Label::kNear);
432 __ fstp_d(Operand(rsp, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000433 __ Movsd(double_result, Operand(rsp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000434 __ addp(rsp, Immediate(kDoubleSize));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100435 __ jmp(&done);
436
437 __ bind(&fast_power_failed);
438 __ fninit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000439 __ addp(rsp, Immediate(kDoubleSize));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100440 __ jmp(&call_runtime);
441 }
442
443 // Calculate power with integer exponent.
444 __ bind(&int_exponent);
445 const XMMRegister double_scratch2 = double_exponent;
446 // Back up exponent as we need to check if exponent is negative later.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000447 __ movp(scratch, exponent); // Back up exponent.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 __ Movsd(double_scratch, double_base); // Back up base.
449 __ Movsd(double_scratch2, double_result); // Load double_exponent with 1.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100450
451 // Get absolute value of exponent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000452 Label no_neg, while_true, while_false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100453 __ testl(scratch, scratch);
454 __ j(positive, &no_neg, Label::kNear);
455 __ negl(scratch);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100456 __ bind(&no_neg);
457
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000458 __ j(zero, &while_false, Label::kNear);
459 __ shrl(scratch, Immediate(1));
460 // Above condition means CF==0 && ZF==0. This means that the
461 // bit that has been shifted out is 0 and the result is not 0.
462 __ j(above, &while_true, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000463 __ Movsd(double_result, double_scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464 __ j(zero, &while_false, Label::kNear);
465
Ben Murdoch85b71792012-04-11 18:30:58 +0100466 __ bind(&while_true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100467 __ shrl(scratch, Immediate(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000468 __ Mulsd(double_scratch, double_scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000469 __ j(above, &while_true, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000470 __ Mulsd(double_result, double_scratch);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100471 __ j(not_zero, &while_true);
472
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000473 __ bind(&while_false);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100474 // If the exponent is negative, return 1/result.
475 __ testl(exponent, exponent);
476 __ j(greater, &done);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 __ Divsd(double_scratch2, double_result);
478 __ Movsd(double_result, double_scratch2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100479 // Test whether result is zero. Bail out to check for subnormal result.
480 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481 __ Xorpd(double_scratch2, double_scratch2);
482 __ Ucomisd(double_scratch2, double_result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100483 // double_exponent aliased as double_scratch2 has already been overwritten
484 // and may not have contained the exponent value in the first place when the
485 // input was a smi. We reset it with exponent value before bailing out.
486 __ j(not_equal, &done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000487 __ Cvtlsi2sd(double_exponent, exponent);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100488
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100489 // Returning or bailing out.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000490 Counters* counters = isolate()->counters();
491 if (exponent_type() == ON_STACK) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100492 // The arguments are still on the stack.
493 __ bind(&call_runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494 __ TailCallRuntime(Runtime::kMathPowRT);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100495
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100496 // The stub is called from non-optimized code, which expects the result
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497 // as heap number in rax.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100498 __ bind(&done);
499 __ AllocateHeapNumber(rax, rcx, &call_runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000500 __ Movsd(FieldOperand(rax, HeapNumber::kValueOffset), double_result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100501 __ IncrementCounter(counters->math_pow(), 1);
502 __ ret(2 * kPointerSize);
503 } else {
504 __ bind(&call_runtime);
505 // Move base to the correct argument register. Exponent is already in xmm1.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000506 __ Movsd(xmm0, double_base);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000507 DCHECK(double_exponent.is(xmm1));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100508 {
509 AllowExternalCallThatCantCauseGC scope(masm);
510 __ PrepareCallCFunction(2);
511 __ CallCFunction(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000512 ExternalReference::power_double_double_function(isolate()), 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100513 }
514 // Return value is in xmm0.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000515 __ Movsd(double_result, xmm0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100516
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100517 __ bind(&done);
518 __ IncrementCounter(counters->math_pow(), 1);
519 __ ret(0);
520 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100521}
522
523
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000524void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
525 Label miss;
526 Register receiver = LoadDescriptor::ReceiverRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400527 // Ensure that the vector and slot registers won't be clobbered before
528 // calling the miss handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000529 DCHECK(!AreAliased(r8, r9, LoadWithVectorDescriptor::VectorRegister(),
530 LoadDescriptor::SlotRegister()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531
532 NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, r8,
533 r9, &miss);
534 __ bind(&miss);
535 PropertyAccessCompiler::TailCallBuiltin(
536 masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
537}
538
539
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100540void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
541 // The key is in rdx and the parameter count is in rax.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000542 DCHECK(rdx.is(ArgumentsAccessReadDescriptor::index()));
543 DCHECK(rax.is(ArgumentsAccessReadDescriptor::parameter_count()));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100544
545 // Check that the key is a smi.
546 Label slow;
547 __ JumpIfNotSmi(rdx, &slow);
548
Steve Block44f0eee2011-05-26 01:26:41 +0100549 // Check if the calling frame is an arguments adaptor frame. We look at the
550 // context offset, and if the frame is not a regular one, then we find a
551 // Smi instead of the context. We can't use SmiCompare here, because that
552 // only works for comparing two smis.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100553 Label adaptor;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000554 __ movp(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
Steve Block44f0eee2011-05-26 01:26:41 +0100555 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
556 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100557 __ j(equal, &adaptor);
558
559 // Check index against formal parameters count limit passed in
560 // through register rax. Use unsigned comparison to get negative
561 // check for free.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000562 __ cmpp(rdx, rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100563 __ j(above_equal, &slow);
564
565 // Read the argument from the stack and return it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 __ SmiSub(rax, rax, rdx);
567 __ SmiToInteger32(rax, rax);
568 StackArgumentsAccessor args(rbp, rax, ARGUMENTS_DONT_CONTAIN_RECEIVER);
569 __ movp(rax, args.GetArgumentOperand(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100570 __ Ret();
571
572 // Arguments adaptor case: Check index against actual arguments
573 // limit found in the arguments adaptor frame. Use unsigned
574 // comparison to get negative check for free.
575 __ bind(&adaptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000576 __ movp(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
577 __ cmpp(rdx, rcx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100578 __ j(above_equal, &slow);
579
580 // Read the argument from the stack and return it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000581 __ SmiSub(rcx, rcx, rdx);
582 __ SmiToInteger32(rcx, rcx);
583 StackArgumentsAccessor adaptor_args(rbx, rcx,
584 ARGUMENTS_DONT_CONTAIN_RECEIVER);
585 __ movp(rax, adaptor_args.GetArgumentOperand(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100586 __ Ret();
587
588 // Slow-case: Handle non-smi or out-of-bounds access to arguments
589 // by calling the runtime system.
590 __ bind(&slow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000591 __ PopReturnAddressTo(rbx);
592 __ Push(rdx);
593 __ PushReturnAddressFrom(rbx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594 __ TailCallRuntime(Runtime::kArguments);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100595}
596
597
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000599 // rcx : number of parameters (tagged)
600 // rdx : parameters pointer
601 // rdi : function
602 // rsp[0] : return address
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000603 // Registers used over the whole function:
604 // rbx: the mapped parameter count (untagged)
605 // rax: the allocated object (tagged).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000606 Factory* factory = isolate()->factory();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000607
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 DCHECK(rdi.is(ArgumentsAccessNewDescriptor::function()));
609 DCHECK(rcx.is(ArgumentsAccessNewDescriptor::parameter_count()));
610 DCHECK(rdx.is(ArgumentsAccessNewDescriptor::parameter_pointer()));
611
612 __ SmiToInteger64(rbx, rcx);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000613 // rbx = parameter count (untagged)
614
615 // Check if the calling frame is an arguments adaptor frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000616 Label adaptor_frame, try_allocate, runtime;
617 __ movp(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
618 __ movp(r8, Operand(rax, StandardFrameConstants::kContextOffset));
619 __ Cmp(r8, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000620 __ j(equal, &adaptor_frame);
621
622 // No adaptor, parameter count = argument count.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623 __ movp(r11, rbx);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000624 __ jmp(&try_allocate, Label::kNear);
625
626 // We have an adaptor frame. Patch the parameters pointer.
627 __ bind(&adaptor_frame);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000628 __ SmiToInteger64(
629 r11, Operand(rax, ArgumentsAdaptorFrameConstants::kLengthOffset));
630 __ leap(rdx, Operand(rax, r11, times_pointer_size,
631 StandardFrameConstants::kCallerSPOffset));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000632
633 // rbx = parameter count (untagged)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000634 // r11 = argument count (untagged)
635 // Compute the mapped parameter count = min(rbx, r11) in rbx.
636 __ cmpp(rbx, r11);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000637 __ j(less_equal, &try_allocate, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000638 __ movp(rbx, r11);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000639
640 __ bind(&try_allocate);
641
642 // Compute the sizes of backing store, parameter map, and arguments object.
643 // 1. Parameter map, has 2 extra words containing context and backing store.
644 const int kParameterMapHeaderSize =
645 FixedArray::kHeaderSize + 2 * kPointerSize;
646 Label no_parameter_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000647 __ xorp(r8, r8);
648 __ testp(rbx, rbx);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000649 __ j(zero, &no_parameter_map, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000650 __ leap(r8, Operand(rbx, times_pointer_size, kParameterMapHeaderSize));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000651 __ bind(&no_parameter_map);
652
653 // 2. Backing store.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 __ leap(r8, Operand(r8, r11, times_pointer_size, FixedArray::kHeaderSize));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000655
656 // 3. Arguments object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000657 __ addp(r8, Immediate(Heap::kSloppyArgumentsObjectSize));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000658
659 // Do the allocation of all three objects in one go.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000660 __ Allocate(r8, rax, r9, no_reg, &runtime, TAG_OBJECT);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000661
662 // rax = address of new object(s) (tagged)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000663 // r11 = argument count (untagged)
664 // Get the arguments map from the current native context into r9.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000665 Label has_mapped_parameters, instantiate;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000666 __ movp(r9, NativeContextOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000667 __ testp(rbx, rbx);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000668 __ j(not_zero, &has_mapped_parameters, Label::kNear);
669
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000670 const int kIndex = Context::SLOPPY_ARGUMENTS_MAP_INDEX;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000671 __ movp(r9, Operand(r9, Context::SlotOffset(kIndex)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000672 __ jmp(&instantiate, Label::kNear);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000673
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000674 const int kAliasedIndex = Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000675 __ bind(&has_mapped_parameters);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000676 __ movp(r9, Operand(r9, Context::SlotOffset(kAliasedIndex)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000677 __ bind(&instantiate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000678
679 // rax = address of new object (tagged)
680 // rbx = mapped parameter count (untagged)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000681 // r11 = argument count (untagged)
682 // r9 = address of arguments map (tagged)
683 __ movp(FieldOperand(rax, JSObject::kMapOffset), r9);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000684 __ LoadRoot(kScratchRegister, Heap::kEmptyFixedArrayRootIndex);
685 __ movp(FieldOperand(rax, JSObject::kPropertiesOffset), kScratchRegister);
686 __ movp(FieldOperand(rax, JSObject::kElementsOffset), kScratchRegister);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000687
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100688 // Set up the callee in-object property.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000689 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000690 __ AssertNotSmi(rdi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000691 __ movp(FieldOperand(rax, JSObject::kHeaderSize +
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000692 Heap::kArgumentsCalleeIndex * kPointerSize),
693 rdi);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000694
695 // Use the length (smi tagged) and set that as an in-object property too.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000696 // Note: r11 is tagged from here on.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000697 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000698 __ Integer32ToSmi(r11, r11);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000699 __ movp(FieldOperand(rax, JSObject::kHeaderSize +
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000700 Heap::kArgumentsLengthIndex * kPointerSize),
701 r11);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000702
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100703 // Set up the elements pointer in the allocated arguments object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000704 // If we allocated a parameter map, rdi will point there, otherwise to the
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000705 // backing store.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706 __ leap(rdi, Operand(rax, Heap::kSloppyArgumentsObjectSize));
707 __ movp(FieldOperand(rax, JSObject::kElementsOffset), rdi);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000708
709 // rax = address of new object (tagged)
710 // rbx = mapped parameter count (untagged)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000711 // r11 = argument count (tagged)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000712 // rdi = address of parameter map or backing store (tagged)
713
714 // Initialize parameter map. If there are no mapped arguments, we're done.
715 Label skip_parameter_map;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000716 __ testp(rbx, rbx);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000717 __ j(zero, &skip_parameter_map);
718
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000719 __ LoadRoot(kScratchRegister, Heap::kSloppyArgumentsElementsMapRootIndex);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000720 // rbx contains the untagged argument count. Add 2 and tag to write.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000721 __ movp(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000722 __ Integer64PlusConstantToSmi(r9, rbx, 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000723 __ movp(FieldOperand(rdi, FixedArray::kLengthOffset), r9);
724 __ movp(FieldOperand(rdi, FixedArray::kHeaderSize + 0 * kPointerSize), rsi);
725 __ leap(r9, Operand(rdi, rbx, times_pointer_size, kParameterMapHeaderSize));
726 __ movp(FieldOperand(rdi, FixedArray::kHeaderSize + 1 * kPointerSize), r9);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000727
728 // Copy the parameter slots and the holes in the arguments.
729 // We need to fill in mapped_parameter_count slots. They index the context,
730 // where parameters are stored in reverse order, at
731 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
732 // The mapped parameter thus need to get indices
733 // MIN_CONTEXT_SLOTS+parameter_count-1 ..
734 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
735 // We loop from right to left.
736 Label parameters_loop, parameters_test;
737
738 // Load tagged parameter count into r9.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100739 __ Integer32ToSmi(r9, rbx);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000740 __ Move(r8, Smi::FromInt(Context::MIN_CONTEXT_SLOTS));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000741 __ addp(r8, rcx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742 __ subp(r8, r9);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000743 __ movp(rcx, rdi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000744 __ leap(rdi, Operand(rdi, rbx, times_pointer_size, kParameterMapHeaderSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000745 __ SmiToInteger64(r9, r9);
746 // r9 = loop variable (untagged)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000747 // r8 = mapping index (tagged)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000748 // rcx = address of parameter map (tagged)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000749 // rdi = address of backing store (tagged)
750 __ jmp(&parameters_test, Label::kNear);
751
752 __ bind(&parameters_loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000753 __ subp(r9, Immediate(1));
754 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
755 __ movp(FieldOperand(rcx, r9, times_pointer_size, kParameterMapHeaderSize),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000756 r8);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000757 __ movp(FieldOperand(rdi, r9, times_pointer_size, FixedArray::kHeaderSize),
758 kScratchRegister);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000759 __ SmiAddConstant(r8, r8, Smi::FromInt(1));
760 __ bind(&parameters_test);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761 __ testp(r9, r9);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000762 __ j(not_zero, &parameters_loop, Label::kNear);
763
764 __ bind(&skip_parameter_map);
765
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000766 // r11 = argument count (tagged)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000767 // rdi = address of backing store (tagged)
768 // Copy arguments header and remaining slots (if there are any).
769 __ Move(FieldOperand(rdi, FixedArray::kMapOffset),
770 factory->fixed_array_map());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000771 __ movp(FieldOperand(rdi, FixedArray::kLengthOffset), r11);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000772
773 Label arguments_loop, arguments_test;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000774 __ movp(r8, rbx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000775 // Untag r11 for the loop below.
776 __ SmiToInteger64(r11, r11);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000777 __ leap(kScratchRegister, Operand(r8, times_pointer_size, 0));
778 __ subp(rdx, kScratchRegister);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000779 __ jmp(&arguments_test, Label::kNear);
780
781 __ bind(&arguments_loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000782 __ subp(rdx, Immediate(kPointerSize));
783 __ movp(r9, Operand(rdx, 0));
784 __ movp(FieldOperand(rdi, r8,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000785 times_pointer_size,
786 FixedArray::kHeaderSize),
787 r9);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000788 __ addp(r8, Immediate(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000789
790 __ bind(&arguments_test);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000791 __ cmpp(r8, r11);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000792 __ j(less, &arguments_loop, Label::kNear);
793
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000794 // Return.
795 __ ret(0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000796
797 // Do the runtime call to allocate the arguments object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000798 // r11 = argument count (untagged)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000799 __ bind(&runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000800 __ Integer32ToSmi(r11, r11);
801 __ PopReturnAddressTo(rax);
802 __ Push(rdi); // Push function.
803 __ Push(rdx); // Push parameters pointer.
804 __ Push(r11); // Push parameter count.
805 __ PushReturnAddressFrom(rax);
806 __ TailCallRuntime(Runtime::kNewSloppyArguments);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000807}
808
809
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000810void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000811 // rcx : number of parameters (tagged)
812 // rdx : parameters pointer
813 // rdi : function
814 // rsp[0] : return address
815
816 DCHECK(rdi.is(ArgumentsAccessNewDescriptor::function()));
817 DCHECK(rcx.is(ArgumentsAccessNewDescriptor::parameter_count()));
818 DCHECK(rdx.is(ArgumentsAccessNewDescriptor::parameter_pointer()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000819
820 // Check if the calling frame is an arguments adaptor frame.
821 Label runtime;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000822 __ movp(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
823 __ movp(rax, Operand(rbx, StandardFrameConstants::kContextOffset));
824 __ Cmp(rax, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000825 __ j(not_equal, &runtime);
826
827 // Patch the arguments.length and the parameters pointer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000828 StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000829 __ movp(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
830 __ SmiToInteger64(rax, rcx);
831 __ leap(rdx, Operand(rbx, rax, times_pointer_size,
832 StandardFrameConstants::kCallerSPOffset));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000833
834 __ bind(&runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000835 __ PopReturnAddressTo(rax);
836 __ Push(rdi); // Push function.
837 __ Push(rdx); // Push parameters pointer.
838 __ Push(rcx); // Push parameter count.
839 __ PushReturnAddressFrom(rax);
840 __ TailCallRuntime(Runtime::kNewSloppyArguments);
841}
842
843
844void RestParamAccessStub::GenerateNew(MacroAssembler* masm) {
845 // rcx : number of parameters (tagged)
846 // rdx : parameters pointer
847 // rbx : rest parameter index (tagged)
848 // rsp[0] : return address
849
850 // Check if the calling frame is an arguments adaptor frame.
851 Label runtime;
852 __ movp(r8, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
853 __ movp(rax, Operand(r8, StandardFrameConstants::kContextOffset));
854 __ Cmp(rax, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
855 __ j(not_equal, &runtime);
856
857 // Patch the arguments.length and the parameters pointer.
858 StackArgumentsAccessor args(rsp, 4, ARGUMENTS_DONT_CONTAIN_RECEIVER);
859 __ movp(rcx, Operand(r8, ArgumentsAdaptorFrameConstants::kLengthOffset));
860 __ SmiToInteger64(rax, rcx);
861 __ leap(rdx, Operand(r8, rax, times_pointer_size,
862 StandardFrameConstants::kCallerSPOffset));
863
864 __ bind(&runtime);
865 __ PopReturnAddressTo(rax);
866 __ Push(rcx); // Push number of parameters.
867 __ Push(rdx); // Push parameters pointer.
868 __ Push(rbx); // Push rest parameter index.
869 __ PushReturnAddressFrom(rax);
870 __ TailCallRuntime(Runtime::kNewRestParam);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000871}
872
873
874void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) {
875 // Return address is on the stack.
876 Label slow;
877
878 Register receiver = LoadDescriptor::ReceiverRegister();
879 Register key = LoadDescriptor::NameRegister();
880 Register scratch = rax;
881 DCHECK(!scratch.is(receiver) && !scratch.is(key));
882
883 // Check that the key is an array index, that is Uint32.
884 STATIC_ASSERT(kSmiValueSize <= 32);
885 __ JumpUnlessNonNegativeSmi(key, &slow);
886
887 // Everything is fine, call runtime.
888 __ PopReturnAddressTo(scratch);
889 __ Push(receiver); // receiver
890 __ Push(key); // key
891 __ PushReturnAddressFrom(scratch);
892
893 // Perform tail call to the entry.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000894 __ TailCallRuntime(Runtime::kLoadElementWithInterceptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000895
896 __ bind(&slow);
897 PropertyAccessCompiler::TailCallBuiltin(
898 masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000899}
900
901
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400902void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
903 // Return address is on the stack.
904 Label miss;
905
906 Register receiver = LoadDescriptor::ReceiverRegister();
907 Register index = LoadDescriptor::NameRegister();
908 Register scratch = rdi;
909 Register result = rax;
910 DCHECK(!scratch.is(receiver) && !scratch.is(index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000911 DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()) &&
912 result.is(LoadDescriptor::SlotRegister()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400913
914 // StringCharAtGenerator doesn't use the result register until it's passed
915 // the different miss possibilities. If it did, we would have a conflict
916 // when FLAG_vector_ics is true.
917 StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
918 &miss, // When not a string.
919 &miss, // When not a number.
920 &miss, // When index out of range.
921 STRING_INDEX_IS_ARRAY_INDEX,
922 RECEIVER_IS_STRING);
923 char_at_generator.GenerateFast(masm);
924 __ ret(0);
925
926 StubRuntimeCallHelper call_helper;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000927 char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400928
929 __ bind(&miss);
930 PropertyAccessCompiler::TailCallBuiltin(
931 masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
932}
933
934
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000935void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000936 // rcx : number of parameters (tagged)
937 // rdx : parameters pointer
938 // rdi : function
939 // rsp[0] : return address
940
941 DCHECK(rdi.is(ArgumentsAccessNewDescriptor::function()));
942 DCHECK(rcx.is(ArgumentsAccessNewDescriptor::parameter_count()));
943 DCHECK(rdx.is(ArgumentsAccessNewDescriptor::parameter_pointer()));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100944
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100945 // Check if the calling frame is an arguments adaptor frame.
946 Label adaptor_frame, try_allocate, runtime;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000947 __ movp(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
948 __ movp(rax, Operand(rbx, StandardFrameConstants::kContextOffset));
949 __ Cmp(rax, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100950 __ j(equal, &adaptor_frame);
951
952 // Get the length from the frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000953 __ SmiToInteger64(rax, rcx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100954 __ jmp(&try_allocate);
955
956 // Patch the arguments.length and the parameters pointer.
957 __ bind(&adaptor_frame);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000958 __ movp(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
959 __ SmiToInteger64(rax, rcx);
960 __ leap(rdx, Operand(rbx, rax, times_pointer_size,
961 StandardFrameConstants::kCallerSPOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100962
963 // Try the new space allocation. Start out with computing the size of
964 // the arguments object and the elements array.
965 Label add_arguments_object;
966 __ bind(&try_allocate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000967 __ testp(rax, rax);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000968 __ j(zero, &add_arguments_object, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000969 __ leap(rax, Operand(rax, times_pointer_size, FixedArray::kHeaderSize));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100970 __ bind(&add_arguments_object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000971 __ addp(rax, Immediate(Heap::kStrictArgumentsObjectSize));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100972
973 // Do the allocation of both objects in one go.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000974 __ Allocate(rax, rax, rbx, no_reg, &runtime, TAG_OBJECT);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100975
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000976 // Get the arguments map from the current native context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000977 __ movp(rdi, NativeContextOperand());
978 __ movp(rdi, ContextOperand(rdi, Context::STRICT_ARGUMENTS_MAP_INDEX));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100979
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000980 __ movp(FieldOperand(rax, JSObject::kMapOffset), rdi);
981 __ LoadRoot(kScratchRegister, Heap::kEmptyFixedArrayRootIndex);
982 __ movp(FieldOperand(rax, JSObject::kPropertiesOffset), kScratchRegister);
983 __ movp(FieldOperand(rax, JSObject::kElementsOffset), kScratchRegister);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100984
985 // Get the length (smi tagged) and set that as an in-object property too.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000986 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000987 __ movp(FieldOperand(rax, JSObject::kHeaderSize +
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000988 Heap::kArgumentsLengthIndex * kPointerSize),
Steve Block44f0eee2011-05-26 01:26:41 +0100989 rcx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100990
991 // If there are no actual arguments, we're done.
992 Label done;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000993 __ testp(rcx, rcx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100994 __ j(zero, &done);
995
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100996 // Set up the elements pointer in the allocated arguments object and
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100997 // initialize the header in the elements fixed array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000998 __ leap(rdi, Operand(rax, Heap::kStrictArgumentsObjectSize));
999 __ movp(FieldOperand(rax, JSObject::kElementsOffset), rdi);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001000 __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001001 __ movp(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001002 __ movp(FieldOperand(rdi, FixedArray::kLengthOffset), rcx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001003
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001004 // Untag the length for the loop below.
1005 __ SmiToInteger64(rcx, rcx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001006
1007 // Copy the fixed array slots.
1008 Label loop;
1009 __ bind(&loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001010 __ movp(rbx, Operand(rdx, -1 * kPointerSize)); // Skip receiver.
1011 __ movp(FieldOperand(rdi, FixedArray::kHeaderSize), rbx);
1012 __ addp(rdi, Immediate(kPointerSize));
1013 __ subp(rdx, Immediate(kPointerSize));
1014 __ decp(rcx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001015 __ j(not_zero, &loop);
1016
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001017 // Return.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001018 __ bind(&done);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001019 __ ret(0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001020
1021 // Do the runtime call to allocate the arguments object.
1022 __ bind(&runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001023 __ PopReturnAddressTo(rax);
1024 __ Push(rdi); // Push function.
1025 __ Push(rdx); // Push parameters pointer.
1026 __ Push(rcx); // Push parameter count.
1027 __ PushReturnAddressFrom(rax);
1028 __ TailCallRuntime(Runtime::kNewStrictArguments);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001029}
1030
1031
1032void RegExpExecStub::Generate(MacroAssembler* masm) {
1033 // Just jump directly to runtime if native RegExp is not selected at compile
1034 // time or if regexp entry in generated code is turned off runtime switch or
1035 // at compilation.
1036#ifdef V8_INTERPRETED_REGEXP
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001037 __ TailCallRuntime(Runtime::kRegExpExec);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001038#else // V8_INTERPRETED_REGEXP
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001039
1040 // Stack frame on entry.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001041 // rsp[0] : return address
1042 // rsp[8] : last_match_info (expected JSArray)
1043 // rsp[16] : previous index
1044 // rsp[24] : subject string
1045 // rsp[32] : JSRegExp object
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001046
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001047 enum RegExpExecStubArgumentIndices {
1048 JS_REG_EXP_OBJECT_ARGUMENT_INDEX,
1049 SUBJECT_STRING_ARGUMENT_INDEX,
1050 PREVIOUS_INDEX_ARGUMENT_INDEX,
1051 LAST_MATCH_INFO_ARGUMENT_INDEX,
1052 REG_EXP_EXEC_ARGUMENT_COUNT
1053 };
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001054
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001055 StackArgumentsAccessor args(rsp, REG_EXP_EXEC_ARGUMENT_COUNT,
1056 ARGUMENTS_DONT_CONTAIN_RECEIVER);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001057 Label runtime;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001058 // Ensure that a RegExp stack is allocated.
1059 ExternalReference address_of_regexp_stack_memory_address =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001060 ExternalReference::address_of_regexp_stack_memory_address(isolate());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001061 ExternalReference address_of_regexp_stack_memory_size =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001062 ExternalReference::address_of_regexp_stack_memory_size(isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01001063 __ Load(kScratchRegister, address_of_regexp_stack_memory_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001064 __ testp(kScratchRegister, kScratchRegister);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001065 __ j(zero, &runtime);
1066
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001067 // Check that the first argument is a JSRegExp object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001068 __ movp(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001069 __ JumpIfSmi(rax, &runtime);
1070 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister);
1071 __ j(not_equal, &runtime);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001072
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001073 // Check that the RegExp has been compiled (data contains a fixed array).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001074 __ movp(rax, FieldOperand(rax, JSRegExp::kDataOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001075 if (FLAG_debug_code) {
Steve Block44f0eee2011-05-26 01:26:41 +01001076 Condition is_smi = masm->CheckSmi(rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001077 __ Check(NegateCondition(is_smi),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001078 kUnexpectedTypeForRegExpDataFixedArrayExpected);
Steve Block44f0eee2011-05-26 01:26:41 +01001079 __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001080 __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001081 }
1082
Steve Block44f0eee2011-05-26 01:26:41 +01001083 // rax: RegExp data (FixedArray)
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001084 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
Steve Block44f0eee2011-05-26 01:26:41 +01001085 __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001086 __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP));
1087 __ j(not_equal, &runtime);
1088
Steve Block44f0eee2011-05-26 01:26:41 +01001089 // rax: RegExp data (FixedArray)
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001090 // Check that the number of captures fit in the static offsets vector buffer.
1091 __ SmiToInteger32(rdx,
Steve Block44f0eee2011-05-26 01:26:41 +01001092 FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001093 // Check (number_of_captures + 1) * 2 <= offsets vector size
1094 // Or number_of_captures <= offsets vector size / 2 - 1
1095 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
1096 __ cmpl(rdx, Immediate(Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001097 __ j(above, &runtime);
1098
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001099 // Reset offset for possibly sliced string.
1100 __ Set(r14, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001101 __ movp(rdi, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX));
1102 __ JumpIfSmi(rdi, &runtime);
1103 __ movp(r15, rdi); // Make a copy of the original subject string.
1104 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001105 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001106 // rax: RegExp data (FixedArray)
1107 // rdi: subject string
1108 // r15: subject string
1109 // Handle subject string according to its encoding and representation:
1110 // (1) Sequential two byte? If yes, go to (9).
1111 // (2) Sequential one byte? If yes, go to (6).
1112 // (3) Anything but sequential or cons? If yes, go to (7).
1113 // (4) Cons string. If the string is flat, replace subject with first string.
1114 // Otherwise bailout.
1115 // (5a) Is subject sequential two byte? If yes, go to (9).
1116 // (5b) Is subject external? If yes, go to (8).
1117 // (6) One byte sequential. Load regexp code for one byte.
1118 // (E) Carry on.
1119 /// [...]
1120
1121 // Deferred code at the end of the stub:
1122 // (7) Not a long external string? If yes, go to (10).
1123 // (8) External string. Make it, offset-wise, look like a sequential string.
1124 // (8a) Is the external string one byte? If yes, go to (6).
1125 // (9) Two byte sequential. Load regexp code for one byte. Go to (E).
1126 // (10) Short external string or not a string? If yes, bail out to runtime.
1127 // (11) Sliced string. Replace subject with parent. Go to (5a).
1128
1129 Label seq_one_byte_string /* 6 */, seq_two_byte_string /* 9 */,
1130 external_string /* 8 */, check_underlying /* 5a */,
1131 not_seq_nor_cons /* 7 */, check_code /* E */,
1132 not_long_external /* 10 */;
1133
1134 // (1) Sequential two byte? If yes, go to (9).
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001135 __ andb(rbx, Immediate(kIsNotStringMask |
1136 kStringRepresentationMask |
1137 kStringEncodingMask |
1138 kShortExternalStringMask));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001139 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001140 __ j(zero, &seq_two_byte_string); // Go to (9).
1141
1142 // (2) Sequential one byte? If yes, go to (6).
1143 // Any other sequential string must be one byte.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001144 __ andb(rbx, Immediate(kIsNotStringMask |
1145 kStringRepresentationMask |
1146 kShortExternalStringMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001147 __ j(zero, &seq_one_byte_string, Label::kNear); // Go to (6).
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001148
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001149 // (3) Anything but sequential or cons? If yes, go to (7).
1150 // We check whether the subject string is a cons, since sequential strings
1151 // have already been covered.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001152 STATIC_ASSERT(kConsStringTag < kExternalStringTag);
1153 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001154 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
1155 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001156 __ cmpp(rbx, Immediate(kExternalStringTag));
1157 __ j(greater_equal, &not_seq_nor_cons); // Go to (7).
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001158
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001159 // (4) Cons string. Check that it's flat.
1160 // Replace subject with first string and reload instance type.
Steve Block44f0eee2011-05-26 01:26:41 +01001161 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001162 Heap::kempty_stringRootIndex);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001163 __ j(not_equal, &runtime);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001164 __ movp(rdi, FieldOperand(rdi, ConsString::kFirstOffset));
1165 __ bind(&check_underlying);
1166 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
1167 __ movp(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
1168
1169 // (5a) Is subject sequential two byte? If yes, go to (9).
1170 __ testb(rbx, Immediate(kStringRepresentationMask | kStringEncodingMask));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001171 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001172 __ j(zero, &seq_two_byte_string); // Go to (9).
1173 // (5b) Is subject external? If yes, go to (8).
1174 __ testb(rbx, Immediate(kStringRepresentationMask));
1175 // The underlying external string is never a short external string.
1176 STATIC_ASSERT(ExternalString::kMaxShortLength < ConsString::kMinLength);
1177 STATIC_ASSERT(ExternalString::kMaxShortLength < SlicedString::kMinLength);
1178 __ j(not_zero, &external_string); // Go to (8)
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001179
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001180 // (6) One byte sequential. Load regexp code for one byte.
1181 __ bind(&seq_one_byte_string);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001182 // rax: RegExp data (FixedArray)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001183 __ movp(r11, FieldOperand(rax, JSRegExp::kDataOneByteCodeOffset));
1184 __ Set(rcx, 1); // Type is one byte.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001185
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001186 // (E) Carry on. String handling is done.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001187 __ bind(&check_code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001188 // r11: irregexp code
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001189 // Check that the irregexp code has been generated for the actual string
1190 // encoding. If it has, the field contains a code object otherwise it contains
Ben Murdoch257744e2011-11-30 15:57:28 +00001191 // smi (code flushing support)
1192 __ JumpIfSmi(r11, &runtime);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001193
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001194 // rdi: sequential subject string (or look-alike, external string)
1195 // r15: original subject string
1196 // rcx: encoding of subject string (1 if one_byte, 0 if two_byte);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001197 // r11: code
1198 // Load used arguments before starting to push arguments for call to native
1199 // RegExp code to avoid handling changing stack height.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001200 // We have to use r15 instead of rdi to load the length because rdi might
1201 // have been only made to look like a sequential string when it actually
1202 // is an external string.
1203 __ movp(rbx, args.GetArgumentOperand(PREVIOUS_INDEX_ARGUMENT_INDEX));
1204 __ JumpIfNotSmi(rbx, &runtime);
1205 __ SmiCompare(rbx, FieldOperand(r15, String::kLengthOffset));
1206 __ j(above_equal, &runtime);
1207 __ SmiToInteger64(rbx, rbx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001208
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001209 // rdi: subject string
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001210 // rbx: previous index
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001211 // rcx: encoding of subject string (1 if one_byte 0 if two_byte);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001212 // r11: code
1213 // All checks done. Now push arguments for native regexp code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001214 Counters* counters = isolate()->counters();
Steve Block44f0eee2011-05-26 01:26:41 +01001215 __ IncrementCounter(counters->regexp_entry_native(), 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001216
Steve Block44f0eee2011-05-26 01:26:41 +01001217 // Isolates: note we add an additional parameter here (isolate pointer).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001218 static const int kRegExpExecuteArguments = 9;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001219 int argument_slots_on_stack =
1220 masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments);
Steve Block44f0eee2011-05-26 01:26:41 +01001221 __ EnterApiExitFrame(argument_slots_on_stack);
1222
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001223 // Argument 9: Pass current isolate address.
1224 __ LoadAddress(kScratchRegister,
1225 ExternalReference::isolate_address(isolate()));
1226 __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kRegisterSize),
Steve Block44f0eee2011-05-26 01:26:41 +01001227 kScratchRegister);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001228
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001229 // Argument 8: Indicate that this is a direct call from JavaScript.
1230 __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kRegisterSize),
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001231 Immediate(1));
1232
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001233 // Argument 7: Start (high end) of backtracking stack memory area.
1234 __ Move(kScratchRegister, address_of_regexp_stack_memory_address);
1235 __ movp(r9, Operand(kScratchRegister, 0));
1236 __ Move(kScratchRegister, address_of_regexp_stack_memory_size);
1237 __ addp(r9, Operand(kScratchRegister, 0));
1238 __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kRegisterSize), r9);
1239
1240 // Argument 6: Set the number of capture registers to zero to force global
1241 // regexps to behave as non-global. This does not affect non-global regexps.
1242 // Argument 6 is passed in r9 on Linux and on the stack on Windows.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001243#ifdef _WIN64
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001244 __ movq(Operand(rsp, (argument_slots_on_stack - 4) * kRegisterSize),
1245 Immediate(0));
1246#else
1247 __ Set(r9, 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001248#endif
1249
1250 // Argument 5: static offsets vector buffer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001251 __ LoadAddress(
1252 r8, ExternalReference::address_of_static_offsets_vector(isolate()));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001253 // Argument 5 passed in r8 on Linux and on the stack on Windows.
1254#ifdef _WIN64
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001255 __ movq(Operand(rsp, (argument_slots_on_stack - 5) * kRegisterSize), r8);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001256#endif
1257
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001258 // rdi: subject string
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001259 // rbx: previous index
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001260 // rcx: encoding of subject string (1 if one_byte 0 if two_byte);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001261 // r11: code
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001262 // r14: slice offset
1263 // r15: original subject string
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001264
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001265 // Argument 2: Previous index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001266 __ movp(arg_reg_2, rbx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001267
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001268 // Argument 4: End of string data
1269 // Argument 3: Start of string data
1270 Label setup_two_byte, setup_rest, got_length, length_not_from_slice;
1271 // Prepare start and end index of the input.
1272 // Load the length from the original sliced string if that is the case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001273 __ addp(rbx, r14);
1274 __ SmiToInteger32(arg_reg_3, FieldOperand(r15, String::kLengthOffset));
1275 __ addp(r14, arg_reg_3); // Using arg3 as scratch.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001276
1277 // rbx: start index of the input
1278 // r14: end index of the input
1279 // r15: original subject string
1280 __ testb(rcx, rcx); // Last use of rcx as encoding of subject string.
1281 __ j(zero, &setup_two_byte, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001282 __ leap(arg_reg_4,
1283 FieldOperand(rdi, r14, times_1, SeqOneByteString::kHeaderSize));
1284 __ leap(arg_reg_3,
1285 FieldOperand(rdi, rbx, times_1, SeqOneByteString::kHeaderSize));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001286 __ jmp(&setup_rest, Label::kNear);
1287 __ bind(&setup_two_byte);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001288 __ leap(arg_reg_4,
1289 FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize));
1290 __ leap(arg_reg_3,
1291 FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001292 __ bind(&setup_rest);
1293
1294 // Argument 1: Original subject string.
1295 // The original subject is in the previous stack frame. Therefore we have to
1296 // use rbp, which points exactly to one pointer size below the previous rsp.
1297 // (Because creating a new stack frame pushes the previous rbp onto the stack
1298 // and thereby moves up rsp by one kPointerSize.)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001299 __ movp(arg_reg_1, r15);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001300
1301 // Locate the code entry and call it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001302 __ addp(r11, Immediate(Code::kHeaderSize - kHeapObjectTag));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001303 __ call(r11);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001304
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001305 __ LeaveApiExitFrame(true);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001306
1307 // Check the result.
Ben Murdoch257744e2011-11-30 15:57:28 +00001308 Label success;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001309 Label exception;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001310 __ cmpl(rax, Immediate(1));
1311 // We expect exactly one result since we force the called regexp to behave
1312 // as non-global.
Ben Murdoch257744e2011-11-30 15:57:28 +00001313 __ j(equal, &success, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001314 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001315 __ j(equal, &exception);
1316 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE));
1317 // If none of the above, it can only be retry.
1318 // Handle that in the runtime system.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001319 __ j(not_equal, &runtime);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001320
1321 // For failure return null.
1322 __ LoadRoot(rax, Heap::kNullValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001323 __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001324
1325 // Load RegExp data.
1326 __ bind(&success);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001327 __ movp(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX));
1328 __ movp(rcx, FieldOperand(rax, JSRegExp::kDataOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001329 __ SmiToInteger32(rax,
1330 FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset));
1331 // Calculate number of capture registers (number_of_captures + 1) * 2.
1332 __ leal(rdx, Operand(rax, rax, times_1, 2));
1333
1334 // rdx: Number of capture registers
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001335 // Check that the fourth object is a JSArray object.
1336 __ movp(r15, args.GetArgumentOperand(LAST_MATCH_INFO_ARGUMENT_INDEX));
1337 __ JumpIfSmi(r15, &runtime);
1338 __ CmpObjectType(r15, JS_ARRAY_TYPE, kScratchRegister);
1339 __ j(not_equal, &runtime);
1340 // Check that the JSArray is in fast case.
1341 __ movp(rbx, FieldOperand(r15, JSArray::kElementsOffset));
1342 __ movp(rax, FieldOperand(rbx, HeapObject::kMapOffset));
1343 __ CompareRoot(rax, Heap::kFixedArrayMapRootIndex);
1344 __ j(not_equal, &runtime);
1345 // Check that the last match info has space for the capture registers and the
1346 // additional information. Ensure no overflow in add.
1347 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset);
1348 __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset));
1349 __ subl(rax, Immediate(RegExpImpl::kLastMatchOverhead));
1350 __ cmpl(rdx, rax);
1351 __ j(greater, &runtime);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001352
1353 // rbx: last_match_info backing store (FixedArray)
1354 // rdx: number of capture registers
1355 // Store the capture count.
1356 __ Integer32ToSmi(kScratchRegister, rdx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001357 __ movp(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset),
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001358 kScratchRegister);
1359 // Store last subject and last input.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001360 __ movp(rax, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX));
1361 __ movp(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax);
1362 __ movp(rcx, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001363 __ RecordWriteField(rbx,
1364 RegExpImpl::kLastSubjectOffset,
1365 rax,
1366 rdi,
1367 kDontSaveFPRegs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001368 __ movp(rax, rcx);
1369 __ movp(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001370 __ RecordWriteField(rbx,
1371 RegExpImpl::kLastInputOffset,
1372 rax,
1373 rdi,
1374 kDontSaveFPRegs);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001375
1376 // Get the static offsets vector filled by the native regexp code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001377 __ LoadAddress(
1378 rcx, ExternalReference::address_of_static_offsets_vector(isolate()));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001379
1380 // rbx: last_match_info backing store (FixedArray)
1381 // rcx: offsets vector
1382 // rdx: number of capture registers
Ben Murdoch257744e2011-11-30 15:57:28 +00001383 Label next_capture, done;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001384 // Capture register counter starts from number of capture registers and
1385 // counts down until wraping after zero.
1386 __ bind(&next_capture);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001387 __ subp(rdx, Immediate(1));
Ben Murdoch257744e2011-11-30 15:57:28 +00001388 __ j(negative, &done, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001389 // Read the value from the static offsets vector buffer and make it a smi.
1390 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001391 __ Integer32ToSmi(rdi, rdi);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001392 // Store the smi value in the last match info.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001393 __ movp(FieldOperand(rbx,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001394 rdx,
1395 times_pointer_size,
1396 RegExpImpl::kFirstCaptureOffset),
1397 rdi);
1398 __ jmp(&next_capture);
1399 __ bind(&done);
1400
1401 // Return last match info.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001402 __ movp(rax, r15);
1403 __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001404
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001405 __ bind(&exception);
1406 // Result must now be exception. If there is no pending exception already a
1407 // stack overflow (on the backtrack stack) was detected in RegExp code but
1408 // haven't created the exception yet. Handle that in the runtime system.
1409 // TODO(592): Rerunning the RegExp to get the stack overflow exception.
Steve Block44f0eee2011-05-26 01:26:41 +01001410 ExternalReference pending_exception_address(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001411 Isolate::kPendingExceptionAddress, isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01001412 Operand pending_exception_operand =
1413 masm->ExternalOperand(pending_exception_address, rbx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001414 __ movp(rax, pending_exception_operand);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001415 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001416 __ cmpp(rax, rdx);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001417 __ j(equal, &runtime);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001418
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001419 // For exception, throw the exception again.
1420 __ TailCallRuntime(Runtime::kRegExpExecReThrow);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001421
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001422 // Do the runtime call to execute the regexp.
1423 __ bind(&runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001424 __ TailCallRuntime(Runtime::kRegExpExec);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001425
1426 // Deferred code for string handling.
1427 // (7) Not a long external string? If yes, go to (10).
1428 __ bind(&not_seq_nor_cons);
1429 // Compare flags are still set from (3).
1430 __ j(greater, &not_long_external, Label::kNear); // Go to (10).
1431
1432 // (8) External string. Short external strings have been ruled out.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001433 __ bind(&external_string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001434 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001435 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
1436 if (FLAG_debug_code) {
1437 // Assert that we do not have a cons or slice (indirect strings) here.
1438 // Sequential strings have already been ruled out.
1439 __ testb(rbx, Immediate(kIsIndirectStringMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001440 __ Assert(zero, kExternalStringExpectedButNotFound);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001441 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001442 __ movp(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001443 // Move the pointer so that offset-wise, it looks like a sequential string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001444 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
1445 __ subp(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001446 STATIC_ASSERT(kTwoByteStringTag == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447 // (8a) Is the external string one byte? If yes, go to (6).
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001448 __ testb(rbx, Immediate(kStringEncodingMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001449 __ j(not_zero, &seq_one_byte_string); // Goto (6).
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001450
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001451 // rdi: subject string (flat two-byte)
1452 // rax: RegExp data (FixedArray)
1453 // (9) Two byte sequential. Load regexp code for one byte. Go to (E).
1454 __ bind(&seq_two_byte_string);
1455 __ movp(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset));
1456 __ Set(rcx, 0); // Type is two byte.
1457 __ jmp(&check_code); // Go to (E).
1458
1459 // (10) Not a string or a short external string? If yes, bail out to runtime.
1460 __ bind(&not_long_external);
1461 // Catch non-string subject or short external string.
1462 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
1463 __ testb(rbx, Immediate(kIsNotStringMask | kShortExternalStringMask));
1464 __ j(not_zero, &runtime);
1465
1466 // (11) Sliced string. Replace subject with parent. Go to (5a).
1467 // Load offset into r14 and replace subject string with parent.
1468 __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset));
1469 __ movp(rdi, FieldOperand(rdi, SlicedString::kParentOffset));
1470 __ jmp(&check_underlying);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001471#endif // V8_INTERPRETED_REGEXP
1472}
1473
1474
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001475static int NegativeComparisonResult(Condition cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476 DCHECK(cc != equal);
1477 DCHECK((cc == less) || (cc == less_equal)
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001478 || (cc == greater) || (cc == greater_equal));
1479 return (cc == greater || cc == greater_equal) ? LESS : GREATER;
1480}
1481
1482
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001483static void CheckInputType(MacroAssembler* masm, Register input,
1484 CompareICState::State expected, Label* fail) {
1485 Label ok;
1486 if (expected == CompareICState::SMI) {
1487 __ JumpIfNotSmi(input, fail);
1488 } else if (expected == CompareICState::NUMBER) {
1489 __ JumpIfSmi(input, &ok);
1490 __ CompareMap(input, masm->isolate()->factory()->heap_number_map());
1491 __ j(not_equal, fail);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001492 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001493 // We could be strict about internalized/non-internalized here, but as long as
1494 // hydrogen doesn't care, the stub doesn't have to care either.
1495 __ bind(&ok);
1496}
1497
1498
1499static void BranchIfNotInternalizedString(MacroAssembler* masm,
1500 Label* label,
1501 Register object,
1502 Register scratch) {
1503 __ JumpIfSmi(object, label);
1504 __ movp(scratch, FieldOperand(object, HeapObject::kMapOffset));
1505 __ movzxbp(scratch,
1506 FieldOperand(scratch, Map::kInstanceTypeOffset));
1507 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
1508 __ testb(scratch, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
1509 __ j(not_zero, label);
1510}
1511
1512
1513void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001514 Label runtime_call, check_unequal_objects, done;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001515 Condition cc = GetCondition();
1516 Factory* factory = isolate()->factory();
1517
1518 Label miss;
1519 CheckInputType(masm, rdx, left(), &miss);
1520 CheckInputType(masm, rax, right(), &miss);
1521
1522 // Compare two smis.
1523 Label non_smi, smi_done;
1524 __ JumpIfNotBothSmi(rax, rdx, &non_smi);
1525 __ subp(rdx, rax);
1526 __ j(no_overflow, &smi_done);
1527 __ notp(rdx); // Correct sign in case of overflow. rdx cannot be 0 here.
1528 __ bind(&smi_done);
1529 __ movp(rax, rdx);
1530 __ ret(0);
1531 __ bind(&non_smi);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001532
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001533 // The compare stub returns a positive, negative, or zero 64-bit integer
1534 // value in rax, corresponding to result of comparing the two inputs.
1535 // NOTICE! This code is only reached after a smi-fast-case check, so
1536 // it is certain that at least one operand isn't a smi.
1537
1538 // Two identical objects are equal unless they are both NaN or undefined.
1539 {
Ben Murdoch257744e2011-11-30 15:57:28 +00001540 Label not_identical;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001541 __ cmpp(rax, rdx);
Ben Murdoch257744e2011-11-30 15:57:28 +00001542 __ j(not_equal, &not_identical, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001543
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001544 if (cc != equal) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001545 // Check for undefined. undefined OP undefined is false even though
1546 // undefined == undefined.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001547 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001548 if (is_strong(strength())) {
1549 // In strong mode, this comparison must throw, so call the runtime.
1550 __ j(equal, &runtime_call, Label::kFar);
1551 } else {
1552 Label check_for_nan;
1553 __ j(not_equal, &check_for_nan, Label::kNear);
1554 __ Set(rax, NegativeComparisonResult(cc));
1555 __ ret(0);
1556 __ bind(&check_for_nan);
1557 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001558 }
1559
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001560 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001561 // so we do the second best thing - test it ourselves.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001562 Label heap_number;
1563 // If it's not a heap number, then return equal for (in)equality operator.
1564 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
1565 factory->heap_number_map());
1566 __ j(equal, &heap_number, Label::kNear);
1567 if (cc != equal) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001568 __ movp(rcx, FieldOperand(rax, HeapObject::kMapOffset));
1569 __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001570 // Call runtime on identical objects. Otherwise return equal.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001571 __ cmpb(rcx, Immediate(static_cast<uint8_t>(FIRST_JS_RECEIVER_TYPE)));
1572 __ j(above_equal, &runtime_call, Label::kFar);
1573 // Call runtime on identical symbols since we need to throw a TypeError.
1574 __ cmpb(rcx, Immediate(static_cast<uint8_t>(SYMBOL_TYPE)));
1575 __ j(equal, &runtime_call, Label::kFar);
1576 // Call runtime on identical SIMD values since we must throw a TypeError.
1577 __ cmpb(rcx, Immediate(static_cast<uint8_t>(SIMD128_VALUE_TYPE)));
1578 __ j(equal, &runtime_call, Label::kFar);
1579 if (is_strong(strength())) {
1580 // We have already tested for smis and heap numbers, so if both
1581 // arguments are not strings we must proceed to the slow case.
1582 __ testb(rcx, Immediate(kIsNotStringMask));
1583 __ j(not_zero, &runtime_call, Label::kFar);
1584 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001585 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001586 __ Set(rax, EQUAL);
1587 __ ret(0);
1588
1589 __ bind(&heap_number);
1590 // It is a heap number, so return equal if it's not NaN.
1591 // For NaN, return 1 for every condition except greater and
1592 // greater-equal. Return -1 for them, so the comparison yields
1593 // false for all conditions except not-equal.
1594 __ Set(rax, EQUAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001595 __ Movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
1596 __ Ucomisd(xmm0, xmm0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001597 __ setcc(parity_even, rax);
1598 // rax is 0 for equal non-NaN heapnumbers, 1 for NaNs.
1599 if (cc == greater_equal || cc == greater) {
1600 __ negp(rax);
1601 }
1602 __ ret(0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001603
1604 __ bind(&not_identical);
1605 }
1606
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001607 if (cc == equal) { // Both strict and non-strict.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001608 Label slow; // Fallthrough label.
1609
1610 // If we're doing a strict equality comparison, we don't have to do
1611 // type conversion, so we generate code to do fast comparison for objects
1612 // and oddballs. Non-smi numbers and strings still go through the usual
1613 // slow-case code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001614 if (strict()) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001615 // If either is a Smi (we know that not both are), then they can only
1616 // be equal if the other is a HeapNumber. If so, use the slow case.
1617 {
1618 Label not_smis;
1619 __ SelectNonSmi(rbx, rax, rdx, &not_smis);
1620
1621 // Check if the non-smi operand is a heap number.
1622 __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
Ben Murdoch257744e2011-11-30 15:57:28 +00001623 factory->heap_number_map());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001624 // If heap number, handle it in the slow case.
1625 __ j(equal, &slow);
1626 // Return non-equal. ebx (the lower half of rbx) is not zero.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001627 __ movp(rax, rbx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001628 __ ret(0);
1629
1630 __ bind(&not_smis);
1631 }
1632
1633 // If either operand is a JSObject or an oddball value, then they are not
1634 // equal since their pointers are different
1635 // There is no test for undetectability in strict equality.
1636
1637 // If the first object is a JS object, we have done pointer comparison.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001638 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
Ben Murdoch257744e2011-11-30 15:57:28 +00001639 Label first_non_object;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001640 __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rcx);
Ben Murdoch257744e2011-11-30 15:57:28 +00001641 __ j(below, &first_non_object, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001642 // Return non-zero (rax (not rax) is not zero)
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001643 Label return_not_equal;
1644 STATIC_ASSERT(kHeapObjectTag != 0);
1645 __ bind(&return_not_equal);
1646 __ ret(0);
1647
1648 __ bind(&first_non_object);
1649 // Check for oddballs: true, false, null, undefined.
1650 __ CmpInstanceType(rcx, ODDBALL_TYPE);
1651 __ j(equal, &return_not_equal);
1652
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001653 __ CmpObjectType(rdx, FIRST_JS_RECEIVER_TYPE, rcx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001654 __ j(above_equal, &return_not_equal);
1655
1656 // Check for oddballs: true, false, null, undefined.
1657 __ CmpInstanceType(rcx, ODDBALL_TYPE);
1658 __ j(equal, &return_not_equal);
1659
1660 // Fall through to the general case.
1661 }
1662 __ bind(&slow);
1663 }
1664
1665 // Generate the number comparison code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001666 Label non_number_comparison;
1667 Label unordered;
1668 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison);
1669 __ xorl(rax, rax);
1670 __ xorl(rcx, rcx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001671 __ Ucomisd(xmm0, xmm1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001672
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001673 // Don't base result on EFLAGS when a NaN is involved.
1674 __ j(parity_even, &unordered, Label::kNear);
1675 // Return a result of -1, 0, or 1, based on EFLAGS.
1676 __ setcc(above, rax);
1677 __ setcc(below, rcx);
1678 __ subp(rax, rcx);
1679 __ ret(0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001680
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001681 // If one of the numbers was NaN, then the result is always false.
1682 // The cc is never not-equal.
1683 __ bind(&unordered);
1684 DCHECK(cc != not_equal);
1685 if (cc == less || cc == less_equal) {
1686 __ Set(rax, 1);
1687 } else {
1688 __ Set(rax, -1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001689 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001690 __ ret(0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001691
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001692 // The number comparison code did not provide a valid result.
1693 __ bind(&non_number_comparison);
1694
1695 // Fast negative check for internalized-to-internalized equality.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001696 Label check_for_strings;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001697 if (cc == equal) {
1698 BranchIfNotInternalizedString(
1699 masm, &check_for_strings, rax, kScratchRegister);
1700 BranchIfNotInternalizedString(
1701 masm, &check_for_strings, rdx, kScratchRegister);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001702
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001703 // We've already checked for object identity, so if both operands are
1704 // internalized strings they aren't equal. Register rax (not rax) already
1705 // holds a non-zero value, which indicates not equal, so just return.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001706 __ ret(0);
1707 }
1708
1709 __ bind(&check_for_strings);
1710
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001711 __ JumpIfNotBothSequentialOneByteStrings(rdx, rax, rcx, rbx,
1712 &check_unequal_objects);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001713
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001714 // Inline comparison of one-byte strings.
1715 if (cc == equal) {
1716 StringHelper::GenerateFlatOneByteStringEquals(masm, rdx, rax, rcx, rbx);
Ben Murdoch257744e2011-11-30 15:57:28 +00001717 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001718 StringHelper::GenerateCompareFlatOneByteStrings(masm, rdx, rax, rcx, rbx,
1719 rdi, r8);
Ben Murdoch257744e2011-11-30 15:57:28 +00001720 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001721
1722#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001723 __ Abort(kUnexpectedFallThroughFromStringComparison);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001724#endif
1725
1726 __ bind(&check_unequal_objects);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001727 if (cc == equal && !strict()) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001728 // Not strict equality. Objects are unequal if
1729 // they are both JSObjects and not undetectable,
1730 // and their pointers are different.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001731 Label return_unequal;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001732 // At most one is a smi, so we can test for smi by adding the two.
1733 // A smi plus a heap object has the low bit set, a heap object plus
1734 // a heap object has the low bit clear.
1735 STATIC_ASSERT(kSmiTag == 0);
1736 STATIC_ASSERT(kSmiTagMask == 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001737 __ leap(rcx, Operand(rax, rdx, times_1, 0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001738 __ testb(rcx, Immediate(kSmiTagMask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001739 __ j(not_zero, &runtime_call, Label::kNear);
1740 __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rbx);
1741 __ j(below, &runtime_call, Label::kNear);
1742 __ CmpObjectType(rdx, FIRST_JS_RECEIVER_TYPE, rcx);
1743 __ j(below, &runtime_call, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001744 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
1745 Immediate(1 << Map::kIsUndetectable));
Ben Murdoch257744e2011-11-30 15:57:28 +00001746 __ j(zero, &return_unequal, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001747 __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
1748 Immediate(1 << Map::kIsUndetectable));
Ben Murdoch257744e2011-11-30 15:57:28 +00001749 __ j(zero, &return_unequal, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001750 // The objects are both undetectable, so they both compare as the value
1751 // undefined, and are equal.
1752 __ Set(rax, EQUAL);
1753 __ bind(&return_unequal);
Steve Block1e0659c2011-05-24 12:43:12 +01001754 // Return non-equal by returning the non-zero object pointer in rax,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001755 // or return equal if we fell through to here.
1756 __ ret(0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001757 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001758 __ bind(&runtime_call);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001759
1760 // Push arguments below the return address to prepare jump to builtin.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001761 __ PopReturnAddressTo(rcx);
1762 __ Push(rdx);
1763 __ Push(rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001764
1765 // Figure out which native to call and setup the arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001766 if (cc == equal) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001767 __ PushReturnAddressFrom(rcx);
1768 __ TailCallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001769 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001770 __ Push(Smi::FromInt(NegativeComparisonResult(cc)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001771 __ PushReturnAddressFrom(rcx);
1772 __ TailCallRuntime(is_strong(strength()) ? Runtime::kCompare_Strong
1773 : Runtime::kCompare);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001774 }
1775
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001776 __ bind(&miss);
1777 GenerateMiss(masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001778}
1779
1780
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001781static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
1782 // rax : number of arguments to the construct function
1783 // rbx : feedback vector
1784 // rdx : slot in feedback vector (Smi)
1785 // rdi : the function to call
1786 FrameScope scope(masm, StackFrame::INTERNAL);
1787
1788 // Number-of-arguments register must be smi-tagged to call out.
1789 __ Integer32ToSmi(rax, rax);
1790 __ Push(rax);
1791 __ Push(rdi);
1792 __ Integer32ToSmi(rdx, rdx);
1793 __ Push(rdx);
1794 __ Push(rbx);
1795
1796 __ CallStub(stub);
1797
1798 __ Pop(rbx);
1799 __ Pop(rdx);
1800 __ Pop(rdi);
1801 __ Pop(rax);
1802 __ SmiToInteger32(rax, rax);
1803}
1804
1805
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001806static void GenerateRecordCallTarget(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001807 // Cache the called function in a feedback vector slot. Cache states
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001808 // are uninitialized, monomorphic (indicated by a JSFunction), and
1809 // megamorphic.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001810 // rax : number of arguments to the construct function
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001811 // rbx : feedback vector
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001812 // rdx : slot in feedback vector (Smi)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001813 // rdi : the function to call
1814 Isolate* isolate = masm->isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001815 Label initialize, done, miss, megamorphic, not_array_function,
1816 done_no_smi_convert;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001817
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001818 // Load the cache state into r11.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001819 __ SmiToInteger32(rdx, rdx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001820 __ movp(r11,
1821 FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001822
1823 // A monomorphic cache hit or an already megamorphic state: invoke the
1824 // function without changing the state.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001825 // We don't know if r11 is a WeakCell or a Symbol, but it's harmless to read
1826 // at this position in a symbol (see static asserts in
1827 // type-feedback-vector.h).
1828 Label check_allocation_site;
1829 __ cmpp(rdi, FieldOperand(r11, WeakCell::kValueOffset));
1830 __ j(equal, &done, Label::kFar);
1831 __ CompareRoot(r11, Heap::kmegamorphic_symbolRootIndex);
1832 __ j(equal, &done, Label::kFar);
1833 __ CompareRoot(FieldOperand(r11, HeapObject::kMapOffset),
1834 Heap::kWeakCellMapRootIndex);
1835 __ j(not_equal, &check_allocation_site);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001836
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001837 // If the weak cell is cleared, we have a new chance to become monomorphic.
1838 __ CheckSmi(FieldOperand(r11, WeakCell::kValueOffset));
1839 __ j(equal, &initialize);
1840 __ jmp(&megamorphic);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001841
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001842 __ bind(&check_allocation_site);
1843 // If we came here, we need to see if we are the array function.
1844 // If we didn't have a matching function, and we didn't find the megamorph
1845 // sentinel, then we have in the slot either some other function or an
1846 // AllocationSite.
1847 __ CompareRoot(FieldOperand(r11, 0), Heap::kAllocationSiteMapRootIndex);
1848 __ j(not_equal, &miss);
1849
1850 // Make sure the function is the Array() function
1851 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r11);
1852 __ cmpp(rdi, r11);
1853 __ j(not_equal, &megamorphic);
1854 __ jmp(&done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001855
1856 __ bind(&miss);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001857
1858 // A monomorphic miss (i.e, here the cache is not uninitialized) goes
1859 // megamorphic.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001860 __ CompareRoot(r11, Heap::kuninitialized_symbolRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001861 __ j(equal, &initialize);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001862 // MegamorphicSentinel is an immortal immovable object (undefined) so no
1863 // write-barrier is needed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001864 __ bind(&megamorphic);
1865 __ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
1866 TypeFeedbackVector::MegamorphicSentinel(isolate));
1867 __ jmp(&done);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001868
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001869 // An uninitialized cache is patched with the function or sentinel to
1870 // indicate the ElementsKind if function is the Array constructor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001871 __ bind(&initialize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001872
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001873 // Make sure the function is the Array() function
1874 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r11);
1875 __ cmpp(rdi, r11);
1876 __ j(not_equal, &not_array_function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001877
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001878 CreateAllocationSiteStub create_stub(isolate);
1879 CallStubInRecordCallTarget(masm, &create_stub);
1880 __ jmp(&done_no_smi_convert);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001881
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001882 __ bind(&not_array_function);
1883 CreateWeakCellStub weak_cell_stub(isolate);
1884 CallStubInRecordCallTarget(masm, &weak_cell_stub);
1885 __ jmp(&done_no_smi_convert);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001886
1887 __ bind(&done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001888 __ Integer32ToSmi(rdx, rdx);
1889
1890 __ bind(&done_no_smi_convert);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001891}
1892
1893
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001894void CallConstructStub::Generate(MacroAssembler* masm) {
1895 // rax : number of arguments
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001896 // rbx : feedback vector
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001897 // rdx : slot in feedback vector (Smi)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001898 // rdi : constructor function
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001899
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001900 Label non_function;
1901 // Check that the constructor is not a smi.
1902 __ JumpIfSmi(rdi, &non_function);
1903 // Check that constructor is a JSFunction.
1904 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, r11);
1905 __ j(not_equal, &non_function);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001906
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001907 GenerateRecordCallTarget(masm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001908
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001909 __ SmiToInteger32(rdx, rdx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001910 Label feedback_register_initialized;
1911 // Put the AllocationSite from the feedback vector into rbx, or undefined.
1912 __ movp(rbx,
1913 FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize));
1914 __ CompareRoot(FieldOperand(rbx, 0), Heap::kAllocationSiteMapRootIndex);
1915 __ j(equal, &feedback_register_initialized, Label::kNear);
1916 __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
1917 __ bind(&feedback_register_initialized);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001918
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001919 __ AssertUndefinedOrAllocationSite(rbx);
1920
1921 // Pass new target to construct stub.
1922 __ movp(rdx, rdi);
1923
1924 // Tail call to the function-specific construct stub (still in the caller
1925 // context at this point).
1926 __ movp(rcx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
1927 __ movp(rcx, FieldOperand(rcx, SharedFunctionInfo::kConstructStubOffset));
1928 __ leap(rcx, FieldOperand(rcx, Code::kHeaderSize));
1929 __ jmp(rcx);
1930
1931 __ bind(&non_function);
1932 __ movp(rdx, rdi);
1933 __ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
1934}
1935
1936
1937void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
1938 // rdi - function
1939 // rdx - slot id
1940 // rbx - vector
1941 // rcx - allocation site (loaded from vector[slot]).
1942 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r8);
1943 __ cmpp(rdi, r8);
1944 __ j(not_equal, miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001945
1946 __ movp(rax, Immediate(arg_count()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001947
1948 // Increment the call count for monomorphic function calls.
1949 __ SmiAddConstant(FieldOperand(rbx, rdx, times_pointer_size,
1950 FixedArray::kHeaderSize + kPointerSize),
1951 Smi::FromInt(CallICNexus::kCallCountIncrement));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001952
1953 __ movp(rbx, rcx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001954 __ movp(rdx, rdi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001955 ArrayConstructorStub stub(masm->isolate(), arg_count());
1956 __ TailCallStub(&stub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001957}
1958
1959
1960void CallICStub::Generate(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001961 // ----------- S t a t e -------------
1962 // -- rdi - function
1963 // -- rdx - slot id
1964 // -- rbx - vector
1965 // -----------------------------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001966 Isolate* isolate = masm->isolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001967 Label extra_checks_or_miss, call, call_function;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001968 int argc = arg_count();
1969 StackArgumentsAccessor args(rsp, argc);
1970 ParameterCount actual(argc);
1971
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001972 // The checks. First, does rdi match the recorded monomorphic target?
1973 __ SmiToInteger32(rdx, rdx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001974 __ movp(rcx,
1975 FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize));
1976
1977 // We don't know that we have a weak cell. We might have a private symbol
1978 // or an AllocationSite, but the memory is safe to examine.
1979 // AllocationSite::kTransitionInfoOffset - contains a Smi or pointer to
1980 // FixedArray.
1981 // WeakCell::kValueOffset - contains a JSFunction or Smi(0)
1982 // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not
1983 // computed, meaning that it can't appear to be a pointer. If the low bit is
1984 // 0, then hash is computed, but the 0 bit prevents the field from appearing
1985 // to be a pointer.
1986 STATIC_ASSERT(WeakCell::kSize >= kPointerSize);
1987 STATIC_ASSERT(AllocationSite::kTransitionInfoOffset ==
1988 WeakCell::kValueOffset &&
1989 WeakCell::kValueOffset == Symbol::kHashFieldSlot);
1990
1991 __ cmpp(rdi, FieldOperand(rcx, WeakCell::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001992 __ j(not_equal, &extra_checks_or_miss);
1993
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001994 // The compare above could have been a SMI/SMI comparison. Guard against this
1995 // convincing us that we have a monomorphic JSFunction.
1996 __ JumpIfSmi(rdi, &extra_checks_or_miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001997
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001998 // Increment the call count for monomorphic function calls.
1999 __ SmiAddConstant(FieldOperand(rbx, rdx, times_pointer_size,
2000 FixedArray::kHeaderSize + kPointerSize),
2001 Smi::FromInt(CallICNexus::kCallCountIncrement));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002002
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002003 __ bind(&call_function);
2004 __ Set(rax, argc);
2005 __ Jump(masm->isolate()->builtins()->CallFunction(convert_mode()),
2006 RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002007
2008 __ bind(&extra_checks_or_miss);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002009 Label uninitialized, miss, not_allocation_site;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002010
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002011 __ Cmp(rcx, TypeFeedbackVector::MegamorphicSentinel(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002012 __ j(equal, &call);
2013
2014 // Check if we have an allocation site.
2015 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
2016 Heap::kAllocationSiteMapRootIndex);
2017 __ j(not_equal, &not_allocation_site);
2018
2019 // We have an allocation site.
2020 HandleArrayCase(masm, &miss);
2021
2022 __ bind(&not_allocation_site);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002023
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002024 // The following cases attempt to handle MISS cases without going to the
2025 // runtime.
2026 if (FLAG_trace_ic) {
2027 __ jmp(&miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002028 }
2029
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002030 __ Cmp(rcx, TypeFeedbackVector::UninitializedSentinel(isolate));
2031 __ j(equal, &uninitialized);
2032
2033 // We are going megamorphic. If the feedback is a JSFunction, it is fine
2034 // to handle it here. More complex cases are dealt with in the runtime.
2035 __ AssertNotSmi(rcx);
2036 __ CmpObjectType(rcx, JS_FUNCTION_TYPE, rcx);
2037 __ j(not_equal, &miss);
2038 __ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
2039 TypeFeedbackVector::MegamorphicSentinel(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002040
2041 __ bind(&call);
2042 __ Set(rax, argc);
2043 __ Jump(masm->isolate()->builtins()->Call(convert_mode()),
2044 RelocInfo::CODE_TARGET);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002045
2046 __ bind(&uninitialized);
2047
2048 // We are going monomorphic, provided we actually have a JSFunction.
2049 __ JumpIfSmi(rdi, &miss);
2050
2051 // Goto miss case if we do not have a function.
2052 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
2053 __ j(not_equal, &miss);
2054
2055 // Make sure the function is not the Array() function, which requires special
2056 // behavior on MISS.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002057 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, rcx);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002058 __ cmpp(rdi, rcx);
2059 __ j(equal, &miss);
2060
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002061 // Make sure the function belongs to the same native context.
2062 __ movp(rcx, FieldOperand(rdi, JSFunction::kContextOffset));
2063 __ movp(rcx, ContextOperand(rcx, Context::NATIVE_CONTEXT_INDEX));
2064 __ cmpp(rcx, NativeContextOperand());
2065 __ j(not_equal, &miss);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002067 // Initialize the call counter.
2068 __ Move(FieldOperand(rbx, rdx, times_pointer_size,
2069 FixedArray::kHeaderSize + kPointerSize),
2070 Smi::FromInt(CallICNexus::kCallCountIncrement));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002071
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002072 // Store the function. Use a stub since we need a frame for allocation.
2073 // rbx - vector
2074 // rdx - slot (needs to be in smi form)
2075 // rdi - function
2076 {
2077 FrameScope scope(masm, StackFrame::INTERNAL);
2078 CreateWeakCellStub create_stub(isolate);
2079
2080 __ Integer32ToSmi(rdx, rdx);
2081 __ Push(rdi);
2082 __ CallStub(&create_stub);
2083 __ Pop(rdi);
2084 }
2085
2086 __ jmp(&call_function);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002087
2088 // We are here because tracing is on or we encountered a MISS case we can't
2089 // handle here.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002090 __ bind(&miss);
2091 GenerateMiss(masm);
2092
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002093 __ jmp(&call);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002094
2095 // Unreachable
2096 __ int3();
2097}
2098
2099
2100void CallICStub::GenerateMiss(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002101 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002102
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002103 // Push the receiver and the function and feedback info.
2104 __ Push(rdi);
2105 __ Push(rbx);
2106 __ Integer32ToSmi(rdx, rdx);
2107 __ Push(rdx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002108
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002109 // Call the entry.
2110 __ CallRuntime(Runtime::kCallIC_Miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002111
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002112 // Move result to edi and exit the internal frame.
2113 __ movp(rdi, rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002114}
2115
2116
Steve Block44f0eee2011-05-26 01:26:41 +01002117bool CEntryStub::NeedsImmovableCode() {
2118 return false;
2119}
2120
2121
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002122void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
2123 CEntryStub::GenerateAheadOfTime(isolate);
2124 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
2125 StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002126 // It is important that the store buffer overflow stubs are generated first.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002127 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
2128 CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002129 CreateWeakCellStub::GenerateAheadOfTime(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002130 BinaryOpICStub::GenerateAheadOfTime(isolate);
2131 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002132 StoreFastElementStub::GenerateAheadOfTime(isolate);
2133 TypeofStub::GenerateAheadOfTime(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002134}
2135
2136
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002137void CodeStub::GenerateFPStubs(Isolate* isolate) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002138}
2139
2140
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002141void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
2142 CEntryStub stub(isolate, 1, kDontSaveFPRegs);
2143 stub.GetCode();
2144 CEntryStub save_doubles(isolate, 1, kSaveFPRegs);
2145 save_doubles.GetCode();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002146}
2147
2148
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002149void CEntryStub::Generate(MacroAssembler* masm) {
2150 // rax: number of arguments including receiver
2151 // rbx: pointer to C function (C callee-saved)
2152 // rbp: frame pointer of calling JS frame (restored after C call)
2153 // rsp: stack pointer (restored after C call)
2154 // rsi: current context (restored)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002155 //
2156 // If argv_in_register():
2157 // r15: pointer to the first argument
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002158
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002159 ProfileEntryHookStub::MaybeCallEntryHook(masm);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002160
2161 // Enter the exit frame that transitions from JavaScript to C++.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002162#ifdef _WIN64
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002163 int arg_stack_space = (result_size() < 2 ? 2 : 4);
2164#else // _WIN64
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002165 int arg_stack_space = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002166#endif // _WIN64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002167 if (argv_in_register()) {
2168 DCHECK(!save_doubles());
2169 __ EnterApiExitFrame(arg_stack_space);
2170 // Move argc into r14 (argv is already in r15).
2171 __ movp(r14, rax);
2172 } else {
2173 __ EnterExitFrame(arg_stack_space, save_doubles());
2174 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002175
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002176 // rbx: pointer to builtin function (C callee-saved).
2177 // rbp: frame pointer of exit frame (restored after C call).
2178 // rsp: stack pointer (restored after C call).
2179 // r14: number of arguments including receiver (C callee-saved).
Steve Block44f0eee2011-05-26 01:26:41 +01002180 // r15: argv pointer (C callee-saved).
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002181
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002182 // Simple results returned in rax (both AMD64 and Win64 calling conventions).
2183 // Complex results must be written to address passed as first argument.
2184 // AMD64 calling convention: a struct of two pointers in rax+rdx
2185
2186 // Check stack alignment.
2187 if (FLAG_debug_code) {
2188 __ CheckStackAlignment();
2189 }
2190
2191 // Call C function.
2192#ifdef _WIN64
2193 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9.
2194 // Pass argv and argc as two parameters. The arguments object will
2195 // be created by stubs declared by DECLARE_RUNTIME_FUNCTION().
2196 if (result_size() < 2) {
2197 // Pass a pointer to the Arguments object as the first argument.
2198 // Return result in single register (rax).
2199 __ movp(rcx, r14); // argc.
2200 __ movp(rdx, r15); // argv.
2201 __ Move(r8, ExternalReference::isolate_address(isolate()));
2202 } else {
2203 DCHECK_EQ(2, result_size());
2204 // Pass a pointer to the result location as the first argument.
2205 __ leap(rcx, StackSpaceOperand(2));
2206 // Pass a pointer to the Arguments object as the second argument.
2207 __ movp(rdx, r14); // argc.
2208 __ movp(r8, r15); // argv.
2209 __ Move(r9, ExternalReference::isolate_address(isolate()));
2210 }
2211
2212#else // _WIN64
2213 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9.
2214 __ movp(rdi, r14); // argc.
2215 __ movp(rsi, r15); // argv.
2216 __ Move(rdx, ExternalReference::isolate_address(isolate()));
2217#endif // _WIN64
2218 __ call(rbx);
2219 // Result is in rax - do not destroy this register!
2220
2221#ifdef _WIN64
2222 // If return value is on the stack, pop it to registers.
2223 if (result_size() > 1) {
2224 DCHECK_EQ(2, result_size());
2225 // Read result values stored on stack. Result is stored
2226 // above the four argument mirror slots and the two
2227 // Arguments object slots.
2228 __ movq(rax, Operand(rsp, 6 * kRegisterSize));
2229 __ movq(rdx, Operand(rsp, 7 * kRegisterSize));
2230 }
2231#endif // _WIN64
2232
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002233 // Check result for exception sentinel.
2234 Label exception_returned;
2235 __ CompareRoot(rax, Heap::kExceptionRootIndex);
2236 __ j(equal, &exception_returned);
2237
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002238 // Check that there is no pending exception, otherwise we
2239 // should have returned the exception sentinel.
2240 if (FLAG_debug_code) {
2241 Label okay;
2242 __ LoadRoot(r14, Heap::kTheHoleValueRootIndex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002243 ExternalReference pending_exception_address(
2244 Isolate::kPendingExceptionAddress, isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002245 Operand pending_exception_operand =
2246 masm->ExternalOperand(pending_exception_address);
2247 __ cmpp(r14, pending_exception_operand);
2248 __ j(equal, &okay, Label::kNear);
2249 __ int3();
2250 __ bind(&okay);
2251 }
2252
2253 // Exit the JavaScript to C++ exit frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002254 __ LeaveExitFrame(save_doubles(), !argv_in_register());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002255 __ ret(0);
2256
2257 // Handling of exception.
2258 __ bind(&exception_returned);
2259
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002260 ExternalReference pending_handler_context_address(
2261 Isolate::kPendingHandlerContextAddress, isolate());
2262 ExternalReference pending_handler_code_address(
2263 Isolate::kPendingHandlerCodeAddress, isolate());
2264 ExternalReference pending_handler_offset_address(
2265 Isolate::kPendingHandlerOffsetAddress, isolate());
2266 ExternalReference pending_handler_fp_address(
2267 Isolate::kPendingHandlerFPAddress, isolate());
2268 ExternalReference pending_handler_sp_address(
2269 Isolate::kPendingHandlerSPAddress, isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002270
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002271 // Ask the runtime for help to determine the handler. This will set rax to
2272 // contain the current pending exception, don't clobber it.
2273 ExternalReference find_handler(Runtime::kUnwindAndFindExceptionHandler,
2274 isolate());
2275 {
2276 FrameScope scope(masm, StackFrame::MANUAL);
2277 __ movp(arg_reg_1, Immediate(0)); // argc.
2278 __ movp(arg_reg_2, Immediate(0)); // argv.
2279 __ Move(arg_reg_3, ExternalReference::isolate_address(isolate()));
2280 __ PrepareCallCFunction(3);
2281 __ CallCFunction(find_handler, 3);
2282 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002283
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002284 // Retrieve the handler context, SP and FP.
2285 __ movp(rsi, masm->ExternalOperand(pending_handler_context_address));
2286 __ movp(rsp, masm->ExternalOperand(pending_handler_sp_address));
2287 __ movp(rbp, masm->ExternalOperand(pending_handler_fp_address));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002288
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002289 // If the handler is a JS frame, restore the context to the frame. Note that
2290 // the context will be set to (rsi == 0) for non-JS frames.
2291 Label skip;
2292 __ testp(rsi, rsi);
2293 __ j(zero, &skip, Label::kNear);
2294 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
2295 __ bind(&skip);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002296
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002297 // Compute the handler entry address and jump to it.
2298 __ movp(rdi, masm->ExternalOperand(pending_handler_code_address));
2299 __ movp(rdx, masm->ExternalOperand(pending_handler_offset_address));
2300 __ leap(rdi, FieldOperand(rdi, rdx, times_1, Code::kHeaderSize));
2301 __ jmp(rdi);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002302}
2303
2304
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002305void JSEntryStub::Generate(MacroAssembler* masm) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002306 Label invoke, handler_entry, exit;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002307 Label not_outermost_js, not_outermost_js_2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002308
2309 ProfileEntryHookStub::MaybeCallEntryHook(masm);
2310
Steve Block44f0eee2011-05-26 01:26:41 +01002311 { // NOLINT. Scope block confuses linter.
2312 MacroAssembler::NoRootArrayScope uninitialized_root_register(masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002313 // Set up frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002314 __ pushq(rbp);
2315 __ movp(rbp, rsp);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002316
Steve Block44f0eee2011-05-26 01:26:41 +01002317 // Push the stack frame type marker twice.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002318 int marker = type();
Steve Block44f0eee2011-05-26 01:26:41 +01002319 // Scratch register is neither callee-save, nor an argument register on any
2320 // platform. It's free to use at this point.
2321 // Cannot use smi-register for loading yet.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002322 __ Move(kScratchRegister, Smi::FromInt(marker), Assembler::RelocInfoNone());
2323 __ Push(kScratchRegister); // context slot
2324 __ Push(kScratchRegister); // function slot
2325 // Save callee-saved registers (X64/X32/Win64 calling conventions).
2326 __ pushq(r12);
2327 __ pushq(r13);
2328 __ pushq(r14);
2329 __ pushq(r15);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002330#ifdef _WIN64
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002331 __ pushq(rdi); // Only callee save in Win64 ABI, argument in AMD64 ABI.
2332 __ pushq(rsi); // Only callee save in Win64 ABI, argument in AMD64 ABI.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002333#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002334 __ pushq(rbx);
2335
2336#ifdef _WIN64
2337 // On Win64 XMM6-XMM15 are callee-save
2338 __ subp(rsp, Immediate(EntryFrameConstants::kXMMRegistersBlockSize));
2339 __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 0), xmm6);
2340 __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 1), xmm7);
2341 __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 2), xmm8);
2342 __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 3), xmm9);
2343 __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 4), xmm10);
2344 __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 5), xmm11);
2345 __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 6), xmm12);
2346 __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 7), xmm13);
2347 __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 8), xmm14);
2348 __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 9), xmm15);
2349#endif
Steve Block44f0eee2011-05-26 01:26:41 +01002350
2351 // Set up the roots and smi constant registers.
2352 // Needs to be done before any further smi loads.
Steve Block44f0eee2011-05-26 01:26:41 +01002353 __ InitializeRootRegister();
2354 }
2355
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002356 // Save copies of the top frame descriptor on the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002357 ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01002358 {
2359 Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002360 __ Push(c_entry_fp_operand);
Steve Block44f0eee2011-05-26 01:26:41 +01002361 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002362
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002363 // If this is the outermost JS call, set js_entry_sp value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002364 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01002365 __ Load(rax, js_entry_sp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002366 __ testp(rax, rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002367 __ j(not_zero, &not_outermost_js);
Steve Block053d10c2011-06-13 19:13:29 +01002368 __ Push(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002369 __ movp(rax, rbp);
Steve Block44f0eee2011-05-26 01:26:41 +01002370 __ Store(js_entry_sp, rax);
Steve Block053d10c2011-06-13 19:13:29 +01002371 Label cont;
2372 __ jmp(&cont);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002373 __ bind(&not_outermost_js);
Steve Block053d10c2011-06-13 19:13:29 +01002374 __ Push(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME));
2375 __ bind(&cont);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002376
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002377 // Jump to a faked try block that does the invoke, with a faked catch
2378 // block that sets the pending exception.
2379 __ jmp(&invoke);
2380 __ bind(&handler_entry);
2381 handler_offset_ = handler_entry.pos();
2382 // Caught exception: Store result (exception) in the pending exception
2383 // field in the JSEnv and return a failure sentinel.
Ben Murdoch589d6972011-11-30 16:04:58 +00002384 ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002385 isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01002386 __ Store(pending_exception, rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002387 __ LoadRoot(rax, Heap::kExceptionRootIndex);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002388 __ jmp(&exit);
2389
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002390 // Invoke: Link this frame into the handler chain.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002391 __ bind(&invoke);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002392 __ PushStackHandler();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002393
2394 // Clear any pending exceptions.
Steve Block44f0eee2011-05-26 01:26:41 +01002395 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex);
2396 __ Store(pending_exception, rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002397
2398 // Fake a receiver (NULL).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002399 __ Push(Immediate(0)); // receiver
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002400
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002401 // Invoke the function by calling through JS entry trampoline builtin and
2402 // pop the faked function when we return. We load the address from an
2403 // external reference instead of inlining the call target address directly
2404 // in the code, because the builtin stubs may not have been generated yet
2405 // at the time this code is generated.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002406 if (type() == StackFrame::ENTRY_CONSTRUCT) {
Steve Block44f0eee2011-05-26 01:26:41 +01002407 ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002408 isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01002409 __ Load(rax, construct_entry);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002410 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002411 ExternalReference entry(Builtins::kJSEntryTrampoline, isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01002412 __ Load(rax, entry);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002413 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002414 __ leap(kScratchRegister, FieldOperand(rax, Code::kHeaderSize));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002415 __ call(kScratchRegister);
2416
2417 // Unlink this frame from the handler chain.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002418 __ PopStackHandler();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002419
Steve Block053d10c2011-06-13 19:13:29 +01002420 __ bind(&exit);
Steve Block053d10c2011-06-13 19:13:29 +01002421 // Check if the current stack frame is marked as the outermost JS frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002422 __ Pop(rbx);
Steve Block053d10c2011-06-13 19:13:29 +01002423 __ Cmp(rbx, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002424 __ j(not_equal, &not_outermost_js_2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002425 __ Move(kScratchRegister, js_entry_sp);
2426 __ movp(Operand(kScratchRegister, 0), Immediate(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002427 __ bind(&not_outermost_js_2);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002428
2429 // Restore the top frame descriptor from the stack.
Steve Block053d10c2011-06-13 19:13:29 +01002430 { Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002431 __ Pop(c_entry_fp_operand);
Steve Block44f0eee2011-05-26 01:26:41 +01002432 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002433
2434 // Restore callee-saved registers (X64 conventions).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002435#ifdef _WIN64
2436 // On Win64 XMM6-XMM15 are callee-save
2437 __ movdqu(xmm6, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 0));
2438 __ movdqu(xmm7, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 1));
2439 __ movdqu(xmm8, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 2));
2440 __ movdqu(xmm9, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 3));
2441 __ movdqu(xmm10, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 4));
2442 __ movdqu(xmm11, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 5));
2443 __ movdqu(xmm12, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 6));
2444 __ movdqu(xmm13, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 7));
2445 __ movdqu(xmm14, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 8));
2446 __ movdqu(xmm15, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 9));
2447 __ addp(rsp, Immediate(EntryFrameConstants::kXMMRegistersBlockSize));
2448#endif
2449
2450 __ popq(rbx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002451#ifdef _WIN64
2452 // Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002453 __ popq(rsi);
2454 __ popq(rdi);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002455#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002456 __ popq(r15);
2457 __ popq(r14);
2458 __ popq(r13);
2459 __ popq(r12);
2460 __ addp(rsp, Immediate(2 * kPointerSize)); // remove markers
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002461
2462 // Restore frame pointer and return.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002463 __ popq(rbp);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002464 __ ret(0);
2465}
2466
2467
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002468void InstanceOfStub::Generate(MacroAssembler* masm) {
2469 Register const object = rdx; // Object (lhs).
2470 Register const function = rax; // Function (rhs).
2471 Register const object_map = rcx; // Map of {object}.
2472 Register const function_map = r8; // Map of {function}.
2473 Register const function_prototype = rdi; // Prototype of {function}.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002474
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002475 DCHECK(object.is(InstanceOfDescriptor::LeftRegister()));
2476 DCHECK(function.is(InstanceOfDescriptor::RightRegister()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002477
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002478 // Check if {object} is a smi.
2479 Label object_is_smi;
2480 __ JumpIfSmi(object, &object_is_smi, Label::kNear);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002481
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002482 // Lookup the {function} and the {object} map in the global instanceof cache.
2483 // Note: This is safe because we clear the global instanceof cache whenever
2484 // we change the prototype of any object.
2485 Label fast_case, slow_case;
2486 __ movp(object_map, FieldOperand(object, HeapObject::kMapOffset));
2487 __ CompareRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
2488 __ j(not_equal, &fast_case, Label::kNear);
2489 __ CompareRoot(object_map, Heap::kInstanceofCacheMapRootIndex);
2490 __ j(not_equal, &fast_case, Label::kNear);
2491 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
2492 __ ret(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002493
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002494 // If {object} is a smi we can safely return false if {function} is a JS
2495 // function, otherwise we have to miss to the runtime and throw an exception.
2496 __ bind(&object_is_smi);
2497 __ JumpIfSmi(function, &slow_case);
2498 __ CmpObjectType(function, JS_FUNCTION_TYPE, function_map);
2499 __ j(not_equal, &slow_case);
2500 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
2501 __ ret(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002502
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002503 // Fast-case: The {function} must be a valid JSFunction.
2504 __ bind(&fast_case);
2505 __ JumpIfSmi(function, &slow_case);
2506 __ CmpObjectType(function, JS_FUNCTION_TYPE, function_map);
2507 __ j(not_equal, &slow_case);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002508
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002509 // Ensure that {function} has an instance prototype.
2510 __ testb(FieldOperand(function_map, Map::kBitFieldOffset),
2511 Immediate(1 << Map::kHasNonInstancePrototype));
2512 __ j(not_zero, &slow_case);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002513
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002514 // Get the "prototype" (or initial map) of the {function}.
2515 __ movp(function_prototype,
2516 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2517 __ AssertNotSmi(function_prototype);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002518
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002519 // Resolve the prototype if the {function} has an initial map. Afterwards the
2520 // {function_prototype} will be either the JSReceiver prototype object or the
2521 // hole value, which means that no instances of the {function} were created so
2522 // far and hence we should return false.
2523 Label function_prototype_valid;
2524 Register const function_prototype_map = kScratchRegister;
2525 __ CmpObjectType(function_prototype, MAP_TYPE, function_prototype_map);
2526 __ j(not_equal, &function_prototype_valid, Label::kNear);
2527 __ movp(function_prototype,
2528 FieldOperand(function_prototype, Map::kPrototypeOffset));
2529 __ bind(&function_prototype_valid);
2530 __ AssertNotSmi(function_prototype);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002531
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002532 // Update the global instanceof cache with the current {object} map and
2533 // {function}. The cached answer will be set when it is known below.
2534 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
2535 __ StoreRoot(object_map, Heap::kInstanceofCacheMapRootIndex);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002536
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002537 // Loop through the prototype chain looking for the {function} prototype.
2538 // Assume true, and change to false if not found.
2539 Label done, loop, fast_runtime_fallback;
2540 __ LoadRoot(rax, Heap::kTrueValueRootIndex);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002541 __ bind(&loop);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002542
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002543 __ testb(FieldOperand(object_map, Map::kBitFieldOffset),
2544 Immediate(1 << Map::kIsAccessCheckNeeded));
2545 __ j(not_zero, &fast_runtime_fallback, Label::kNear);
2546 __ CmpInstanceType(object_map, JS_PROXY_TYPE);
2547 __ j(equal, &fast_runtime_fallback, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002548
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002549 __ movp(object, FieldOperand(object_map, Map::kPrototypeOffset));
2550 __ cmpp(object, function_prototype);
2551 __ j(equal, &done, Label::kNear);
2552 __ CompareRoot(object, Heap::kNullValueRootIndex);
2553 __ movp(object_map, FieldOperand(object, HeapObject::kMapOffset));
2554 __ j(not_equal, &loop);
2555 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
2556 __ bind(&done);
2557 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
2558 __ ret(0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002559
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002560 // Found Proxy or access check needed: Call the runtime.
2561 __ bind(&fast_runtime_fallback);
2562 __ PopReturnAddressTo(kScratchRegister);
2563 __ Push(object);
2564 __ Push(function_prototype);
2565 __ PushReturnAddressFrom(kScratchRegister);
2566 // Invalidate the instanceof cache.
2567 __ Move(rax, Smi::FromInt(0));
2568 __ StoreRoot(rax, Heap::kInstanceofCacheFunctionRootIndex);
2569 __ TailCallRuntime(Runtime::kHasInPrototypeChain);
2570
2571 // Slow-case: Call the %InstanceOf runtime function.
2572 __ bind(&slow_case);
2573 __ PopReturnAddressTo(kScratchRegister);
2574 __ Push(object);
2575 __ Push(function);
2576 __ PushReturnAddressFrom(kScratchRegister);
2577 __ TailCallRuntime(Runtime::kInstanceOf);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002578}
2579
2580
2581// -------------------------------------------------------------------------
2582// StringCharCodeAtGenerator
2583
2584void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002585 // If the receiver is a smi trigger the non-string case.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002586 if (check_mode_ == RECEIVER_IS_UNKNOWN) {
2587 __ JumpIfSmi(object_, receiver_not_string_);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002588
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002589 // Fetch the instance type of the receiver into result register.
2590 __ movp(result_, FieldOperand(object_, HeapObject::kMapOffset));
2591 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
2592 // If the receiver is not a string trigger the non-string case.
2593 __ testb(result_, Immediate(kIsNotStringMask));
2594 __ j(not_zero, receiver_not_string_);
2595 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002596
2597 // If the index is non-smi trigger the non-smi case.
2598 __ JumpIfNotSmi(index_, &index_not_smi_);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002599 __ bind(&got_smi_index_);
2600
2601 // Check for index out of range.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002602 __ SmiCompare(index_, FieldOperand(object_, String::kLengthOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002603 __ j(above_equal, index_out_of_range_);
2604
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002605 __ SmiToInteger32(index_, index_);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002606
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002607 StringCharLoadGenerator::Generate(
2608 masm, object_, index_, result_, &call_runtime_);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002609
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002610 __ Integer32ToSmi(result_, result_);
2611 __ bind(&exit_);
2612}
2613
2614
2615void StringCharCodeAtGenerator::GenerateSlow(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002616 MacroAssembler* masm, EmbedMode embed_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002617 const RuntimeCallHelper& call_helper) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002618 __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002619
Ben Murdoch257744e2011-11-30 15:57:28 +00002620 Factory* factory = masm->isolate()->factory();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002621 // Index is not a smi.
2622 __ bind(&index_not_smi_);
2623 // If index is a heap number, try converting it to an integer.
Ben Murdoch257744e2011-11-30 15:57:28 +00002624 __ CheckMap(index_,
2625 factory->heap_number_map(),
2626 index_not_number_,
2627 DONT_DO_SMI_CHECK);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002628 call_helper.BeforeCall(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002629 if (embed_mode == PART_OF_IC_HANDLER) {
2630 __ Push(LoadWithVectorDescriptor::VectorRegister());
2631 __ Push(LoadDescriptor::SlotRegister());
2632 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002633 __ Push(object_);
2634 __ Push(index_); // Consumed by runtime conversion function.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002635 if (index_flags_ == STRING_INDEX_IS_NUMBER) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002636 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002637 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002638 DCHECK(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002639 // NumberToSmi discards numbers that are not exact integers.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002640 __ CallRuntime(Runtime::kNumberToSmi);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002641 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002642 if (!index_.is(rax)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002643 // Save the conversion result before the pop instructions below
2644 // have a chance to overwrite it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002645 __ movp(index_, rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002646 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002647 __ Pop(object_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002648 if (embed_mode == PART_OF_IC_HANDLER) {
2649 __ Pop(LoadDescriptor::SlotRegister());
2650 __ Pop(LoadWithVectorDescriptor::VectorRegister());
2651 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002652 // Reload the instance type.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002653 __ movp(result_, FieldOperand(object_, HeapObject::kMapOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002654 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
2655 call_helper.AfterCall(masm);
2656 // If index is still not a smi, it must be out of range.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002657 __ JumpIfNotSmi(index_, index_out_of_range_);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002658 // Otherwise, return to the fast path.
2659 __ jmp(&got_smi_index_);
2660
2661 // Call runtime. We get here when the receiver is a string and the
2662 // index is a number, but the code of getting the actual character
2663 // is too complex (e.g., when the string needs to be flattened).
2664 __ bind(&call_runtime_);
2665 call_helper.BeforeCall(masm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002666 __ Push(object_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002667 __ Integer32ToSmi(index_, index_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002668 __ Push(index_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002669 __ CallRuntime(Runtime::kStringCharCodeAtRT);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002670 if (!result_.is(rax)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002671 __ movp(result_, rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002672 }
2673 call_helper.AfterCall(masm);
2674 __ jmp(&exit_);
2675
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002676 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002677}
2678
2679
2680// -------------------------------------------------------------------------
2681// StringCharFromCodeGenerator
2682
2683void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
2684 // Fast case of Heap::LookupSingleCharacterStringFromCode.
2685 __ JumpIfNotSmi(code_, &slow_case_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002686 __ SmiCompare(code_, Smi::FromInt(String::kMaxOneByteCharCode));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002687 __ j(above, &slow_case_);
2688
2689 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
2690 SmiIndex index = masm->SmiToIndex(kScratchRegister, code_, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002691 __ movp(result_, FieldOperand(result_, index.reg, index.scale,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002692 FixedArray::kHeaderSize));
2693 __ CompareRoot(result_, Heap::kUndefinedValueRootIndex);
2694 __ j(equal, &slow_case_);
2695 __ bind(&exit_);
2696}
2697
2698
2699void StringCharFromCodeGenerator::GenerateSlow(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002700 MacroAssembler* masm,
2701 const RuntimeCallHelper& call_helper) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002702 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002703
2704 __ bind(&slow_case_);
2705 call_helper.BeforeCall(masm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002706 __ Push(code_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002707 __ CallRuntime(Runtime::kStringCharFromCode);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002708 if (!result_.is(rax)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002709 __ movp(result_, rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002710 }
2711 call_helper.AfterCall(masm);
2712 __ jmp(&exit_);
2713
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002714 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002715}
2716
2717
2718void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
2719 Register dest,
2720 Register src,
2721 Register count,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002722 String::Encoding encoding) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002723 // Nothing to do for zero characters.
Ben Murdoch257744e2011-11-30 15:57:28 +00002724 Label done;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002725 __ testl(count, count);
Ben Murdoch257744e2011-11-30 15:57:28 +00002726 __ j(zero, &done, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002727
2728 // Make count the number of bytes to copy.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002729 if (encoding == String::TWO_BYTE_ENCODING) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002730 STATIC_ASSERT(2 == sizeof(uc16));
2731 __ addl(count, count);
2732 }
2733
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002734 // Copy remaining characters.
2735 Label loop;
2736 __ bind(&loop);
2737 __ movb(kScratchRegister, Operand(src, 0));
2738 __ movb(Operand(dest, 0), kScratchRegister);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002739 __ incp(src);
2740 __ incp(dest);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002741 __ decl(count);
2742 __ j(not_zero, &loop);
2743
2744 __ bind(&done);
2745}
2746
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002747
2748void SubStringStub::Generate(MacroAssembler* masm) {
2749 Label runtime;
2750
2751 // Stack frame on entry.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002752 // rsp[0] : return address
2753 // rsp[8] : to
2754 // rsp[16] : from
2755 // rsp[24] : string
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002756
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002757 enum SubStringStubArgumentIndices {
2758 STRING_ARGUMENT_INDEX,
2759 FROM_ARGUMENT_INDEX,
2760 TO_ARGUMENT_INDEX,
2761 SUB_STRING_ARGUMENT_COUNT
2762 };
2763
2764 StackArgumentsAccessor args(rsp, SUB_STRING_ARGUMENT_COUNT,
2765 ARGUMENTS_DONT_CONTAIN_RECEIVER);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002766
2767 // Make sure first argument is a string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002768 __ movp(rax, args.GetArgumentOperand(STRING_ARGUMENT_INDEX));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002769 STATIC_ASSERT(kSmiTag == 0);
2770 __ testl(rax, Immediate(kSmiTagMask));
2771 __ j(zero, &runtime);
2772 Condition is_string = masm->IsObjectStringType(rax, rbx, rbx);
2773 __ j(NegateCondition(is_string), &runtime);
2774
2775 // rax: string
2776 // rbx: instance type
2777 // Calculate length of sub string using the smi values.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002778 __ movp(rcx, args.GetArgumentOperand(TO_ARGUMENT_INDEX));
2779 __ movp(rdx, args.GetArgumentOperand(FROM_ARGUMENT_INDEX));
Ben Murdochf87a2032010-10-22 12:50:53 +01002780 __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002781
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002782 __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002783 __ cmpp(rcx, FieldOperand(rax, String::kLengthOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002784 Label not_original_string;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002785 // Shorter than original string's length: an actual substring.
2786 __ j(below, &not_original_string, Label::kNear);
2787 // Longer than original string's length or negative: unsafe arguments.
2788 __ j(above, &runtime);
2789 // Return original string.
2790 Counters* counters = isolate()->counters();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002791 __ IncrementCounter(counters->sub_string_native(), 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002792 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002793 __ bind(&not_original_string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002794
2795 Label single_char;
2796 __ SmiCompare(rcx, Smi::FromInt(1));
2797 __ j(equal, &single_char);
2798
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002799 __ SmiToInteger32(rcx, rcx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002800
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002801 // rax: string
2802 // rbx: instance type
2803 // rcx: sub string length
2804 // rdx: from index (smi)
2805 // Deal with different string types: update the index if necessary
2806 // and put the underlying string into edi.
2807 Label underlying_unpacked, sliced_string, seq_or_external_string;
2808 // If the string is not indirect, it can only be sequential or external.
2809 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
2810 STATIC_ASSERT(kIsIndirectStringMask != 0);
2811 __ testb(rbx, Immediate(kIsIndirectStringMask));
2812 __ j(zero, &seq_or_external_string, Label::kNear);
2813
2814 __ testb(rbx, Immediate(kSlicedNotConsMask));
2815 __ j(not_zero, &sliced_string, Label::kNear);
2816 // Cons string. Check whether it is flat, then fetch first part.
2817 // Flat cons strings have an empty second part.
2818 __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002819 Heap::kempty_stringRootIndex);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002820 __ j(not_equal, &runtime);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002821 __ movp(rdi, FieldOperand(rax, ConsString::kFirstOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002822 // Update instance type.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002823 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002824 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002825 __ jmp(&underlying_unpacked, Label::kNear);
2826
2827 __ bind(&sliced_string);
2828 // Sliced string. Fetch parent and correct start index by offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002829 __ addp(rdx, FieldOperand(rax, SlicedString::kOffsetOffset));
2830 __ movp(rdi, FieldOperand(rax, SlicedString::kParentOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002831 // Update instance type.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002832 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002833 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
2834 __ jmp(&underlying_unpacked, Label::kNear);
2835
2836 __ bind(&seq_or_external_string);
2837 // Sequential or external string. Just move string to the correct register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002838 __ movp(rdi, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002839
2840 __ bind(&underlying_unpacked);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002841
Ben Murdoch589d6972011-11-30 16:04:58 +00002842 if (FLAG_string_slices) {
2843 Label copy_routine;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002844 // rdi: underlying subject string
2845 // rbx: instance type of underlying subject string
2846 // rdx: adjusted start index (smi)
2847 // rcx: length
Ben Murdoch589d6972011-11-30 16:04:58 +00002848 // If coming from the make_two_character_string path, the string
2849 // is too short to be sliced anyways.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002850 __ cmpp(rcx, Immediate(SlicedString::kMinLength));
Ben Murdoch589d6972011-11-30 16:04:58 +00002851 // Short slice. Copy instead of slicing.
2852 __ j(less, &copy_routine);
Ben Murdoch589d6972011-11-30 16:04:58 +00002853 // Allocate new sliced string. At this point we do not reload the instance
2854 // type including the string encoding because we simply rely on the info
2855 // provided by the original string. It does not matter if the original
2856 // string's encoding is wrong because we always have to recheck encoding of
2857 // the newly created string's parent anyways due to externalized strings.
2858 Label two_byte_slice, set_slice_header;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002859 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
Ben Murdoch589d6972011-11-30 16:04:58 +00002860 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
2861 __ testb(rbx, Immediate(kStringEncodingMask));
2862 __ j(zero, &two_byte_slice, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002863 __ AllocateOneByteSlicedString(rax, rbx, r14, &runtime);
Ben Murdoch589d6972011-11-30 16:04:58 +00002864 __ jmp(&set_slice_header, Label::kNear);
2865 __ bind(&two_byte_slice);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002866 __ AllocateTwoByteSlicedString(rax, rbx, r14, &runtime);
Ben Murdoch589d6972011-11-30 16:04:58 +00002867 __ bind(&set_slice_header);
Ben Murdoch589d6972011-11-30 16:04:58 +00002868 __ Integer32ToSmi(rcx, rcx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002869 __ movp(FieldOperand(rax, SlicedString::kLengthOffset), rcx);
2870 __ movp(FieldOperand(rax, SlicedString::kHashFieldOffset),
Ben Murdoch589d6972011-11-30 16:04:58 +00002871 Immediate(String::kEmptyHashField));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002872 __ movp(FieldOperand(rax, SlicedString::kParentOffset), rdi);
2873 __ movp(FieldOperand(rax, SlicedString::kOffsetOffset), rdx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002874 __ IncrementCounter(counters->sub_string_native(), 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002875 __ ret(3 * kPointerSize);
Ben Murdoch589d6972011-11-30 16:04:58 +00002876
2877 __ bind(&copy_routine);
Ben Murdoch589d6972011-11-30 16:04:58 +00002878 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002879
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002880 // rdi: underlying subject string
2881 // rbx: instance type of underlying subject string
2882 // rdx: adjusted start index (smi)
2883 // rcx: length
2884 // The subject string can only be external or sequential string of either
2885 // encoding at this point.
2886 Label two_byte_sequential, sequential_string;
2887 STATIC_ASSERT(kExternalStringTag != 0);
2888 STATIC_ASSERT(kSeqStringTag == 0);
2889 __ testb(rbx, Immediate(kExternalStringTag));
2890 __ j(zero, &sequential_string);
2891
2892 // Handle external string.
2893 // Rule out short external strings.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002894 STATIC_ASSERT(kShortExternalStringTag != 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002895 __ testb(rbx, Immediate(kShortExternalStringMask));
2896 __ j(not_zero, &runtime);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002897 __ movp(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002898 // Move the pointer so that offset-wise, it looks like a sequential string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002899 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
2900 __ subp(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002901
2902 __ bind(&sequential_string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002903 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002904 __ testb(rbx, Immediate(kStringEncodingMask));
2905 __ j(zero, &two_byte_sequential);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002906
2907 // Allocate the result.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002908 __ AllocateOneByteString(rax, rcx, r11, r14, r15, &runtime);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002909
2910 // rax: result string
2911 // rcx: result string length
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002912 { // Locate character of sub string start.
2913 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002914 __ leap(r14, Operand(rdi, smi_as_index.reg, smi_as_index.scale,
2915 SeqOneByteString::kHeaderSize - kHeapObjectTag));
Ben Murdoch85b71792012-04-11 18:30:58 +01002916 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002917 // Locate first character of result.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002918 __ leap(rdi, FieldOperand(rax, SeqOneByteString::kHeaderSize));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002919
2920 // rax: result string
2921 // rcx: result length
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002922 // r14: first character of result
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002923 // rsi: character of sub string start
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002924 StringHelper::GenerateCopyCharacters(
2925 masm, rdi, r14, rcx, String::ONE_BYTE_ENCODING);
Steve Block44f0eee2011-05-26 01:26:41 +01002926 __ IncrementCounter(counters->sub_string_native(), 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002927 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002928
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002929 __ bind(&two_byte_sequential);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002930 // Allocate the result.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002931 __ AllocateTwoByteString(rax, rcx, r11, r14, r15, &runtime);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002932
2933 // rax: result string
2934 // rcx: result string length
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002935 { // Locate character of sub string start.
2936 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002937 __ leap(r14, Operand(rdi, smi_as_index.reg, smi_as_index.scale,
2938 SeqOneByteString::kHeaderSize - kHeapObjectTag));
Ben Murdoch85b71792012-04-11 18:30:58 +01002939 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002940 // Locate first character of result.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002941 __ leap(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002942
2943 // rax: result string
2944 // rcx: result length
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002945 // rdi: first character of result
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002946 // r14: character of sub string start
2947 StringHelper::GenerateCopyCharacters(
2948 masm, rdi, r14, rcx, String::TWO_BYTE_ENCODING);
Steve Block44f0eee2011-05-26 01:26:41 +01002949 __ IncrementCounter(counters->sub_string_native(), 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002950 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002951
2952 // Just jump to runtime to create the sub string.
2953 __ bind(&runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002954 __ TailCallRuntime(Runtime::kSubString);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002955
2956 __ bind(&single_char);
2957 // rax: string
2958 // rbx: instance type
2959 // rcx: sub string length (smi)
2960 // rdx: from index (smi)
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002961 StringCharAtGenerator generator(rax, rdx, rcx, rax, &runtime, &runtime,
2962 &runtime, STRING_INDEX_IS_NUMBER,
2963 RECEIVER_IS_STRING);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002964 generator.GenerateFast(masm);
2965 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize);
2966 generator.SkipSlow(masm, &runtime);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002967}
2968
2969
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002970void ToNumberStub::Generate(MacroAssembler* masm) {
2971 // The ToNumber stub takes one argument in rax.
2972 Label not_smi;
2973 __ JumpIfNotSmi(rax, &not_smi, Label::kNear);
2974 __ Ret();
2975 __ bind(&not_smi);
2976
2977 Label not_heap_number;
2978 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
2979 Heap::kHeapNumberMapRootIndex);
2980 __ j(not_equal, &not_heap_number, Label::kNear);
2981 __ Ret();
2982 __ bind(&not_heap_number);
2983
2984 Label not_string, slow_string;
2985 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdi);
2986 // rax: object
2987 // rdi: object map
2988 __ j(above_equal, &not_string, Label::kNear);
2989 // Check if string has a cached array index.
2990 __ testl(FieldOperand(rax, String::kHashFieldOffset),
2991 Immediate(String::kContainsCachedArrayIndexMask));
2992 __ j(not_zero, &slow_string, Label::kNear);
2993 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
2994 __ IndexFromHash(rax, rax);
2995 __ Ret();
2996 __ bind(&slow_string);
2997 __ PopReturnAddressTo(rcx); // Pop return address.
2998 __ Push(rax); // Push argument.
2999 __ PushReturnAddressFrom(rcx); // Push return address.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003000 __ TailCallRuntime(Runtime::kStringToNumber);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003001 __ bind(&not_string);
3002
3003 Label not_oddball;
3004 __ CmpInstanceType(rdi, ODDBALL_TYPE);
3005 __ j(not_equal, &not_oddball, Label::kNear);
3006 __ movp(rax, FieldOperand(rax, Oddball::kToNumberOffset));
3007 __ Ret();
3008 __ bind(&not_oddball);
3009
3010 __ PopReturnAddressTo(rcx); // Pop return address.
3011 __ Push(rax); // Push argument.
3012 __ PushReturnAddressFrom(rcx); // Push return address.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003013 __ TailCallRuntime(Runtime::kToNumber);
3014}
3015
3016
3017void ToLengthStub::Generate(MacroAssembler* masm) {
3018 // The ToLength stub takes on argument in rax.
3019 Label not_smi, positive_smi;
3020 __ JumpIfNotSmi(rax, &not_smi, Label::kNear);
3021 STATIC_ASSERT(kSmiTag == 0);
3022 __ testp(rax, rax);
3023 __ j(greater_equal, &positive_smi, Label::kNear);
3024 __ xorl(rax, rax);
3025 __ bind(&positive_smi);
3026 __ Ret();
3027 __ bind(&not_smi);
3028
3029 __ PopReturnAddressTo(rcx); // Pop return address.
3030 __ Push(rax); // Push argument.
3031 __ PushReturnAddressFrom(rcx); // Push return address.
3032 __ TailCallRuntime(Runtime::kToLength);
3033}
3034
3035
3036void ToStringStub::Generate(MacroAssembler* masm) {
3037 // The ToString stub takes one argument in rax.
3038 Label is_number;
3039 __ JumpIfSmi(rax, &is_number, Label::kNear);
3040
3041 Label not_string;
3042 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdi);
3043 // rax: receiver
3044 // rdi: receiver map
3045 __ j(above_equal, &not_string, Label::kNear);
3046 __ Ret();
3047 __ bind(&not_string);
3048
3049 Label not_heap_number;
3050 __ CompareRoot(rdi, Heap::kHeapNumberMapRootIndex);
3051 __ j(not_equal, &not_heap_number, Label::kNear);
3052 __ bind(&is_number);
3053 NumberToStringStub stub(isolate());
3054 __ TailCallStub(&stub);
3055 __ bind(&not_heap_number);
3056
3057 Label not_oddball;
3058 __ CmpInstanceType(rdi, ODDBALL_TYPE);
3059 __ j(not_equal, &not_oddball, Label::kNear);
3060 __ movp(rax, FieldOperand(rax, Oddball::kToStringOffset));
3061 __ Ret();
3062 __ bind(&not_oddball);
3063
3064 __ PopReturnAddressTo(rcx); // Pop return address.
3065 __ Push(rax); // Push argument.
3066 __ PushReturnAddressFrom(rcx); // Push return address.
3067 __ TailCallRuntime(Runtime::kToString);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003068}
3069
3070
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003071void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
3072 Register left,
3073 Register right,
3074 Register scratch1,
3075 Register scratch2) {
Ben Murdoch257744e2011-11-30 15:57:28 +00003076 Register length = scratch1;
3077
3078 // Compare lengths.
3079 Label check_zero_length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003080 __ movp(length, FieldOperand(left, String::kLengthOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +00003081 __ SmiCompare(length, FieldOperand(right, String::kLengthOffset));
3082 __ j(equal, &check_zero_length, Label::kNear);
3083 __ Move(rax, Smi::FromInt(NOT_EQUAL));
3084 __ ret(0);
3085
3086 // Check if the length is zero.
3087 Label compare_chars;
3088 __ bind(&check_zero_length);
3089 STATIC_ASSERT(kSmiTag == 0);
3090 __ SmiTest(length);
3091 __ j(not_zero, &compare_chars, Label::kNear);
3092 __ Move(rax, Smi::FromInt(EQUAL));
3093 __ ret(0);
3094
3095 // Compare characters.
3096 __ bind(&compare_chars);
3097 Label strings_not_equal;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003098 GenerateOneByteCharsCompareLoop(masm, left, right, length, scratch2,
3099 &strings_not_equal, Label::kNear);
Ben Murdoch257744e2011-11-30 15:57:28 +00003100
3101 // Characters are equal.
3102 __ Move(rax, Smi::FromInt(EQUAL));
3103 __ ret(0);
3104
3105 // Characters are not equal.
3106 __ bind(&strings_not_equal);
3107 __ Move(rax, Smi::FromInt(NOT_EQUAL));
3108 __ ret(0);
3109}
3110
3111
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003112void StringHelper::GenerateCompareFlatOneByteStrings(
3113 MacroAssembler* masm, Register left, Register right, Register scratch1,
3114 Register scratch2, Register scratch3, Register scratch4) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003115 // Ensure that you can always subtract a string length from a non-negative
3116 // number (e.g. another length).
3117 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
3118
3119 // Find minimum length and length difference.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003120 __ movp(scratch1, FieldOperand(left, String::kLengthOffset));
3121 __ movp(scratch4, scratch1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003122 __ SmiSub(scratch4,
3123 scratch4,
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003124 FieldOperand(right, String::kLengthOffset));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003125 // Register scratch4 now holds left.length - right.length.
3126 const Register length_difference = scratch4;
Ben Murdoch257744e2011-11-30 15:57:28 +00003127 Label left_shorter;
3128 __ j(less, &left_shorter, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003129 // The right string isn't longer that the left one.
3130 // Get the right string's length by subtracting the (non-negative) difference
3131 // from the left string's length.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003132 __ SmiSub(scratch1, scratch1, length_difference);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003133 __ bind(&left_shorter);
3134 // Register scratch1 now holds Min(left.length, right.length).
3135 const Register min_length = scratch1;
3136
Ben Murdoch257744e2011-11-30 15:57:28 +00003137 Label compare_lengths;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003138 // If min-length is zero, go directly to comparing lengths.
3139 __ SmiTest(min_length);
Ben Murdoch257744e2011-11-30 15:57:28 +00003140 __ j(zero, &compare_lengths, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003141
Ben Murdoch257744e2011-11-30 15:57:28 +00003142 // Compare loop.
3143 Label result_not_equal;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003144 GenerateOneByteCharsCompareLoop(
3145 masm, left, right, min_length, scratch2, &result_not_equal,
3146 // In debug-code mode, SmiTest below might push
3147 // the target label outside the near range.
3148 Label::kFar);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003149
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003150 // Completed loop without finding different characters.
3151 // Compare lengths (precomputed).
3152 __ bind(&compare_lengths);
3153 __ SmiTest(length_difference);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003154 Label length_not_equal;
3155 __ j(not_zero, &length_not_equal, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003156
3157 // Result is EQUAL.
3158 __ Move(rax, Smi::FromInt(EQUAL));
3159 __ ret(0);
3160
Ben Murdoch257744e2011-11-30 15:57:28 +00003161 Label result_greater;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003162 Label result_less;
3163 __ bind(&length_not_equal);
3164 __ j(greater, &result_greater, Label::kNear);
3165 __ jmp(&result_less, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003166 __ bind(&result_not_equal);
3167 // Unequal comparison of left to right, either character or length.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003168 __ j(above, &result_greater, Label::kNear);
3169 __ bind(&result_less);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003170
3171 // Result is LESS.
3172 __ Move(rax, Smi::FromInt(LESS));
3173 __ ret(0);
3174
3175 // Result is GREATER.
3176 __ bind(&result_greater);
3177 __ Move(rax, Smi::FromInt(GREATER));
3178 __ ret(0);
3179}
3180
3181
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003182void StringHelper::GenerateOneByteCharsCompareLoop(
3183 MacroAssembler* masm, Register left, Register right, Register length,
3184 Register scratch, Label* chars_not_equal, Label::Distance near_jump) {
Ben Murdoch257744e2011-11-30 15:57:28 +00003185 // Change index to run from -length to -1 by adding length to string
3186 // start. This means that loop ends when index reaches zero, which
3187 // doesn't need an additional compare.
3188 __ SmiToInteger32(length, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003189 __ leap(left,
3190 FieldOperand(left, length, times_1, SeqOneByteString::kHeaderSize));
3191 __ leap(right,
3192 FieldOperand(right, length, times_1, SeqOneByteString::kHeaderSize));
3193 __ negq(length);
Ben Murdoch257744e2011-11-30 15:57:28 +00003194 Register index = length; // index = -length;
3195
3196 // Compare loop.
3197 Label loop;
3198 __ bind(&loop);
3199 __ movb(scratch, Operand(left, index, times_1, 0));
3200 __ cmpb(scratch, Operand(right, index, times_1, 0));
3201 __ j(not_equal, chars_not_equal, near_jump);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003202 __ incq(index);
Ben Murdoch257744e2011-11-30 15:57:28 +00003203 __ j(not_zero, &loop);
3204}
3205
3206
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003207void StringCompareStub::Generate(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003208 // ----------- S t a t e -------------
3209 // -- rdx : left string
3210 // -- rax : right string
3211 // -- rsp[0] : return address
3212 // -----------------------------------
3213 __ AssertString(rdx);
3214 __ AssertString(rax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003215
3216 // Check for identity.
Ben Murdoch257744e2011-11-30 15:57:28 +00003217 Label not_same;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003218 __ cmpp(rdx, rax);
Ben Murdoch257744e2011-11-30 15:57:28 +00003219 __ j(not_equal, &not_same, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003220 __ Move(rax, Smi::FromInt(EQUAL));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003221 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1);
3222 __ Ret();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003223
3224 __ bind(&not_same);
3225
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003226 // Check that both are sequential one-byte strings.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003227 Label runtime;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003228 __ JumpIfNotBothSequentialOneByteStrings(rdx, rax, rcx, rbx, &runtime);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003229
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003230 // Inline comparison of one-byte strings.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003231 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003232 StringHelper::GenerateCompareFlatOneByteStrings(masm, rdx, rax, rcx, rbx, rdi,
3233 r8);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003234
3235 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
3236 // tagged as a small integer.
3237 __ bind(&runtime);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003238 __ PopReturnAddressTo(rcx);
3239 __ Push(rdx);
3240 __ Push(rax);
3241 __ PushReturnAddressFrom(rcx);
3242 __ TailCallRuntime(Runtime::kStringCompare);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003243}
3244
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003245
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003246void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
3247 // ----------- S t a t e -------------
3248 // -- rdx : left
3249 // -- rax : right
3250 // -- rsp[0] : return address
3251 // -----------------------------------
3252
3253 // Load rcx with the allocation site. We stick an undefined dummy value here
3254 // and replace it with the real allocation site later when we instantiate this
3255 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
3256 __ Move(rcx, handle(isolate()->heap()->undefined_value()));
3257
3258 // Make sure that we actually patched the allocation site.
3259 if (FLAG_debug_code) {
3260 __ testb(rcx, Immediate(kSmiTagMask));
3261 __ Assert(not_equal, kExpectedAllocationSite);
3262 __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset),
3263 isolate()->factory()->allocation_site_map());
3264 __ Assert(equal, kExpectedAllocationSite);
3265 }
3266
3267 // Tail call into the stub that handles binary operations with allocation
3268 // sites.
3269 BinaryOpWithAllocationSiteStub stub(isolate(), state());
3270 __ TailCallStub(&stub);
3271}
3272
3273
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003274void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
3275 DCHECK_EQ(CompareICState::BOOLEAN, state());
3276 Label miss;
3277 Label::Distance const miss_distance =
3278 masm->emit_debug_code() ? Label::kFar : Label::kNear;
3279
3280 __ JumpIfSmi(rdx, &miss, miss_distance);
3281 __ movp(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
3282 __ JumpIfSmi(rax, &miss, miss_distance);
3283 __ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
3284 __ JumpIfNotRoot(rcx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
3285 __ JumpIfNotRoot(rbx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
3286 if (op() != Token::EQ_STRICT && is_strong(strength())) {
3287 __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion);
3288 } else {
3289 if (!Token::IsEqualityOp(op())) {
3290 __ movp(rax, FieldOperand(rax, Oddball::kToNumberOffset));
3291 __ AssertSmi(rax);
3292 __ movp(rdx, FieldOperand(rdx, Oddball::kToNumberOffset));
3293 __ AssertSmi(rdx);
3294 __ pushq(rax);
3295 __ movq(rax, rdx);
3296 __ popq(rdx);
3297 }
3298 __ subp(rax, rdx);
3299 __ Ret();
3300 }
3301
3302 __ bind(&miss);
3303 GenerateMiss(masm);
3304}
3305
3306
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003307void CompareICStub::GenerateSmis(MacroAssembler* masm) {
3308 DCHECK(state() == CompareICState::SMI);
Ben Murdoch257744e2011-11-30 15:57:28 +00003309 Label miss;
3310 __ JumpIfNotBothSmi(rdx, rax, &miss, Label::kNear);
Steve Block1e0659c2011-05-24 12:43:12 +01003311
3312 if (GetCondition() == equal) {
3313 // For equality we do not care about the sign of the result.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003314 __ subp(rax, rdx);
Steve Block1e0659c2011-05-24 12:43:12 +01003315 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +00003316 Label done;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003317 __ subp(rdx, rax);
Ben Murdoch257744e2011-11-30 15:57:28 +00003318 __ j(no_overflow, &done, Label::kNear);
Steve Block1e0659c2011-05-24 12:43:12 +01003319 // Correct sign of result in case of overflow.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003320 __ notp(rdx);
Steve Block1e0659c2011-05-24 12:43:12 +01003321 __ bind(&done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003322 __ movp(rax, rdx);
Steve Block1e0659c2011-05-24 12:43:12 +01003323 }
3324 __ ret(0);
3325
3326 __ bind(&miss);
3327 GenerateMiss(masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003328}
3329
3330
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003331void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
3332 DCHECK(state() == CompareICState::NUMBER);
Steve Block1e0659c2011-05-24 12:43:12 +01003333
Ben Murdoch257744e2011-11-30 15:57:28 +00003334 Label generic_stub;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003335 Label unordered, maybe_undefined1, maybe_undefined2;
Ben Murdoch257744e2011-11-30 15:57:28 +00003336 Label miss;
Steve Block1e0659c2011-05-24 12:43:12 +01003337
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003338 if (left() == CompareICState::SMI) {
3339 __ JumpIfNotSmi(rdx, &miss);
3340 }
3341 if (right() == CompareICState::SMI) {
3342 __ JumpIfNotSmi(rax, &miss);
3343 }
3344
3345 // Load left and right operand.
3346 Label done, left, left_smi, right_smi;
3347 __ JumpIfSmi(rax, &right_smi, Label::kNear);
3348 __ CompareMap(rax, isolate()->factory()->heap_number_map());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003349 __ j(not_equal, &maybe_undefined1, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003350 __ Movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003351 __ jmp(&left, Label::kNear);
3352 __ bind(&right_smi);
3353 __ SmiToInteger32(rcx, rax); // Can't clobber rax yet.
3354 __ Cvtlsi2sd(xmm1, rcx);
Steve Block1e0659c2011-05-24 12:43:12 +01003355
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003356 __ bind(&left);
3357 __ JumpIfSmi(rdx, &left_smi, Label::kNear);
3358 __ CompareMap(rdx, isolate()->factory()->heap_number_map());
3359 __ j(not_equal, &maybe_undefined2, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003360 __ Movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003361 __ jmp(&done);
3362 __ bind(&left_smi);
3363 __ SmiToInteger32(rcx, rdx); // Can't clobber rdx yet.
3364 __ Cvtlsi2sd(xmm0, rcx);
3365
3366 __ bind(&done);
Steve Block1e0659c2011-05-24 12:43:12 +01003367 // Compare operands
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003368 __ Ucomisd(xmm0, xmm1);
Steve Block1e0659c2011-05-24 12:43:12 +01003369
3370 // Don't base result on EFLAGS when a NaN is involved.
Ben Murdoch257744e2011-11-30 15:57:28 +00003371 __ j(parity_even, &unordered, Label::kNear);
Steve Block1e0659c2011-05-24 12:43:12 +01003372
3373 // Return a result of -1, 0, or 1, based on EFLAGS.
3374 // Performing mov, because xor would destroy the flag register.
3375 __ movl(rax, Immediate(0));
3376 __ movl(rcx, Immediate(0));
3377 __ setcc(above, rax); // Add one to zero if carry clear and not equal.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003378 __ sbbp(rax, rcx); // Subtract one if below (aka. carry set).
Steve Block1e0659c2011-05-24 12:43:12 +01003379 __ ret(0);
3380
3381 __ bind(&unordered);
Steve Block1e0659c2011-05-24 12:43:12 +01003382 __ bind(&generic_stub);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003383 CompareICStub stub(isolate(), op(), strength(), CompareICState::GENERIC,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003384 CompareICState::GENERIC, CompareICState::GENERIC);
Steve Block1e0659c2011-05-24 12:43:12 +01003385 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
3386
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003387 __ bind(&maybe_undefined1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003388 if (Token::IsOrderedRelationalCompareOp(op())) {
3389 __ Cmp(rax, isolate()->factory()->undefined_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003390 __ j(not_equal, &miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003391 __ JumpIfSmi(rdx, &unordered);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003392 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
3393 __ j(not_equal, &maybe_undefined2, Label::kNear);
3394 __ jmp(&unordered);
3395 }
3396
3397 __ bind(&maybe_undefined2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003398 if (Token::IsOrderedRelationalCompareOp(op())) {
3399 __ Cmp(rdx, isolate()->factory()->undefined_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003400 __ j(equal, &unordered);
3401 }
3402
Steve Block1e0659c2011-05-24 12:43:12 +01003403 __ bind(&miss);
3404 GenerateMiss(masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003405}
3406
3407
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003408void CompareICStub::GenerateInternalizedStrings(MacroAssembler* masm) {
3409 DCHECK(state() == CompareICState::INTERNALIZED_STRING);
3410 DCHECK(GetCondition() == equal);
Ben Murdoch257744e2011-11-30 15:57:28 +00003411
3412 // Registers containing left and right operands respectively.
3413 Register left = rdx;
3414 Register right = rax;
3415 Register tmp1 = rcx;
3416 Register tmp2 = rbx;
3417
3418 // Check that both operands are heap objects.
3419 Label miss;
3420 Condition cond = masm->CheckEitherSmi(left, right, tmp1);
3421 __ j(cond, &miss, Label::kNear);
3422
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003423 // Check that both operands are internalized strings.
3424 __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset));
3425 __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset));
3426 __ movzxbp(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
3427 __ movzxbp(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
3428 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
3429 __ orp(tmp1, tmp2);
3430 __ testb(tmp1, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
3431 __ j(not_zero, &miss, Label::kNear);
Ben Murdoch257744e2011-11-30 15:57:28 +00003432
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003433 // Internalized strings are compared by identity.
Ben Murdoch257744e2011-11-30 15:57:28 +00003434 Label done;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003435 __ cmpp(left, right);
Ben Murdoch257744e2011-11-30 15:57:28 +00003436 // Make sure rax is non-zero. At this point input operands are
3437 // guaranteed to be non-zero.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003438 DCHECK(right.is(rax));
Ben Murdoch257744e2011-11-30 15:57:28 +00003439 __ j(not_equal, &done, Label::kNear);
3440 STATIC_ASSERT(EQUAL == 0);
3441 STATIC_ASSERT(kSmiTag == 0);
3442 __ Move(rax, Smi::FromInt(EQUAL));
3443 __ bind(&done);
3444 __ ret(0);
3445
3446 __ bind(&miss);
3447 GenerateMiss(masm);
3448}
3449
3450
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003451void CompareICStub::GenerateUniqueNames(MacroAssembler* masm) {
3452 DCHECK(state() == CompareICState::UNIQUE_NAME);
3453 DCHECK(GetCondition() == equal);
3454
3455 // Registers containing left and right operands respectively.
3456 Register left = rdx;
3457 Register right = rax;
3458 Register tmp1 = rcx;
3459 Register tmp2 = rbx;
3460
3461 // Check that both operands are heap objects.
3462 Label miss;
3463 Condition cond = masm->CheckEitherSmi(left, right, tmp1);
3464 __ j(cond, &miss, Label::kNear);
3465
3466 // Check that both operands are unique names. This leaves the instance
3467 // types loaded in tmp1 and tmp2.
3468 __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset));
3469 __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset));
3470 __ movzxbp(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
3471 __ movzxbp(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
3472
3473 __ JumpIfNotUniqueNameInstanceType(tmp1, &miss, Label::kNear);
3474 __ JumpIfNotUniqueNameInstanceType(tmp2, &miss, Label::kNear);
3475
3476 // Unique names are compared by identity.
3477 Label done;
3478 __ cmpp(left, right);
3479 // Make sure rax is non-zero. At this point input operands are
3480 // guaranteed to be non-zero.
3481 DCHECK(right.is(rax));
3482 __ j(not_equal, &done, Label::kNear);
3483 STATIC_ASSERT(EQUAL == 0);
3484 STATIC_ASSERT(kSmiTag == 0);
3485 __ Move(rax, Smi::FromInt(EQUAL));
3486 __ bind(&done);
3487 __ ret(0);
3488
3489 __ bind(&miss);
3490 GenerateMiss(masm);
3491}
3492
3493
3494void CompareICStub::GenerateStrings(MacroAssembler* masm) {
3495 DCHECK(state() == CompareICState::STRING);
Ben Murdoch257744e2011-11-30 15:57:28 +00003496 Label miss;
3497
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003498 bool equality = Token::IsEqualityOp(op());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003499
Ben Murdoch257744e2011-11-30 15:57:28 +00003500 // Registers containing left and right operands respectively.
3501 Register left = rdx;
3502 Register right = rax;
3503 Register tmp1 = rcx;
3504 Register tmp2 = rbx;
3505 Register tmp3 = rdi;
3506
3507 // Check that both operands are heap objects.
3508 Condition cond = masm->CheckEitherSmi(left, right, tmp1);
3509 __ j(cond, &miss);
3510
3511 // Check that both operands are strings. This leaves the instance
3512 // types loaded in tmp1 and tmp2.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003513 __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset));
3514 __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset));
3515 __ movzxbp(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
3516 __ movzxbp(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
3517 __ movp(tmp3, tmp1);
Ben Murdoch257744e2011-11-30 15:57:28 +00003518 STATIC_ASSERT(kNotStringTag != 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003519 __ orp(tmp3, tmp2);
Ben Murdoch257744e2011-11-30 15:57:28 +00003520 __ testb(tmp3, Immediate(kIsNotStringMask));
3521 __ j(not_zero, &miss);
3522
3523 // Fast check for identical strings.
3524 Label not_same;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003525 __ cmpp(left, right);
Ben Murdoch257744e2011-11-30 15:57:28 +00003526 __ j(not_equal, &not_same, Label::kNear);
3527 STATIC_ASSERT(EQUAL == 0);
3528 STATIC_ASSERT(kSmiTag == 0);
3529 __ Move(rax, Smi::FromInt(EQUAL));
3530 __ ret(0);
3531
3532 // Handle not identical strings.
3533 __ bind(&not_same);
3534
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003535 // Check that both strings are internalized strings. If they are, we're done
3536 // because we already know they are not identical. We also know they are both
3537 // strings.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003538 if (equality) {
3539 Label do_compare;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003540 STATIC_ASSERT(kInternalizedTag == 0);
3541 __ orp(tmp1, tmp2);
3542 __ testb(tmp1, Immediate(kIsNotInternalizedMask));
3543 __ j(not_zero, &do_compare, Label::kNear);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003544 // Make sure rax is non-zero. At this point input operands are
3545 // guaranteed to be non-zero.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003546 DCHECK(right.is(rax));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003547 __ ret(0);
3548 __ bind(&do_compare);
3549 }
Ben Murdoch257744e2011-11-30 15:57:28 +00003550
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003551 // Check that both strings are sequential one-byte.
Ben Murdoch257744e2011-11-30 15:57:28 +00003552 Label runtime;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003553 __ JumpIfNotBothSequentialOneByteStrings(left, right, tmp1, tmp2, &runtime);
Ben Murdoch257744e2011-11-30 15:57:28 +00003554
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003555 // Compare flat one-byte strings. Returns when done.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003556 if (equality) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003557 StringHelper::GenerateFlatOneByteStringEquals(masm, left, right, tmp1,
3558 tmp2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003559 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003560 StringHelper::GenerateCompareFlatOneByteStrings(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003561 masm, left, right, tmp1, tmp2, tmp3, kScratchRegister);
3562 }
Ben Murdoch257744e2011-11-30 15:57:28 +00003563
3564 // Handle more complex cases in runtime.
3565 __ bind(&runtime);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003566 __ PopReturnAddressTo(tmp1);
3567 __ Push(left);
3568 __ Push(right);
3569 __ PushReturnAddressFrom(tmp1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003570 if (equality) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003571 __ TailCallRuntime(Runtime::kStringEquals);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003572 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003573 __ TailCallRuntime(Runtime::kStringCompare);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003574 }
Ben Murdoch257744e2011-11-30 15:57:28 +00003575
3576 __ bind(&miss);
3577 GenerateMiss(masm);
3578}
3579
3580
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003581void CompareICStub::GenerateReceivers(MacroAssembler* masm) {
3582 DCHECK_EQ(CompareICState::RECEIVER, state());
Ben Murdoch257744e2011-11-30 15:57:28 +00003583 Label miss;
Steve Block1e0659c2011-05-24 12:43:12 +01003584 Condition either_smi = masm->CheckEitherSmi(rdx, rax);
Ben Murdoch257744e2011-11-30 15:57:28 +00003585 __ j(either_smi, &miss, Label::kNear);
Steve Block1e0659c2011-05-24 12:43:12 +01003586
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003587 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
3588 __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rcx);
3589 __ j(below, &miss, Label::kNear);
3590 __ CmpObjectType(rdx, FIRST_JS_RECEIVER_TYPE, rcx);
3591 __ j(below, &miss, Label::kNear);
Steve Block1e0659c2011-05-24 12:43:12 +01003592
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003593 DCHECK_EQ(equal, GetCondition());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003594 __ subp(rax, rdx);
Steve Block1e0659c2011-05-24 12:43:12 +01003595 __ ret(0);
3596
3597 __ bind(&miss);
3598 GenerateMiss(masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003599}
3600
3601
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003602void CompareICStub::GenerateKnownReceivers(MacroAssembler* masm) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003603 Label miss;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003604 Handle<WeakCell> cell = Map::WeakCellForMap(known_map_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003605 Condition either_smi = masm->CheckEitherSmi(rdx, rax);
3606 __ j(either_smi, &miss, Label::kNear);
3607
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003608 __ GetWeakValue(rdi, cell);
3609 __ cmpp(FieldOperand(rdx, HeapObject::kMapOffset), rdi);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003610 __ j(not_equal, &miss, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003611 __ cmpp(FieldOperand(rax, HeapObject::kMapOffset), rdi);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003612 __ j(not_equal, &miss, Label::kNear);
3613
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003614 if (Token::IsEqualityOp(op())) {
3615 __ subp(rax, rdx);
3616 __ ret(0);
3617 } else if (is_strong(strength())) {
3618 __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion);
3619 } else {
3620 __ PopReturnAddressTo(rcx);
3621 __ Push(rdx);
3622 __ Push(rax);
3623 __ Push(Smi::FromInt(NegativeComparisonResult(GetCondition())));
3624 __ PushReturnAddressFrom(rcx);
3625 __ TailCallRuntime(Runtime::kCompare);
3626 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003627
3628 __ bind(&miss);
3629 GenerateMiss(masm);
3630}
3631
3632
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003633void CompareICStub::GenerateMiss(MacroAssembler* masm) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003634 {
3635 // Call the runtime system in a fresh internal frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003636 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003637 __ Push(rdx);
3638 __ Push(rax);
3639 __ Push(rdx);
3640 __ Push(rax);
3641 __ Push(Smi::FromInt(op()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003642 __ CallRuntime(Runtime::kCompareIC_Miss);
Ben Murdochc7cc0282012-03-05 14:35:55 +00003643
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003644 // Compute the entry point of the rewritten stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003645 __ leap(rdi, FieldOperand(rax, Code::kHeaderSize));
3646 __ Pop(rax);
3647 __ Pop(rdx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003648 }
Steve Block1e0659c2011-05-24 12:43:12 +01003649
Steve Block1e0659c2011-05-24 12:43:12 +01003650 // Do a tail call to the rewritten stub.
3651 __ jmp(rdi);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003652}
3653
Steve Block1e0659c2011-05-24 12:43:12 +01003654
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003655void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
3656 Label* miss,
3657 Label* done,
3658 Register properties,
3659 Handle<Name> name,
3660 Register r0) {
3661 DCHECK(name->IsUniqueName());
Ben Murdoch257744e2011-11-30 15:57:28 +00003662 // If names of slots in range from 1 to kProbes - 1 for the hash value are
3663 // not equal to the name and kProbes-th slot is not used (its name is the
3664 // undefined value), it guarantees the hash table doesn't contain the
3665 // property. It's true even if some slots represent deleted properties
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003666 // (their names are the hole value).
Ben Murdoch257744e2011-11-30 15:57:28 +00003667 for (int i = 0; i < kInlinedProbes; i++) {
3668 // r0 points to properties hash.
3669 // Compute the masked index: (hash + i + i * i) & mask.
3670 Register index = r0;
3671 // Capacity is smi 2^n.
3672 __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset));
3673 __ decl(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003674 __ andp(index,
3675 Immediate(name->Hash() + NameDictionary::GetProbeOffset(i)));
Ben Murdoch257744e2011-11-30 15:57:28 +00003676
3677 // Scale the index by multiplying by the entry size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003678 STATIC_ASSERT(NameDictionary::kEntrySize == 3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003679 __ leap(index, Operand(index, index, times_2, 0)); // index *= 3.
Ben Murdoch257744e2011-11-30 15:57:28 +00003680
3681 Register entity_name = r0;
3682 // Having undefined at this place means the name is not contained.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003683 STATIC_ASSERT(kSmiTagSize == 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003684 __ movp(entity_name, Operand(properties,
Ben Murdoch257744e2011-11-30 15:57:28 +00003685 index,
3686 times_pointer_size,
3687 kElementsStartOffset - kHeapObjectTag));
3688 __ Cmp(entity_name, masm->isolate()->factory()->undefined_value());
3689 __ j(equal, done);
3690
3691 // Stop if found the property.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003692 __ Cmp(entity_name, Handle<Name>(name));
Ben Murdoch257744e2011-11-30 15:57:28 +00003693 __ j(equal, miss);
3694
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003695 Label good;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003696 // Check for the hole and skip.
3697 __ CompareRoot(entity_name, Heap::kTheHoleValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003698 __ j(equal, &good, Label::kNear);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003699
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003700 // Check if the entry name is not a unique name.
3701 __ movp(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
3702 __ JumpIfNotUniqueNameInstanceType(
3703 FieldOperand(entity_name, Map::kInstanceTypeOffset), miss);
3704 __ bind(&good);
Ben Murdoch257744e2011-11-30 15:57:28 +00003705 }
3706
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003707 NameDictionaryLookupStub stub(masm->isolate(), properties, r0, r0,
3708 NEGATIVE_LOOKUP);
Ben Murdoch257744e2011-11-30 15:57:28 +00003709 __ Push(Handle<Object>(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003710 __ Push(Immediate(name->Hash()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003711 __ CallStub(&stub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003712 __ testp(r0, r0);
Ben Murdoch257744e2011-11-30 15:57:28 +00003713 __ j(not_zero, miss);
3714 __ jmp(done);
Ben Murdoch257744e2011-11-30 15:57:28 +00003715}
3716
3717
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003718// Probe the name dictionary in the |elements| register. Jump to the
Ben Murdoch257744e2011-11-30 15:57:28 +00003719// |done| label if a property with the given name is found leaving the
3720// index into the dictionary in |r1|. Jump to the |miss| label
3721// otherwise.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003722void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
3723 Label* miss,
3724 Label* done,
3725 Register elements,
3726 Register name,
3727 Register r0,
3728 Register r1) {
3729 DCHECK(!elements.is(r0));
3730 DCHECK(!elements.is(r1));
3731 DCHECK(!name.is(r0));
3732 DCHECK(!name.is(r1));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003733
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003734 __ AssertName(name);
Ben Murdoch257744e2011-11-30 15:57:28 +00003735
3736 __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset));
3737 __ decl(r0);
3738
3739 for (int i = 0; i < kInlinedProbes; i++) {
3740 // Compute the masked index: (hash + i + i * i) & mask.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003741 __ movl(r1, FieldOperand(name, Name::kHashFieldOffset));
3742 __ shrl(r1, Immediate(Name::kHashShift));
Ben Murdoch257744e2011-11-30 15:57:28 +00003743 if (i > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003744 __ addl(r1, Immediate(NameDictionary::GetProbeOffset(i)));
Ben Murdoch257744e2011-11-30 15:57:28 +00003745 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003746 __ andp(r1, r0);
Ben Murdoch257744e2011-11-30 15:57:28 +00003747
3748 // Scale the index by multiplying by the entry size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003749 STATIC_ASSERT(NameDictionary::kEntrySize == 3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003750 __ leap(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3
Ben Murdoch257744e2011-11-30 15:57:28 +00003751
3752 // Check if the key is identical to the name.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003753 __ cmpp(name, Operand(elements, r1, times_pointer_size,
Ben Murdoch257744e2011-11-30 15:57:28 +00003754 kElementsStartOffset - kHeapObjectTag));
3755 __ j(equal, done);
3756 }
3757
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003758 NameDictionaryLookupStub stub(masm->isolate(), elements, r0, r1,
3759 POSITIVE_LOOKUP);
3760 __ Push(name);
3761 __ movl(r0, FieldOperand(name, Name::kHashFieldOffset));
3762 __ shrl(r0, Immediate(Name::kHashShift));
3763 __ Push(r0);
Ben Murdoch257744e2011-11-30 15:57:28 +00003764 __ CallStub(&stub);
3765
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003766 __ testp(r0, r0);
Ben Murdoch257744e2011-11-30 15:57:28 +00003767 __ j(zero, miss);
3768 __ jmp(done);
3769}
3770
3771
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003772void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003773 // This stub overrides SometimesSetsUpAFrame() to return false. That means
3774 // we cannot call anything that could cause a GC from this stub.
Ben Murdoch257744e2011-11-30 15:57:28 +00003775 // Stack frame on entry:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003776 // rsp[0 * kPointerSize] : return address.
3777 // rsp[1 * kPointerSize] : key's hash.
3778 // rsp[2 * kPointerSize] : key.
Ben Murdoch257744e2011-11-30 15:57:28 +00003779 // Registers:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003780 // dictionary_: NameDictionary to probe.
Ben Murdoch257744e2011-11-30 15:57:28 +00003781 // result_: used as scratch.
3782 // index_: will hold an index of entry if lookup is successful.
3783 // might alias with result_.
3784 // Returns:
3785 // result_ is zero if lookup failed, non zero otherwise.
3786
3787 Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
3788
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003789 Register scratch = result();
Ben Murdoch257744e2011-11-30 15:57:28 +00003790
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003791 __ SmiToInteger32(scratch, FieldOperand(dictionary(), kCapacityOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +00003792 __ decl(scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003793 __ Push(scratch);
Ben Murdoch257744e2011-11-30 15:57:28 +00003794
3795 // If names of slots in range from 1 to kProbes - 1 for the hash value are
3796 // not equal to the name and kProbes-th slot is not used (its name is the
3797 // undefined value), it guarantees the hash table doesn't contain the
3798 // property. It's true even if some slots represent deleted properties
3799 // (their names are the null value).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003800 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER,
3801 kPointerSize);
Ben Murdoch257744e2011-11-30 15:57:28 +00003802 for (int i = kInlinedProbes; i < kTotalProbes; i++) {
3803 // Compute the masked index: (hash + i + i * i) & mask.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003804 __ movp(scratch, args.GetArgumentOperand(1));
Ben Murdoch257744e2011-11-30 15:57:28 +00003805 if (i > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003806 __ addl(scratch, Immediate(NameDictionary::GetProbeOffset(i)));
Ben Murdoch257744e2011-11-30 15:57:28 +00003807 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003808 __ andp(scratch, Operand(rsp, 0));
Ben Murdoch257744e2011-11-30 15:57:28 +00003809
3810 // Scale the index by multiplying by the entry size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003811 STATIC_ASSERT(NameDictionary::kEntrySize == 3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003812 __ leap(index(), Operand(scratch, scratch, times_2, 0)); // index *= 3.
Ben Murdoch257744e2011-11-30 15:57:28 +00003813
3814 // Having undefined at this place means the name is not contained.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003815 __ movp(scratch, Operand(dictionary(), index(), times_pointer_size,
Ben Murdoch257744e2011-11-30 15:57:28 +00003816 kElementsStartOffset - kHeapObjectTag));
3817
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003818 __ Cmp(scratch, isolate()->factory()->undefined_value());
Ben Murdoch257744e2011-11-30 15:57:28 +00003819 __ j(equal, &not_in_dictionary);
3820
3821 // Stop if found the property.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003822 __ cmpp(scratch, args.GetArgumentOperand(0));
Ben Murdoch257744e2011-11-30 15:57:28 +00003823 __ j(equal, &in_dictionary);
3824
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003825 if (i != kTotalProbes - 1 && mode() == NEGATIVE_LOOKUP) {
3826 // If we hit a key that is not a unique name during negative
3827 // lookup we have to bailout as this key might be equal to the
Ben Murdoch257744e2011-11-30 15:57:28 +00003828 // key we are looking for.
3829
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003830 // Check if the entry name is not a unique name.
3831 __ movp(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
3832 __ JumpIfNotUniqueNameInstanceType(
3833 FieldOperand(scratch, Map::kInstanceTypeOffset),
3834 &maybe_in_dictionary);
Ben Murdoch257744e2011-11-30 15:57:28 +00003835 }
3836 }
3837
3838 __ bind(&maybe_in_dictionary);
3839 // If we are doing negative lookup then probing failure should be
3840 // treated as a lookup success. For positive lookup probing failure
3841 // should be treated as lookup failure.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003842 if (mode() == POSITIVE_LOOKUP) {
3843 __ movp(scratch, Immediate(0));
Ben Murdoch257744e2011-11-30 15:57:28 +00003844 __ Drop(1);
3845 __ ret(2 * kPointerSize);
3846 }
3847
3848 __ bind(&in_dictionary);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003849 __ movp(scratch, Immediate(1));
Ben Murdoch257744e2011-11-30 15:57:28 +00003850 __ Drop(1);
3851 __ ret(2 * kPointerSize);
3852
3853 __ bind(&not_in_dictionary);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003854 __ movp(scratch, Immediate(0));
Ben Murdoch257744e2011-11-30 15:57:28 +00003855 __ Drop(1);
3856 __ ret(2 * kPointerSize);
3857}
3858
3859
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003860void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
3861 Isolate* isolate) {
3862 StoreBufferOverflowStub stub1(isolate, kDontSaveFPRegs);
3863 stub1.GetCode();
3864 StoreBufferOverflowStub stub2(isolate, kSaveFPRegs);
3865 stub2.GetCode();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003866}
3867
3868
3869// Takes the input in 3 registers: address_ value_ and object_. A pointer to
3870// the value has just been written into the object, now this stub makes sure
3871// we keep the GC informed. The word in the object where the value has been
3872// written is in the address register.
3873void RecordWriteStub::Generate(MacroAssembler* masm) {
3874 Label skip_to_incremental_noncompacting;
3875 Label skip_to_incremental_compacting;
3876
3877 // The first two instructions are generated with labels so as to get the
3878 // offset fixed up correctly by the bind(Label*) call. We patch it back and
3879 // forth between a compare instructions (a nop in this position) and the
3880 // real branch when we start and stop incremental heap marking.
3881 // See RecordWriteStub::Patch for details.
3882 __ jmp(&skip_to_incremental_noncompacting, Label::kNear);
3883 __ jmp(&skip_to_incremental_compacting, Label::kFar);
3884
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003885 if (remembered_set_action() == EMIT_REMEMBERED_SET) {
3886 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003887 MacroAssembler::kReturnAtEnd);
3888 } else {
3889 __ ret(0);
3890 }
3891
3892 __ bind(&skip_to_incremental_noncompacting);
3893 GenerateIncremental(masm, INCREMENTAL);
3894
3895 __ bind(&skip_to_incremental_compacting);
3896 GenerateIncremental(masm, INCREMENTAL_COMPACTION);
3897
3898 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
3899 // Will be checked in IncrementalMarking::ActivateGeneratedStub.
3900 masm->set_byte_at(0, kTwoByteNopInstruction);
3901 masm->set_byte_at(2, kFiveByteNopInstruction);
3902}
3903
3904
3905void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
3906 regs_.Save(masm);
3907
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003908 if (remembered_set_action() == EMIT_REMEMBERED_SET) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003909 Label dont_need_remembered_set;
3910
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003911 __ movp(regs_.scratch0(), Operand(regs_.address(), 0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003912 __ JumpIfNotInNewSpace(regs_.scratch0(),
3913 regs_.scratch0(),
3914 &dont_need_remembered_set);
3915
3916 __ CheckPageFlag(regs_.object(),
3917 regs_.scratch0(),
3918 1 << MemoryChunk::SCAN_ON_SCAVENGE,
3919 not_zero,
3920 &dont_need_remembered_set);
3921
3922 // First notify the incremental marker if necessary, then update the
3923 // remembered set.
3924 CheckNeedsToInformIncrementalMarker(
3925 masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003926 InformIncrementalMarker(masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003927 regs_.Restore(masm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003928 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003929 MacroAssembler::kReturnAtEnd);
3930
3931 __ bind(&dont_need_remembered_set);
3932 }
3933
3934 CheckNeedsToInformIncrementalMarker(
3935 masm, kReturnOnNoNeedToInformIncrementalMarker, mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003936 InformIncrementalMarker(masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003937 regs_.Restore(masm);
3938 __ ret(0);
3939}
3940
3941
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003942void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
3943 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003944 Register address =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003945 arg_reg_1.is(regs_.address()) ? kScratchRegister : regs_.address();
3946 DCHECK(!address.is(regs_.object()));
3947 DCHECK(!address.is(arg_reg_1));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003948 __ Move(address, regs_.address());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003949 __ Move(arg_reg_1, regs_.object());
3950 // TODO(gc) Can we just set address arg2 in the beginning?
3951 __ Move(arg_reg_2, address);
3952 __ LoadAddress(arg_reg_3,
3953 ExternalReference::isolate_address(isolate()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003954 int argument_count = 3;
3955
3956 AllowExternalCallThatCantCauseGC scope(masm);
3957 __ PrepareCallCFunction(argument_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003958 __ CallCFunction(
3959 ExternalReference::incremental_marking_record_write_function(isolate()),
3960 argument_count);
3961 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003962}
3963
3964
3965void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
3966 MacroAssembler* masm,
3967 OnNoNeedToInformIncrementalMarker on_no_need,
3968 Mode mode) {
3969 Label on_black;
3970 Label need_incremental;
3971 Label need_incremental_pop_object;
3972
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003973 __ movp(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask));
3974 __ andp(regs_.scratch0(), regs_.object());
3975 __ movp(regs_.scratch1(),
3976 Operand(regs_.scratch0(),
3977 MemoryChunk::kWriteBarrierCounterOffset));
3978 __ subp(regs_.scratch1(), Immediate(1));
3979 __ movp(Operand(regs_.scratch0(),
3980 MemoryChunk::kWriteBarrierCounterOffset),
3981 regs_.scratch1());
3982 __ j(negative, &need_incremental);
3983
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003984 // Let's look at the color of the object: If it is not black we don't have
3985 // to inform the incremental marker.
3986 __ JumpIfBlack(regs_.object(),
3987 regs_.scratch0(),
3988 regs_.scratch1(),
3989 &on_black,
3990 Label::kNear);
3991
3992 regs_.Restore(masm);
3993 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003994 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003995 MacroAssembler::kReturnAtEnd);
3996 } else {
3997 __ ret(0);
3998 }
3999
4000 __ bind(&on_black);
4001
4002 // Get the value from the slot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004003 __ movp(regs_.scratch0(), Operand(regs_.address(), 0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004004
4005 if (mode == INCREMENTAL_COMPACTION) {
4006 Label ensure_not_white;
4007
4008 __ CheckPageFlag(regs_.scratch0(), // Contains value.
4009 regs_.scratch1(), // Scratch.
4010 MemoryChunk::kEvacuationCandidateMask,
4011 zero,
4012 &ensure_not_white,
4013 Label::kNear);
4014
4015 __ CheckPageFlag(regs_.object(),
4016 regs_.scratch1(), // Scratch.
4017 MemoryChunk::kSkipEvacuationSlotsRecordingMask,
4018 zero,
4019 &need_incremental);
4020
4021 __ bind(&ensure_not_white);
4022 }
4023
4024 // We need an extra register for this, so we push the object register
4025 // temporarily.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004026 __ Push(regs_.object());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004027 __ JumpIfWhite(regs_.scratch0(), // The value.
4028 regs_.scratch1(), // Scratch.
4029 regs_.object(), // Scratch.
4030 &need_incremental_pop_object, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004031 __ Pop(regs_.object());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004032
4033 regs_.Restore(masm);
4034 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004035 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004036 MacroAssembler::kReturnAtEnd);
4037 } else {
4038 __ ret(0);
4039 }
4040
4041 __ bind(&need_incremental_pop_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004042 __ Pop(regs_.object());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004043
4044 __ bind(&need_incremental);
4045
4046 // Fall through when we need to inform the incremental marker.
4047}
4048
4049
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004050void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
4051 CEntryStub ces(isolate(), 1, kSaveFPRegs);
4052 __ Call(ces.GetCode(), RelocInfo::CODE_TARGET);
4053 int parameter_count_offset =
4054 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
4055 __ movp(rbx, MemOperand(rbp, parameter_count_offset));
4056 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
4057 __ PopReturnAddressTo(rcx);
4058 int additional_offset =
4059 function_mode() == JS_FUNCTION_STUB_MODE ? kPointerSize : 0;
4060 __ leap(rsp, MemOperand(rsp, rbx, times_pointer_size, additional_offset));
4061 __ jmp(rcx); // Return to IC Miss stub, continuation still on stack.
4062}
4063
4064
4065void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004066 __ EmitLoadTypeFeedbackVector(LoadWithVectorDescriptor::VectorRegister());
4067 LoadICStub stub(isolate(), state());
4068 stub.GenerateForTrampoline(masm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004069}
4070
4071
4072void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004073 __ EmitLoadTypeFeedbackVector(LoadWithVectorDescriptor::VectorRegister());
4074 KeyedLoadICStub stub(isolate(), state());
4075 stub.GenerateForTrampoline(masm);
4076}
4077
4078
4079static void HandleArrayCases(MacroAssembler* masm, Register feedback,
4080 Register receiver_map, Register scratch1,
4081 Register scratch2, Register scratch3,
4082 bool is_polymorphic, Label* miss) {
4083 // feedback initially contains the feedback array
4084 Label next_loop, prepare_next;
4085 Label start_polymorphic;
4086
4087 Register counter = scratch1;
4088 Register length = scratch2;
4089 Register cached_map = scratch3;
4090
4091 __ movp(cached_map, FieldOperand(feedback, FixedArray::OffsetOfElementAt(0)));
4092 __ cmpp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
4093 __ j(not_equal, &start_polymorphic);
4094
4095 // found, now call handler.
4096 Register handler = feedback;
4097 __ movp(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
4098 __ leap(handler, FieldOperand(handler, Code::kHeaderSize));
4099 __ jmp(handler);
4100
4101 // Polymorphic, we have to loop from 2 to N
4102 __ bind(&start_polymorphic);
4103 __ SmiToInteger32(length, FieldOperand(feedback, FixedArray::kLengthOffset));
4104 if (!is_polymorphic) {
4105 // If the IC could be monomorphic we have to make sure we don't go past the
4106 // end of the feedback array.
4107 __ cmpl(length, Immediate(2));
4108 __ j(equal, miss);
4109 }
4110 __ movl(counter, Immediate(2));
4111
4112 __ bind(&next_loop);
4113 __ movp(cached_map, FieldOperand(feedback, counter, times_pointer_size,
4114 FixedArray::kHeaderSize));
4115 __ cmpp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
4116 __ j(not_equal, &prepare_next);
4117 __ movp(handler, FieldOperand(feedback, counter, times_pointer_size,
4118 FixedArray::kHeaderSize + kPointerSize));
4119 __ leap(handler, FieldOperand(handler, Code::kHeaderSize));
4120 __ jmp(handler);
4121
4122 __ bind(&prepare_next);
4123 __ addl(counter, Immediate(2));
4124 __ cmpl(counter, length);
4125 __ j(less, &next_loop);
4126
4127 // We exhausted our array of map handler pairs.
4128 __ jmp(miss);
4129}
4130
4131
4132static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
4133 Register receiver_map, Register feedback,
4134 Register vector, Register integer_slot,
4135 Label* compare_map, Label* load_smi_map,
4136 Label* try_array) {
4137 __ JumpIfSmi(receiver, load_smi_map);
4138 __ movp(receiver_map, FieldOperand(receiver, 0));
4139
4140 __ bind(compare_map);
4141 __ cmpp(receiver_map, FieldOperand(feedback, WeakCell::kValueOffset));
4142 __ j(not_equal, try_array);
4143 Register handler = feedback;
4144 __ movp(handler, FieldOperand(vector, integer_slot, times_pointer_size,
4145 FixedArray::kHeaderSize + kPointerSize));
4146 __ leap(handler, FieldOperand(handler, Code::kHeaderSize));
4147 __ jmp(handler);
4148}
4149
4150
4151void LoadICStub::Generate(MacroAssembler* masm) { GenerateImpl(masm, false); }
4152
4153
4154void LoadICStub::GenerateForTrampoline(MacroAssembler* masm) {
4155 GenerateImpl(masm, true);
4156}
4157
4158
4159void LoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
4160 Register receiver = LoadWithVectorDescriptor::ReceiverRegister(); // rdx
4161 Register name = LoadWithVectorDescriptor::NameRegister(); // rcx
4162 Register vector = LoadWithVectorDescriptor::VectorRegister(); // rbx
4163 Register slot = LoadWithVectorDescriptor::SlotRegister(); // rax
4164 Register feedback = rdi;
4165 Register integer_slot = r8;
4166 Register receiver_map = r9;
4167
4168 __ SmiToInteger32(integer_slot, slot);
4169 __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
4170 FixedArray::kHeaderSize));
4171
4172 // Try to quickly handle the monomorphic case without knowing for sure
4173 // if we have a weak cell in feedback. We do know it's safe to look
4174 // at WeakCell::kValueOffset.
4175 Label try_array, load_smi_map, compare_map;
4176 Label not_array, miss;
4177 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector,
4178 integer_slot, &compare_map, &load_smi_map, &try_array);
4179
4180 // Is it a fixed array?
4181 __ bind(&try_array);
4182 __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
4183 __ j(not_equal, &not_array);
4184 HandleArrayCases(masm, feedback, receiver_map, integer_slot, r11, r15, true,
4185 &miss);
4186
4187 __ bind(&not_array);
4188 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
4189 __ j(not_equal, &miss);
4190 Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
4191 Code::ComputeHandlerFlags(Code::LOAD_IC));
4192 masm->isolate()->stub_cache()->GenerateProbe(
4193 masm, Code::LOAD_IC, code_flags, receiver, name, feedback, no_reg);
4194
4195 __ bind(&miss);
4196 LoadIC::GenerateMiss(masm);
4197
4198 __ bind(&load_smi_map);
4199 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
4200 __ jmp(&compare_map);
4201}
4202
4203
4204void KeyedLoadICStub::Generate(MacroAssembler* masm) {
4205 GenerateImpl(masm, false);
4206}
4207
4208
4209void KeyedLoadICStub::GenerateForTrampoline(MacroAssembler* masm) {
4210 GenerateImpl(masm, true);
4211}
4212
4213
4214void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
4215 Register receiver = LoadWithVectorDescriptor::ReceiverRegister(); // rdx
4216 Register key = LoadWithVectorDescriptor::NameRegister(); // rcx
4217 Register vector = LoadWithVectorDescriptor::VectorRegister(); // rbx
4218 Register slot = LoadWithVectorDescriptor::SlotRegister(); // rax
4219 Register feedback = rdi;
4220 Register integer_slot = r8;
4221 Register receiver_map = r9;
4222
4223 __ SmiToInteger32(integer_slot, slot);
4224 __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
4225 FixedArray::kHeaderSize));
4226
4227 // Try to quickly handle the monomorphic case without knowing for sure
4228 // if we have a weak cell in feedback. We do know it's safe to look
4229 // at WeakCell::kValueOffset.
4230 Label try_array, load_smi_map, compare_map;
4231 Label not_array, miss;
4232 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector,
4233 integer_slot, &compare_map, &load_smi_map, &try_array);
4234
4235 __ bind(&try_array);
4236 // Is it a fixed array?
4237 __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
4238 __ j(not_equal, &not_array);
4239
4240 // We have a polymorphic element handler.
4241 Label polymorphic, try_poly_name;
4242 __ bind(&polymorphic);
4243 HandleArrayCases(masm, feedback, receiver_map, integer_slot, r11, r15, true,
4244 &miss);
4245
4246 __ bind(&not_array);
4247 // Is it generic?
4248 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
4249 __ j(not_equal, &try_poly_name);
4250 Handle<Code> megamorphic_stub =
4251 KeyedLoadIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState());
4252 __ jmp(megamorphic_stub, RelocInfo::CODE_TARGET);
4253
4254 __ bind(&try_poly_name);
4255 // We might have a name in feedback, and a fixed array in the next slot.
4256 __ cmpp(key, feedback);
4257 __ j(not_equal, &miss);
4258 // If the name comparison succeeded, we know we have a fixed array with
4259 // at least one map/handler pair.
4260 __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
4261 FixedArray::kHeaderSize + kPointerSize));
4262 HandleArrayCases(masm, feedback, receiver_map, integer_slot, r11, r15, false,
4263 &miss);
4264
4265 __ bind(&miss);
4266 KeyedLoadIC::GenerateMiss(masm);
4267
4268 __ bind(&load_smi_map);
4269 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
4270 __ jmp(&compare_map);
4271}
4272
4273
4274void VectorStoreICTrampolineStub::Generate(MacroAssembler* masm) {
4275 __ EmitLoadTypeFeedbackVector(VectorStoreICDescriptor::VectorRegister());
4276 VectorStoreICStub stub(isolate(), state());
4277 stub.GenerateForTrampoline(masm);
4278}
4279
4280
4281void VectorKeyedStoreICTrampolineStub::Generate(MacroAssembler* masm) {
4282 __ EmitLoadTypeFeedbackVector(VectorStoreICDescriptor::VectorRegister());
4283 VectorKeyedStoreICStub stub(isolate(), state());
4284 stub.GenerateForTrampoline(masm);
4285}
4286
4287
4288void VectorStoreICStub::Generate(MacroAssembler* masm) {
4289 GenerateImpl(masm, false);
4290}
4291
4292
4293void VectorStoreICStub::GenerateForTrampoline(MacroAssembler* masm) {
4294 GenerateImpl(masm, true);
4295}
4296
4297
4298void VectorStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
4299 Register receiver = VectorStoreICDescriptor::ReceiverRegister(); // rdx
4300 Register key = VectorStoreICDescriptor::NameRegister(); // rcx
4301 Register vector = VectorStoreICDescriptor::VectorRegister(); // rbx
4302 Register slot = VectorStoreICDescriptor::SlotRegister(); // rdi
4303 DCHECK(VectorStoreICDescriptor::ValueRegister().is(rax)); // rax
4304 Register feedback = r8;
4305 Register integer_slot = r9;
4306 Register receiver_map = r11;
4307 DCHECK(!AreAliased(feedback, integer_slot, vector, slot, receiver_map));
4308
4309 __ SmiToInteger32(integer_slot, slot);
4310 __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
4311 FixedArray::kHeaderSize));
4312
4313 // Try to quickly handle the monomorphic case without knowing for sure
4314 // if we have a weak cell in feedback. We do know it's safe to look
4315 // at WeakCell::kValueOffset.
4316 Label try_array, load_smi_map, compare_map;
4317 Label not_array, miss;
4318 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector,
4319 integer_slot, &compare_map, &load_smi_map, &try_array);
4320
4321 // Is it a fixed array?
4322 __ bind(&try_array);
4323 __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
4324 __ j(not_equal, &not_array);
4325 HandleArrayCases(masm, feedback, receiver_map, integer_slot, r14, r15, true,
4326 &miss);
4327
4328 __ bind(&not_array);
4329 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
4330 __ j(not_equal, &miss);
4331
4332 Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
4333 Code::ComputeHandlerFlags(Code::STORE_IC));
4334 masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, code_flags,
4335 receiver, key, feedback, no_reg);
4336
4337 __ bind(&miss);
4338 StoreIC::GenerateMiss(masm);
4339
4340 __ bind(&load_smi_map);
4341 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
4342 __ jmp(&compare_map);
4343}
4344
4345
4346void VectorKeyedStoreICStub::Generate(MacroAssembler* masm) {
4347 GenerateImpl(masm, false);
4348}
4349
4350
4351void VectorKeyedStoreICStub::GenerateForTrampoline(MacroAssembler* masm) {
4352 GenerateImpl(masm, true);
4353}
4354
4355
4356static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
4357 Register receiver_map,
4358 Register feedback, Register scratch,
4359 Register scratch1,
4360 Register scratch2, Label* miss) {
4361 // feedback initially contains the feedback array
4362 Label next, next_loop, prepare_next;
4363 Label transition_call;
4364
4365 Register cached_map = scratch;
4366 Register counter = scratch1;
4367 Register length = scratch2;
4368
4369 // Polymorphic, we have to loop from 0 to N - 1
4370 __ movp(counter, Immediate(0));
4371 __ movp(length, FieldOperand(feedback, FixedArray::kLengthOffset));
4372 __ SmiToInteger32(length, length);
4373
4374 __ bind(&next_loop);
4375 __ movp(cached_map, FieldOperand(feedback, counter, times_pointer_size,
4376 FixedArray::kHeaderSize));
4377 __ cmpp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
4378 __ j(not_equal, &prepare_next);
4379 __ movp(cached_map, FieldOperand(feedback, counter, times_pointer_size,
4380 FixedArray::kHeaderSize + kPointerSize));
4381 __ CompareRoot(cached_map, Heap::kUndefinedValueRootIndex);
4382 __ j(not_equal, &transition_call);
4383 __ movp(feedback, FieldOperand(feedback, counter, times_pointer_size,
4384 FixedArray::kHeaderSize + 2 * kPointerSize));
4385 __ leap(feedback, FieldOperand(feedback, Code::kHeaderSize));
4386 __ jmp(feedback);
4387
4388 __ bind(&transition_call);
4389 DCHECK(receiver_map.is(VectorStoreTransitionDescriptor::MapRegister()));
4390 __ movp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
4391 // The weak cell may have been cleared.
4392 __ JumpIfSmi(receiver_map, miss);
4393 // Get the handler in value.
4394 __ movp(feedback, FieldOperand(feedback, counter, times_pointer_size,
4395 FixedArray::kHeaderSize + 2 * kPointerSize));
4396 __ leap(feedback, FieldOperand(feedback, Code::kHeaderSize));
4397 __ jmp(feedback);
4398
4399 __ bind(&prepare_next);
4400 __ addl(counter, Immediate(3));
4401 __ cmpl(counter, length);
4402 __ j(less, &next_loop);
4403
4404 // We exhausted our array of map handler pairs.
4405 __ jmp(miss);
4406}
4407
4408
4409void VectorKeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
4410 Register receiver = VectorStoreICDescriptor::ReceiverRegister(); // rdx
4411 Register key = VectorStoreICDescriptor::NameRegister(); // rcx
4412 Register vector = VectorStoreICDescriptor::VectorRegister(); // rbx
4413 Register slot = VectorStoreICDescriptor::SlotRegister(); // rdi
4414 DCHECK(VectorStoreICDescriptor::ValueRegister().is(rax)); // rax
4415 Register feedback = r8;
4416 Register integer_slot = r9;
4417 Register receiver_map = r11;
4418 DCHECK(!AreAliased(feedback, integer_slot, vector, slot, receiver_map));
4419
4420 __ SmiToInteger32(integer_slot, slot);
4421 __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
4422 FixedArray::kHeaderSize));
4423
4424 // Try to quickly handle the monomorphic case without knowing for sure
4425 // if we have a weak cell in feedback. We do know it's safe to look
4426 // at WeakCell::kValueOffset.
4427 Label try_array, load_smi_map, compare_map;
4428 Label not_array, miss;
4429 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector,
4430 integer_slot, &compare_map, &load_smi_map, &try_array);
4431
4432 // Is it a fixed array?
4433 __ bind(&try_array);
4434 __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
4435 __ j(not_equal, &not_array);
4436 HandlePolymorphicKeyedStoreCase(masm, receiver_map, feedback, integer_slot,
4437 r15, r14, &miss);
4438
4439 __ bind(&not_array);
4440 Label try_poly_name;
4441 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
4442 __ j(not_equal, &try_poly_name);
4443
4444 Handle<Code> megamorphic_stub =
4445 KeyedStoreIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState());
4446 __ jmp(megamorphic_stub, RelocInfo::CODE_TARGET);
4447
4448 __ bind(&try_poly_name);
4449 // We might have a name in feedback, and a fixed array in the next slot.
4450 __ cmpp(key, feedback);
4451 __ j(not_equal, &miss);
4452 // If the name comparison succeeded, we know we have a fixed array with
4453 // at least one map/handler pair.
4454 __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
4455 FixedArray::kHeaderSize + kPointerSize));
4456 HandleArrayCases(masm, feedback, receiver_map, integer_slot, r14, r15, false,
4457 &miss);
4458
4459 __ bind(&miss);
4460 KeyedStoreIC::GenerateMiss(masm);
4461
4462 __ bind(&load_smi_map);
4463 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
4464 __ jmp(&compare_map);
4465}
4466
4467
4468void CallICTrampolineStub::Generate(MacroAssembler* masm) {
4469 __ EmitLoadTypeFeedbackVector(rbx);
4470 CallICStub stub(isolate(), state());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004471 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
4472}
4473
4474
4475void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
4476 if (masm->isolate()->function_entry_hook() != NULL) {
4477 ProfileEntryHookStub stub(masm->isolate());
4478 masm->CallStub(&stub);
4479 }
4480}
4481
4482
4483void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
4484 // This stub can be called from essentially anywhere, so it needs to save
4485 // all volatile and callee-save registers.
4486 const size_t kNumSavedRegisters = 2;
4487 __ pushq(arg_reg_1);
4488 __ pushq(arg_reg_2);
4489
4490 // Calculate the original stack pointer and store it in the second arg.
4491 __ leap(arg_reg_2,
4492 Operand(rsp, kNumSavedRegisters * kRegisterSize + kPCOnStackSize));
4493
4494 // Calculate the function address to the first arg.
4495 __ movp(arg_reg_1, Operand(rsp, kNumSavedRegisters * kRegisterSize));
4496 __ subp(arg_reg_1, Immediate(Assembler::kShortCallInstructionLength));
4497
4498 // Save the remainder of the volatile registers.
4499 masm->PushCallerSaved(kSaveFPRegs, arg_reg_1, arg_reg_2);
4500
4501 // Call the entry hook function.
4502 __ Move(rax, FUNCTION_ADDR(isolate()->function_entry_hook()),
4503 Assembler::RelocInfoNone());
4504
4505 AllowExternalCallThatCantCauseGC scope(masm);
4506
4507 const int kArgumentCount = 2;
4508 __ PrepareCallCFunction(kArgumentCount);
4509 __ CallCFunction(rax, kArgumentCount);
4510
4511 // Restore volatile regs.
4512 masm->PopCallerSaved(kSaveFPRegs, arg_reg_1, arg_reg_2);
4513 __ popq(arg_reg_2);
4514 __ popq(arg_reg_1);
4515
4516 __ Ret();
4517}
4518
4519
4520template<class T>
4521static void CreateArrayDispatch(MacroAssembler* masm,
4522 AllocationSiteOverrideMode mode) {
4523 if (mode == DISABLE_ALLOCATION_SITES) {
4524 T stub(masm->isolate(), GetInitialFastElementsKind(), mode);
4525 __ TailCallStub(&stub);
4526 } else if (mode == DONT_OVERRIDE) {
4527 int last_index = GetSequenceIndexFromFastElementsKind(
4528 TERMINAL_FAST_ELEMENTS_KIND);
4529 for (int i = 0; i <= last_index; ++i) {
4530 Label next;
4531 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
4532 __ cmpl(rdx, Immediate(kind));
4533 __ j(not_equal, &next);
4534 T stub(masm->isolate(), kind);
4535 __ TailCallStub(&stub);
4536 __ bind(&next);
4537 }
4538
4539 // If we reached this point there is a problem.
4540 __ Abort(kUnexpectedElementsKindInArrayConstructor);
4541 } else {
4542 UNREACHABLE();
4543 }
4544}
4545
4546
4547static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
4548 AllocationSiteOverrideMode mode) {
4549 // rbx - allocation site (if mode != DISABLE_ALLOCATION_SITES)
4550 // rdx - kind (if mode != DISABLE_ALLOCATION_SITES)
4551 // rax - number of arguments
4552 // rdi - constructor?
4553 // rsp[0] - return address
4554 // rsp[8] - last argument
4555 Handle<Object> undefined_sentinel(
4556 masm->isolate()->heap()->undefined_value(),
4557 masm->isolate());
4558
4559 Label normal_sequence;
4560 if (mode == DONT_OVERRIDE) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004561 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
4562 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
4563 STATIC_ASSERT(FAST_ELEMENTS == 2);
4564 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
4565 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS == 4);
4566 STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004567
4568 // is the low bit set? If so, we are holey and that is good.
4569 __ testb(rdx, Immediate(1));
4570 __ j(not_zero, &normal_sequence);
4571 }
4572
4573 // look at the first argument
4574 StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
4575 __ movp(rcx, args.GetArgumentOperand(0));
4576 __ testp(rcx, rcx);
4577 __ j(zero, &normal_sequence);
4578
4579 if (mode == DISABLE_ALLOCATION_SITES) {
4580 ElementsKind initial = GetInitialFastElementsKind();
4581 ElementsKind holey_initial = GetHoleyElementsKind(initial);
4582
4583 ArraySingleArgumentConstructorStub stub_holey(masm->isolate(),
4584 holey_initial,
4585 DISABLE_ALLOCATION_SITES);
4586 __ TailCallStub(&stub_holey);
4587
4588 __ bind(&normal_sequence);
4589 ArraySingleArgumentConstructorStub stub(masm->isolate(),
4590 initial,
4591 DISABLE_ALLOCATION_SITES);
4592 __ TailCallStub(&stub);
4593 } else if (mode == DONT_OVERRIDE) {
4594 // We are going to create a holey array, but our kind is non-holey.
4595 // Fix kind and retry (only if we have an allocation site in the slot).
4596 __ incl(rdx);
4597
4598 if (FLAG_debug_code) {
4599 Handle<Map> allocation_site_map =
4600 masm->isolate()->factory()->allocation_site_map();
4601 __ Cmp(FieldOperand(rbx, 0), allocation_site_map);
4602 __ Assert(equal, kExpectedAllocationSite);
4603 }
4604
4605 // Save the resulting elements kind in type info. We can't just store r3
4606 // in the AllocationSite::transition_info field because elements kind is
4607 // restricted to a portion of the field...upper bits need to be left alone.
4608 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
4609 __ SmiAddConstant(FieldOperand(rbx, AllocationSite::kTransitionInfoOffset),
4610 Smi::FromInt(kFastElementsKindPackedToHoley));
4611
4612 __ bind(&normal_sequence);
4613 int last_index = GetSequenceIndexFromFastElementsKind(
4614 TERMINAL_FAST_ELEMENTS_KIND);
4615 for (int i = 0; i <= last_index; ++i) {
4616 Label next;
4617 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
4618 __ cmpl(rdx, Immediate(kind));
4619 __ j(not_equal, &next);
4620 ArraySingleArgumentConstructorStub stub(masm->isolate(), kind);
4621 __ TailCallStub(&stub);
4622 __ bind(&next);
4623 }
4624
4625 // If we reached this point there is a problem.
4626 __ Abort(kUnexpectedElementsKindInArrayConstructor);
4627 } else {
4628 UNREACHABLE();
4629 }
4630}
4631
4632
4633template<class T>
4634static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
4635 int to_index = GetSequenceIndexFromFastElementsKind(
4636 TERMINAL_FAST_ELEMENTS_KIND);
4637 for (int i = 0; i <= to_index; ++i) {
4638 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
4639 T stub(isolate, kind);
4640 stub.GetCode();
4641 if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
4642 T stub1(isolate, kind, DISABLE_ALLOCATION_SITES);
4643 stub1.GetCode();
4644 }
4645 }
4646}
4647
4648
4649void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) {
4650 ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
4651 isolate);
4652 ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
4653 isolate);
4654 ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
4655 isolate);
4656}
4657
4658
4659void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(
4660 Isolate* isolate) {
4661 ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS };
4662 for (int i = 0; i < 2; i++) {
4663 // For internal arrays we only need a few things
4664 InternalArrayNoArgumentConstructorStub stubh1(isolate, kinds[i]);
4665 stubh1.GetCode();
4666 InternalArraySingleArgumentConstructorStub stubh2(isolate, kinds[i]);
4667 stubh2.GetCode();
4668 InternalArrayNArgumentsConstructorStub stubh3(isolate, kinds[i]);
4669 stubh3.GetCode();
4670 }
4671}
4672
4673
4674void ArrayConstructorStub::GenerateDispatchToArrayStub(
4675 MacroAssembler* masm,
4676 AllocationSiteOverrideMode mode) {
4677 if (argument_count() == ANY) {
4678 Label not_zero_case, not_one_case;
4679 __ testp(rax, rax);
4680 __ j(not_zero, &not_zero_case);
4681 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
4682
4683 __ bind(&not_zero_case);
4684 __ cmpl(rax, Immediate(1));
4685 __ j(greater, &not_one_case);
4686 CreateArrayDispatchOneArgument(masm, mode);
4687
4688 __ bind(&not_one_case);
4689 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
4690 } else if (argument_count() == NONE) {
4691 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
4692 } else if (argument_count() == ONE) {
4693 CreateArrayDispatchOneArgument(masm, mode);
4694 } else if (argument_count() == MORE_THAN_ONE) {
4695 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
4696 } else {
4697 UNREACHABLE();
4698 }
4699}
4700
4701
4702void ArrayConstructorStub::Generate(MacroAssembler* masm) {
4703 // ----------- S t a t e -------------
4704 // -- rax : argc
4705 // -- rbx : AllocationSite or undefined
4706 // -- rdi : constructor
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004707 // -- rdx : new target
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004708 // -- rsp[0] : return address
4709 // -- rsp[8] : last argument
4710 // -----------------------------------
4711 if (FLAG_debug_code) {
4712 // The array construct code is only set for the global and natives
4713 // builtin Array functions which always have maps.
4714
4715 // Initial map for the builtin Array function should be a map.
4716 __ movp(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
4717 // Will both indicate a NULL and a Smi.
4718 STATIC_ASSERT(kSmiTag == 0);
4719 Condition not_smi = NegateCondition(masm->CheckSmi(rcx));
4720 __ Check(not_smi, kUnexpectedInitialMapForArrayFunction);
4721 __ CmpObjectType(rcx, MAP_TYPE, rcx);
4722 __ Check(equal, kUnexpectedInitialMapForArrayFunction);
4723
4724 // We should either have undefined in rbx or a valid AllocationSite
4725 __ AssertUndefinedOrAllocationSite(rbx);
4726 }
4727
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004728 // Enter the context of the Array function.
4729 __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
4730
4731 Label subclassing;
4732 __ cmpp(rdi, rdx);
4733 __ j(not_equal, &subclassing);
4734
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004735 Label no_info;
4736 // If the feedback vector is the undefined value call an array constructor
4737 // that doesn't use AllocationSites.
4738 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
4739 __ j(equal, &no_info);
4740
4741 // Only look at the lower 16 bits of the transition info.
4742 __ movp(rdx, FieldOperand(rbx, AllocationSite::kTransitionInfoOffset));
4743 __ SmiToInteger32(rdx, rdx);
4744 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
4745 __ andp(rdx, Immediate(AllocationSite::ElementsKindBits::kMask));
4746 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
4747
4748 __ bind(&no_info);
4749 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004750
4751 // Subclassing
4752 __ bind(&subclassing);
4753 switch (argument_count()) {
4754 case ANY:
4755 case MORE_THAN_ONE: {
4756 StackArgumentsAccessor args(rsp, rax);
4757 __ movp(args.GetReceiverOperand(), rdi);
4758 __ addp(rax, Immediate(3));
4759 break;
4760 }
4761 case NONE: {
4762 StackArgumentsAccessor args(rsp, 0);
4763 __ movp(args.GetReceiverOperand(), rdi);
4764 __ Set(rax, 3);
4765 break;
4766 }
4767 case ONE: {
4768 StackArgumentsAccessor args(rsp, 1);
4769 __ movp(args.GetReceiverOperand(), rdi);
4770 __ Set(rax, 4);
4771 break;
4772 }
4773 }
4774 __ PopReturnAddressTo(rcx);
4775 __ Push(rdx);
4776 __ Push(rbx);
4777 __ PushReturnAddressFrom(rcx);
4778 __ JumpToExternalReference(ExternalReference(Runtime::kNewArray, isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004779}
4780
4781
4782void InternalArrayConstructorStub::GenerateCase(
4783 MacroAssembler* masm, ElementsKind kind) {
4784 Label not_zero_case, not_one_case;
4785 Label normal_sequence;
4786
4787 __ testp(rax, rax);
4788 __ j(not_zero, &not_zero_case);
4789 InternalArrayNoArgumentConstructorStub stub0(isolate(), kind);
4790 __ TailCallStub(&stub0);
4791
4792 __ bind(&not_zero_case);
4793 __ cmpl(rax, Immediate(1));
4794 __ j(greater, &not_one_case);
4795
4796 if (IsFastPackedElementsKind(kind)) {
4797 // We might need to create a holey array
4798 // look at the first argument
4799 StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
4800 __ movp(rcx, args.GetArgumentOperand(0));
4801 __ testp(rcx, rcx);
4802 __ j(zero, &normal_sequence);
4803
4804 InternalArraySingleArgumentConstructorStub
4805 stub1_holey(isolate(), GetHoleyElementsKind(kind));
4806 __ TailCallStub(&stub1_holey);
4807 }
4808
4809 __ bind(&normal_sequence);
4810 InternalArraySingleArgumentConstructorStub stub1(isolate(), kind);
4811 __ TailCallStub(&stub1);
4812
4813 __ bind(&not_one_case);
4814 InternalArrayNArgumentsConstructorStub stubN(isolate(), kind);
4815 __ TailCallStub(&stubN);
4816}
4817
4818
4819void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
4820 // ----------- S t a t e -------------
4821 // -- rax : argc
4822 // -- rdi : constructor
4823 // -- rsp[0] : return address
4824 // -- rsp[8] : last argument
4825 // -----------------------------------
4826
4827 if (FLAG_debug_code) {
4828 // The array construct code is only set for the global and natives
4829 // builtin Array functions which always have maps.
4830
4831 // Initial map for the builtin Array function should be a map.
4832 __ movp(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
4833 // Will both indicate a NULL and a Smi.
4834 STATIC_ASSERT(kSmiTag == 0);
4835 Condition not_smi = NegateCondition(masm->CheckSmi(rcx));
4836 __ Check(not_smi, kUnexpectedInitialMapForArrayFunction);
4837 __ CmpObjectType(rcx, MAP_TYPE, rcx);
4838 __ Check(equal, kUnexpectedInitialMapForArrayFunction);
4839 }
4840
4841 // Figure out the right elements kind
4842 __ movp(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
4843
4844 // Load the map's "bit field 2" into |result|. We only need the first byte,
4845 // but the following masking takes care of that anyway.
4846 __ movzxbp(rcx, FieldOperand(rcx, Map::kBitField2Offset));
4847 // Retrieve elements_kind from bit field 2.
4848 __ DecodeField<Map::ElementsKindBits>(rcx);
4849
4850 if (FLAG_debug_code) {
4851 Label done;
4852 __ cmpl(rcx, Immediate(FAST_ELEMENTS));
4853 __ j(equal, &done);
4854 __ cmpl(rcx, Immediate(FAST_HOLEY_ELEMENTS));
4855 __ Assert(equal,
4856 kInvalidElementsKindForInternalArrayOrInternalPackedArray);
4857 __ bind(&done);
4858 }
4859
4860 Label fast_elements_case;
4861 __ cmpl(rcx, Immediate(FAST_ELEMENTS));
4862 __ j(equal, &fast_elements_case);
4863 GenerateCase(masm, FAST_HOLEY_ELEMENTS);
4864
4865 __ bind(&fast_elements_case);
4866 GenerateCase(masm, FAST_ELEMENTS);
4867}
4868
4869
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004870void LoadGlobalViaContextStub::Generate(MacroAssembler* masm) {
4871 Register context_reg = rsi;
4872 Register slot_reg = rbx;
4873 Register result_reg = rax;
4874 Label slow_case;
4875
4876 // Go up context chain to the script context.
4877 for (int i = 0; i < depth(); ++i) {
4878 __ movp(rdi, ContextOperand(context_reg, Context::PREVIOUS_INDEX));
4879 context_reg = rdi;
4880 }
4881
4882 // Load the PropertyCell value at the specified slot.
4883 __ movp(result_reg, ContextOperand(context_reg, slot_reg));
4884 __ movp(result_reg, FieldOperand(result_reg, PropertyCell::kValueOffset));
4885
4886 // Check that value is not the_hole.
4887 __ CompareRoot(result_reg, Heap::kTheHoleValueRootIndex);
4888 __ j(equal, &slow_case, Label::kNear);
4889 __ Ret();
4890
4891 // Fallback to the runtime.
4892 __ bind(&slow_case);
4893 __ Integer32ToSmi(slot_reg, slot_reg);
4894 __ PopReturnAddressTo(kScratchRegister);
4895 __ Push(slot_reg);
4896 __ Push(kScratchRegister);
4897 __ TailCallRuntime(Runtime::kLoadGlobalViaContext);
4898}
4899
4900
4901void StoreGlobalViaContextStub::Generate(MacroAssembler* masm) {
4902 Register context_reg = rsi;
4903 Register slot_reg = rbx;
4904 Register value_reg = rax;
4905 Register cell_reg = r8;
4906 Register cell_details_reg = rdx;
4907 Register cell_value_reg = r9;
4908 Label fast_heapobject_case, fast_smi_case, slow_case;
4909
4910 if (FLAG_debug_code) {
4911 __ CompareRoot(value_reg, Heap::kTheHoleValueRootIndex);
4912 __ Check(not_equal, kUnexpectedValue);
4913 }
4914
4915 // Go up context chain to the script context.
4916 for (int i = 0; i < depth(); ++i) {
4917 __ movp(rdi, ContextOperand(context_reg, Context::PREVIOUS_INDEX));
4918 context_reg = rdi;
4919 }
4920
4921 // Load the PropertyCell at the specified slot.
4922 __ movp(cell_reg, ContextOperand(context_reg, slot_reg));
4923
4924 // Load PropertyDetails for the cell (actually only the cell_type, kind and
4925 // READ_ONLY bit of attributes).
4926 __ SmiToInteger32(cell_details_reg,
4927 FieldOperand(cell_reg, PropertyCell::kDetailsOffset));
4928 __ andl(cell_details_reg,
4929 Immediate(PropertyDetails::PropertyCellTypeField::kMask |
4930 PropertyDetails::KindField::kMask |
4931 PropertyDetails::kAttributesReadOnlyMask));
4932
4933 // Check if PropertyCell holds mutable data.
4934 Label not_mutable_data;
4935 __ cmpl(cell_details_reg,
4936 Immediate(PropertyDetails::PropertyCellTypeField::encode(
4937 PropertyCellType::kMutable) |
4938 PropertyDetails::KindField::encode(kData)));
4939 __ j(not_equal, &not_mutable_data);
4940 __ JumpIfSmi(value_reg, &fast_smi_case);
4941 __ bind(&fast_heapobject_case);
4942 __ movp(FieldOperand(cell_reg, PropertyCell::kValueOffset), value_reg);
4943 __ RecordWriteField(cell_reg, PropertyCell::kValueOffset, value_reg,
4944 cell_value_reg, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
4945 OMIT_SMI_CHECK);
4946 // RecordWriteField clobbers the value register, so we need to reload.
4947 __ movp(value_reg, FieldOperand(cell_reg, PropertyCell::kValueOffset));
4948 __ Ret();
4949 __ bind(&not_mutable_data);
4950
4951 // Check if PropertyCell value matches the new value (relevant for Constant,
4952 // ConstantType and Undefined cells).
4953 Label not_same_value;
4954 __ movp(cell_value_reg, FieldOperand(cell_reg, PropertyCell::kValueOffset));
4955 __ cmpp(cell_value_reg, value_reg);
4956 __ j(not_equal, &not_same_value,
4957 FLAG_debug_code ? Label::kFar : Label::kNear);
4958 // Make sure the PropertyCell is not marked READ_ONLY.
4959 __ testl(cell_details_reg,
4960 Immediate(PropertyDetails::kAttributesReadOnlyMask));
4961 __ j(not_zero, &slow_case);
4962 if (FLAG_debug_code) {
4963 Label done;
4964 // This can only be true for Constant, ConstantType and Undefined cells,
4965 // because we never store the_hole via this stub.
4966 __ cmpl(cell_details_reg,
4967 Immediate(PropertyDetails::PropertyCellTypeField::encode(
4968 PropertyCellType::kConstant) |
4969 PropertyDetails::KindField::encode(kData)));
4970 __ j(equal, &done);
4971 __ cmpl(cell_details_reg,
4972 Immediate(PropertyDetails::PropertyCellTypeField::encode(
4973 PropertyCellType::kConstantType) |
4974 PropertyDetails::KindField::encode(kData)));
4975 __ j(equal, &done);
4976 __ cmpl(cell_details_reg,
4977 Immediate(PropertyDetails::PropertyCellTypeField::encode(
4978 PropertyCellType::kUndefined) |
4979 PropertyDetails::KindField::encode(kData)));
4980 __ Check(equal, kUnexpectedValue);
4981 __ bind(&done);
4982 }
4983 __ Ret();
4984 __ bind(&not_same_value);
4985
4986 // Check if PropertyCell contains data with constant type (and is not
4987 // READ_ONLY).
4988 __ cmpl(cell_details_reg,
4989 Immediate(PropertyDetails::PropertyCellTypeField::encode(
4990 PropertyCellType::kConstantType) |
4991 PropertyDetails::KindField::encode(kData)));
4992 __ j(not_equal, &slow_case, Label::kNear);
4993
4994 // Now either both old and new values must be SMIs or both must be heap
4995 // objects with same map.
4996 Label value_is_heap_object;
4997 __ JumpIfNotSmi(value_reg, &value_is_heap_object, Label::kNear);
4998 __ JumpIfNotSmi(cell_value_reg, &slow_case, Label::kNear);
4999 // Old and new values are SMIs, no need for a write barrier here.
5000 __ bind(&fast_smi_case);
5001 __ movp(FieldOperand(cell_reg, PropertyCell::kValueOffset), value_reg);
5002 __ Ret();
5003 __ bind(&value_is_heap_object);
5004 __ JumpIfSmi(cell_value_reg, &slow_case, Label::kNear);
5005 Register cell_value_map_reg = cell_value_reg;
5006 __ movp(cell_value_map_reg,
5007 FieldOperand(cell_value_reg, HeapObject::kMapOffset));
5008 __ cmpp(cell_value_map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
5009 __ j(equal, &fast_heapobject_case);
5010
5011 // Fallback to the runtime.
5012 __ bind(&slow_case);
5013 __ Integer32ToSmi(slot_reg, slot_reg);
5014 __ PopReturnAddressTo(kScratchRegister);
5015 __ Push(slot_reg);
5016 __ Push(value_reg);
5017 __ Push(kScratchRegister);
5018 __ TailCallRuntime(is_strict(language_mode())
5019 ? Runtime::kStoreGlobalViaContext_Strict
5020 : Runtime::kStoreGlobalViaContext_Sloppy);
5021}
5022
5023
5024static int Offset(ExternalReference ref0, ExternalReference ref1) {
5025 int64_t offset = (ref0.address() - ref1.address());
5026 // Check that fits into int.
5027 DCHECK(static_cast<int>(offset) == offset);
5028 return static_cast<int>(offset);
5029}
5030
5031
5032// Prepares stack to put arguments (aligns and so on). WIN64 calling
5033// convention requires to put the pointer to the return value slot into
5034// rcx (rcx must be preserverd until CallApiFunctionAndReturn). Saves
5035// context (rsi). Clobbers rax. Allocates arg_stack_space * kPointerSize
5036// inside the exit frame (not GCed) accessible via StackSpaceOperand.
5037static void PrepareCallApiFunction(MacroAssembler* masm, int arg_stack_space) {
5038 __ EnterApiExitFrame(arg_stack_space);
5039}
5040
5041
5042// Calls an API function. Allocates HandleScope, extracts returned value
5043// from handle and propagates exceptions. Clobbers r14, r15, rbx and
5044// caller-save registers. Restores context. On return removes
5045// stack_space * kPointerSize (GCed).
5046static void CallApiFunctionAndReturn(MacroAssembler* masm,
5047 Register function_address,
5048 ExternalReference thunk_ref,
5049 Register thunk_last_arg, int stack_space,
5050 Operand* stack_space_operand,
5051 Operand return_value_operand,
5052 Operand* context_restore_operand) {
5053 Label prologue;
5054 Label promote_scheduled_exception;
5055 Label delete_allocated_handles;
5056 Label leave_exit_frame;
5057 Label write_back;
5058
5059 Isolate* isolate = masm->isolate();
5060 Factory* factory = isolate->factory();
5061 ExternalReference next_address =
5062 ExternalReference::handle_scope_next_address(isolate);
5063 const int kNextOffset = 0;
5064 const int kLimitOffset = Offset(
5065 ExternalReference::handle_scope_limit_address(isolate), next_address);
5066 const int kLevelOffset = Offset(
5067 ExternalReference::handle_scope_level_address(isolate), next_address);
5068 ExternalReference scheduled_exception_address =
5069 ExternalReference::scheduled_exception_address(isolate);
5070
5071 DCHECK(rdx.is(function_address) || r8.is(function_address));
5072 // Allocate HandleScope in callee-save registers.
5073 Register prev_next_address_reg = r14;
5074 Register prev_limit_reg = rbx;
5075 Register base_reg = r15;
5076 __ Move(base_reg, next_address);
5077 __ movp(prev_next_address_reg, Operand(base_reg, kNextOffset));
5078 __ movp(prev_limit_reg, Operand(base_reg, kLimitOffset));
5079 __ addl(Operand(base_reg, kLevelOffset), Immediate(1));
5080
5081 if (FLAG_log_timer_events) {
5082 FrameScope frame(masm, StackFrame::MANUAL);
5083 __ PushSafepointRegisters();
5084 __ PrepareCallCFunction(1);
5085 __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate));
5086 __ CallCFunction(ExternalReference::log_enter_external_function(isolate),
5087 1);
5088 __ PopSafepointRegisters();
5089 }
5090
5091 Label profiler_disabled;
5092 Label end_profiler_check;
5093 __ Move(rax, ExternalReference::is_profiling_address(isolate));
5094 __ cmpb(Operand(rax, 0), Immediate(0));
5095 __ j(zero, &profiler_disabled);
5096
5097 // Third parameter is the address of the actual getter function.
5098 __ Move(thunk_last_arg, function_address);
5099 __ Move(rax, thunk_ref);
5100 __ jmp(&end_profiler_check);
5101
5102 __ bind(&profiler_disabled);
5103 // Call the api function!
5104 __ Move(rax, function_address);
5105
5106 __ bind(&end_profiler_check);
5107
5108 // Call the api function!
5109 __ call(rax);
5110
5111 if (FLAG_log_timer_events) {
5112 FrameScope frame(masm, StackFrame::MANUAL);
5113 __ PushSafepointRegisters();
5114 __ PrepareCallCFunction(1);
5115 __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate));
5116 __ CallCFunction(ExternalReference::log_leave_external_function(isolate),
5117 1);
5118 __ PopSafepointRegisters();
5119 }
5120
5121 // Load the value from ReturnValue
5122 __ movp(rax, return_value_operand);
5123 __ bind(&prologue);
5124
5125 // No more valid handles (the result handle was the last one). Restore
5126 // previous handle scope.
5127 __ subl(Operand(base_reg, kLevelOffset), Immediate(1));
5128 __ movp(Operand(base_reg, kNextOffset), prev_next_address_reg);
5129 __ cmpp(prev_limit_reg, Operand(base_reg, kLimitOffset));
5130 __ j(not_equal, &delete_allocated_handles);
5131
5132 // Leave the API exit frame.
5133 __ bind(&leave_exit_frame);
5134 bool restore_context = context_restore_operand != NULL;
5135 if (restore_context) {
5136 __ movp(rsi, *context_restore_operand);
5137 }
5138 if (stack_space_operand != nullptr) {
5139 __ movp(rbx, *stack_space_operand);
5140 }
5141 __ LeaveApiExitFrame(!restore_context);
5142
5143 // Check if the function scheduled an exception.
5144 __ Move(rdi, scheduled_exception_address);
5145 __ Cmp(Operand(rdi, 0), factory->the_hole_value());
5146 __ j(not_equal, &promote_scheduled_exception);
5147
5148#if DEBUG
5149 // Check if the function returned a valid JavaScript value.
5150 Label ok;
5151 Register return_value = rax;
5152 Register map = rcx;
5153
5154 __ JumpIfSmi(return_value, &ok, Label::kNear);
5155 __ movp(map, FieldOperand(return_value, HeapObject::kMapOffset));
5156
5157 __ CmpInstanceType(map, LAST_NAME_TYPE);
5158 __ j(below_equal, &ok, Label::kNear);
5159
5160 __ CmpInstanceType(map, FIRST_JS_RECEIVER_TYPE);
5161 __ j(above_equal, &ok, Label::kNear);
5162
5163 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
5164 __ j(equal, &ok, Label::kNear);
5165
5166 __ CompareRoot(return_value, Heap::kUndefinedValueRootIndex);
5167 __ j(equal, &ok, Label::kNear);
5168
5169 __ CompareRoot(return_value, Heap::kTrueValueRootIndex);
5170 __ j(equal, &ok, Label::kNear);
5171
5172 __ CompareRoot(return_value, Heap::kFalseValueRootIndex);
5173 __ j(equal, &ok, Label::kNear);
5174
5175 __ CompareRoot(return_value, Heap::kNullValueRootIndex);
5176 __ j(equal, &ok, Label::kNear);
5177
5178 __ Abort(kAPICallReturnedInvalidObject);
5179
5180 __ bind(&ok);
5181#endif
5182
5183 if (stack_space_operand != nullptr) {
5184 DCHECK_EQ(stack_space, 0);
5185 __ PopReturnAddressTo(rcx);
5186 __ addq(rsp, rbx);
5187 __ jmp(rcx);
5188 } else {
5189 __ ret(stack_space * kPointerSize);
5190 }
5191
5192 // Re-throw by promoting a scheduled exception.
5193 __ bind(&promote_scheduled_exception);
5194 __ TailCallRuntime(Runtime::kPromoteScheduledException);
5195
5196 // HandleScope limit has changed. Delete allocated extensions.
5197 __ bind(&delete_allocated_handles);
5198 __ movp(Operand(base_reg, kLimitOffset), prev_limit_reg);
5199 __ movp(prev_limit_reg, rax);
5200 __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate));
5201 __ LoadAddress(rax,
5202 ExternalReference::delete_handle_scope_extensions(isolate));
5203 __ call(rax);
5204 __ movp(rax, prev_limit_reg);
5205 __ jmp(&leave_exit_frame);
5206}
5207
5208
5209static void CallApiFunctionStubHelper(MacroAssembler* masm,
5210 const ParameterCount& argc,
5211 bool return_first_arg,
5212 bool call_data_undefined) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005213 // ----------- S t a t e -------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005214 // -- rdi : callee
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005215 // -- rbx : call_data
5216 // -- rcx : holder
5217 // -- rdx : api_function_address
5218 // -- rsi : context
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005219 // -- rax : number of arguments if argc is a register
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005220 // -- rsp[0] : return address
5221 // -- rsp[8] : last argument
5222 // -- ...
5223 // -- rsp[argc * 8] : first argument
5224 // -- rsp[(argc + 1) * 8] : receiver
5225 // -----------------------------------
5226
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005227 Register callee = rdi;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005228 Register call_data = rbx;
5229 Register holder = rcx;
5230 Register api_function_address = rdx;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005231 Register context = rsi;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005232 Register return_address = r8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005233
5234 typedef FunctionCallbackArguments FCA;
5235
5236 STATIC_ASSERT(FCA::kContextSaveIndex == 6);
5237 STATIC_ASSERT(FCA::kCalleeIndex == 5);
5238 STATIC_ASSERT(FCA::kDataIndex == 4);
5239 STATIC_ASSERT(FCA::kReturnValueOffset == 3);
5240 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
5241 STATIC_ASSERT(FCA::kIsolateIndex == 1);
5242 STATIC_ASSERT(FCA::kHolderIndex == 0);
5243 STATIC_ASSERT(FCA::kArgsLength == 7);
5244
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005245 DCHECK(argc.is_immediate() || rax.is(argc.reg()));
5246
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005247 __ PopReturnAddressTo(return_address);
5248
5249 // context save
5250 __ Push(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005251
5252 // callee
5253 __ Push(callee);
5254
5255 // call data
5256 __ Push(call_data);
5257 Register scratch = call_data;
5258 if (!call_data_undefined) {
5259 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
5260 }
5261 // return value
5262 __ Push(scratch);
5263 // return value default
5264 __ Push(scratch);
5265 // isolate
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005266 __ Move(scratch, ExternalReference::isolate_address(masm->isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005267 __ Push(scratch);
5268 // holder
5269 __ Push(holder);
5270
5271 __ movp(scratch, rsp);
5272 // Push return address back on stack.
5273 __ PushReturnAddressFrom(return_address);
5274
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005275 // load context from callee
5276 __ movp(context, FieldOperand(callee, JSFunction::kContextOffset));
5277
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005278 // Allocate the v8::Arguments structure in the arguments' space since
5279 // it's not controlled by GC.
5280 const int kApiStackSpace = 4;
5281
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005282 PrepareCallApiFunction(masm, kApiStackSpace);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005283
5284 // FunctionCallbackInfo::implicit_args_.
5285 __ movp(StackSpaceOperand(0), scratch);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005286 if (argc.is_immediate()) {
5287 __ addp(scratch, Immediate((argc.immediate() + FCA::kArgsLength - 1) *
5288 kPointerSize));
5289 // FunctionCallbackInfo::values_.
5290 __ movp(StackSpaceOperand(1), scratch);
5291 // FunctionCallbackInfo::length_.
5292 __ Set(StackSpaceOperand(2), argc.immediate());
5293 // FunctionCallbackInfo::is_construct_call_.
5294 __ Set(StackSpaceOperand(3), 0);
5295 } else {
5296 __ leap(scratch, Operand(scratch, argc.reg(), times_pointer_size,
5297 (FCA::kArgsLength - 1) * kPointerSize));
5298 // FunctionCallbackInfo::values_.
5299 __ movp(StackSpaceOperand(1), scratch);
5300 // FunctionCallbackInfo::length_.
5301 __ movp(StackSpaceOperand(2), argc.reg());
5302 // FunctionCallbackInfo::is_construct_call_.
5303 __ leap(argc.reg(), Operand(argc.reg(), times_pointer_size,
5304 (FCA::kArgsLength + 1) * kPointerSize));
5305 __ movp(StackSpaceOperand(3), argc.reg());
5306 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005307
5308#if defined(__MINGW64__) || defined(_WIN64)
5309 Register arguments_arg = rcx;
5310 Register callback_arg = rdx;
5311#else
5312 Register arguments_arg = rdi;
5313 Register callback_arg = rsi;
5314#endif
5315
5316 // It's okay if api_function_address == callback_arg
5317 // but not arguments_arg
5318 DCHECK(!api_function_address.is(arguments_arg));
5319
5320 // v8::InvocationCallback's argument.
5321 __ leap(arguments_arg, StackSpaceOperand(0));
5322
5323 ExternalReference thunk_ref =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005324 ExternalReference::invoke_function_callback(masm->isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005325
5326 // Accessor for FunctionCallbackInfo and first js arg.
5327 StackArgumentsAccessor args_from_rbp(rbp, FCA::kArgsLength + 1,
5328 ARGUMENTS_DONT_CONTAIN_RECEIVER);
5329 Operand context_restore_operand = args_from_rbp.GetArgumentOperand(
5330 FCA::kArgsLength - FCA::kContextSaveIndex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005331 Operand is_construct_call_operand = StackSpaceOperand(3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005332 Operand return_value_operand = args_from_rbp.GetArgumentOperand(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005333 return_first_arg ? 0 : FCA::kArgsLength - FCA::kReturnValueOffset);
5334 int stack_space = 0;
5335 Operand* stack_space_operand = &is_construct_call_operand;
5336 if (argc.is_immediate()) {
5337 stack_space = argc.immediate() + FCA::kArgsLength + 1;
5338 stack_space_operand = nullptr;
5339 }
5340 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, callback_arg,
5341 stack_space, stack_space_operand,
5342 return_value_operand, &context_restore_operand);
5343}
5344
5345
5346void CallApiFunctionStub::Generate(MacroAssembler* masm) {
5347 bool call_data_undefined = this->call_data_undefined();
5348 CallApiFunctionStubHelper(masm, ParameterCount(rax), false,
5349 call_data_undefined);
5350}
5351
5352
5353void CallApiAccessorStub::Generate(MacroAssembler* masm) {
5354 bool is_store = this->is_store();
5355 int argc = this->argc();
5356 bool call_data_undefined = this->call_data_undefined();
5357 CallApiFunctionStubHelper(masm, ParameterCount(argc), is_store,
5358 call_data_undefined);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005359}
5360
5361
5362void CallApiGetterStub::Generate(MacroAssembler* masm) {
5363 // ----------- S t a t e -------------
5364 // -- rsp[0] : return address
5365 // -- rsp[8] : name
5366 // -- rsp[16 - kArgsLength*8] : PropertyCallbackArguments object
5367 // -- ...
5368 // -- r8 : api_function_address
5369 // -----------------------------------
5370
5371#if defined(__MINGW64__) || defined(_WIN64)
5372 Register getter_arg = r8;
5373 Register accessor_info_arg = rdx;
5374 Register name_arg = rcx;
5375#else
5376 Register getter_arg = rdx;
5377 Register accessor_info_arg = rsi;
5378 Register name_arg = rdi;
5379#endif
5380 Register api_function_address = ApiGetterDescriptor::function_address();
5381 DCHECK(api_function_address.is(r8));
5382 Register scratch = rax;
5383
5384 // v8::Arguments::values_ and handler for name.
5385 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 1;
5386
5387 // Allocate v8::AccessorInfo in non-GCed stack space.
5388 const int kArgStackSpace = 1;
5389
5390 __ leap(name_arg, Operand(rsp, kPCOnStackSize));
5391
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005392 PrepareCallApiFunction(masm, kArgStackSpace);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005393 __ leap(scratch, Operand(name_arg, 1 * kPointerSize));
5394
5395 // v8::PropertyAccessorInfo::args_.
5396 __ movp(StackSpaceOperand(0), scratch);
5397
5398 // The context register (rsi) has been saved in PrepareCallApiFunction and
5399 // could be used to pass arguments.
5400 __ leap(accessor_info_arg, StackSpaceOperand(0));
5401
5402 ExternalReference thunk_ref =
5403 ExternalReference::invoke_accessor_getter_callback(isolate());
5404
5405 // It's okay if api_function_address == getter_arg
5406 // but not accessor_info_arg or name_arg
5407 DCHECK(!api_function_address.is(accessor_info_arg) &&
5408 !api_function_address.is(name_arg));
5409
5410 // The name handler is counted as an argument.
5411 StackArgumentsAccessor args(rbp, PropertyCallbackArguments::kArgsLength);
5412 Operand return_value_operand = args.GetArgumentOperand(
5413 PropertyCallbackArguments::kArgsLength - 1 -
5414 PropertyCallbackArguments::kReturnValueOffset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005415 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, getter_arg,
5416 kStackSpace, nullptr, return_value_operand, NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005417}
5418
5419
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005420#undef __
5421
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005422} // namespace internal
5423} // namespace v8
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005424
5425#endif // V8_TARGET_ARCH_X64