blob: 7851b58c2199d47c4007ccb7d642051eeea2cc7b [file] [log] [blame]
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001// Copyright 2012 the V8 project authors. All rights reserved.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_MIPS
lrn@chromium.org7516f052011-03-30 08:52:27 +000031
32#include "bootstrapper.h"
33#include "code-stubs.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000034#include "codegen.h"
lrn@chromium.org7516f052011-03-30 08:52:27 +000035#include "regexp-macro-assembler.h"
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +000036#include "stub-cache.h"
lrn@chromium.org7516f052011-03-30 08:52:27 +000037
38namespace v8 {
39namespace internal {
40
41
verwaest@chromium.org662436e2013-08-28 08:41:27 +000042void FastNewClosureStub::InitializeInterfaceDescriptor(
43 Isolate* isolate,
44 CodeStubInterfaceDescriptor* descriptor) {
45 static Register registers[] = { a2 };
46 descriptor->register_param_count_ = 1;
47 descriptor->register_params_ = registers;
48 descriptor->deoptimization_handler_ =
machenbach@chromium.org895f00d2014-03-27 01:04:43 +000049 Runtime::FunctionForId(Runtime::kHiddenNewClosureFromStubFailure)->entry;
verwaest@chromium.org662436e2013-08-28 08:41:27 +000050}
51
52
palfia@homejinni.comcc96b0e2014-01-23 17:24:54 +000053void FastNewContextStub::InitializeInterfaceDescriptor(
54 Isolate* isolate,
55 CodeStubInterfaceDescriptor* descriptor) {
56 static Register registers[] = { a1 };
57 descriptor->register_param_count_ = 1;
58 descriptor->register_params_ = registers;
59 descriptor->deoptimization_handler_ = NULL;
60}
61
62
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +000063void ToNumberStub::InitializeInterfaceDescriptor(
64 Isolate* isolate,
65 CodeStubInterfaceDescriptor* descriptor) {
66 static Register registers[] = { a0 };
67 descriptor->register_param_count_ = 1;
68 descriptor->register_params_ = registers;
69 descriptor->deoptimization_handler_ = NULL;
70}
71
72
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +000073void NumberToStringStub::InitializeInterfaceDescriptor(
74 Isolate* isolate,
75 CodeStubInterfaceDescriptor* descriptor) {
76 static Register registers[] = { a0 };
77 descriptor->register_param_count_ = 1;
78 descriptor->register_params_ = registers;
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +000079 descriptor->deoptimization_handler_ =
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +000080 Runtime::FunctionForId(Runtime::kHiddenNumberToString)->entry;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +000081}
82
83
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000084void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
85 Isolate* isolate,
86 CodeStubInterfaceDescriptor* descriptor) {
87 static Register registers[] = { a3, a2, a1 };
88 descriptor->register_param_count_ = 3;
89 descriptor->register_params_ = registers;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000090 descriptor->deoptimization_handler_ =
machenbach@chromium.org895f00d2014-03-27 01:04:43 +000091 Runtime::FunctionForId(
92 Runtime::kHiddenCreateArrayLiteralStubBailout)->entry;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000093}
94
95
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000096void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
97 Isolate* isolate,
98 CodeStubInterfaceDescriptor* descriptor) {
99 static Register registers[] = { a3, a2, a1, a0 };
100 descriptor->register_param_count_ = 4;
101 descriptor->register_params_ = registers;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000102 descriptor->deoptimization_handler_ =
machenbach@chromium.org895f00d2014-03-27 01:04:43 +0000103 Runtime::FunctionForId(Runtime::kHiddenCreateObjectLiteral)->entry;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000104}
105
106
danno@chromium.orgbee51992013-07-10 14:57:15 +0000107void CreateAllocationSiteStub::InitializeInterfaceDescriptor(
108 Isolate* isolate,
109 CodeStubInterfaceDescriptor* descriptor) {
titzer@chromium.orgf5a24542014-03-04 09:06:17 +0000110 static Register registers[] = { a2, a3 };
111 descriptor->register_param_count_ = 2;
danno@chromium.orgbee51992013-07-10 14:57:15 +0000112 descriptor->register_params_ = registers;
113 descriptor->deoptimization_handler_ = NULL;
114}
115
116
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000117void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
118 Isolate* isolate,
119 CodeStubInterfaceDescriptor* descriptor) {
120 static Register registers[] = { a1, a0 };
121 descriptor->register_param_count_ = 2;
122 descriptor->register_params_ = registers;
123 descriptor->deoptimization_handler_ =
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000124 FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000125}
126
127
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000128void KeyedLoadDictionaryElementStub::InitializeInterfaceDescriptor(
129 Isolate* isolate,
130 CodeStubInterfaceDescriptor* descriptor) {
131 static Register registers[] = {a1, a0 };
132 descriptor->register_param_count_ = 2;
133 descriptor->register_params_ = registers;
134 descriptor->deoptimization_handler_ =
135 FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
136}
137
138
machenbach@chromium.org09cae8d2014-01-30 01:05:27 +0000139void RegExpConstructResultStub::InitializeInterfaceDescriptor(
140 Isolate* isolate,
141 CodeStubInterfaceDescriptor* descriptor) {
142 static Register registers[] = { a2, a1, a0 };
143 descriptor->register_param_count_ = 3;
144 descriptor->register_params_ = registers;
145 descriptor->deoptimization_handler_ =
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +0000146 Runtime::FunctionForId(Runtime::kHiddenRegExpConstructResult)->entry;
machenbach@chromium.org09cae8d2014-01-30 01:05:27 +0000147}
148
149
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000150void LoadFieldStub::InitializeInterfaceDescriptor(
151 Isolate* isolate,
152 CodeStubInterfaceDescriptor* descriptor) {
153 static Register registers[] = { a0 };
154 descriptor->register_param_count_ = 1;
155 descriptor->register_params_ = registers;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000156 descriptor->deoptimization_handler_ = NULL;
157}
158
159
160void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
161 Isolate* isolate,
162 CodeStubInterfaceDescriptor* descriptor) {
163 static Register registers[] = { a1 };
164 descriptor->register_param_count_ = 1;
165 descriptor->register_params_ = registers;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000166 descriptor->deoptimization_handler_ = NULL;
167}
168
169
machenbach@chromium.org381adef2014-03-14 03:04:56 +0000170void StringLengthStub::InitializeInterfaceDescriptor(
171 Isolate* isolate,
172 CodeStubInterfaceDescriptor* descriptor) {
173 static Register registers[] = { a0, a2 };
174 descriptor->register_param_count_ = 2;
175 descriptor->register_params_ = registers;
176 descriptor->deoptimization_handler_ = NULL;
177}
178
179
180void KeyedStringLengthStub::InitializeInterfaceDescriptor(
181 Isolate* isolate,
182 CodeStubInterfaceDescriptor* descriptor) {
183 static Register registers[] = { a1, a0 };
184 descriptor->register_param_count_ = 2;
185 descriptor->register_params_ = registers;
186 descriptor->deoptimization_handler_ = NULL;
187}
188
189
danno@chromium.orgc99cd482013-03-21 15:26:42 +0000190void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
191 Isolate* isolate,
192 CodeStubInterfaceDescriptor* descriptor) {
193 static Register registers[] = { a2, a1, a0 };
194 descriptor->register_param_count_ = 3;
195 descriptor->register_params_ = registers;
196 descriptor->deoptimization_handler_ =
197 FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure);
198}
199
200
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000201void TransitionElementsKindStub::InitializeInterfaceDescriptor(
202 Isolate* isolate,
203 CodeStubInterfaceDescriptor* descriptor) {
204 static Register registers[] = { a0, a1 };
205 descriptor->register_param_count_ = 2;
206 descriptor->register_params_ = registers;
207 Address entry =
208 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry;
209 descriptor->deoptimization_handler_ = FUNCTION_ADDR(entry);
210}
211
212
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000213void CompareNilICStub::InitializeInterfaceDescriptor(
214 Isolate* isolate,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000215 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000216 static Register registers[] = { a0 };
217 descriptor->register_param_count_ = 1;
218 descriptor->register_params_ = registers;
219 descriptor->deoptimization_handler_ =
220 FUNCTION_ADDR(CompareNilIC_Miss);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000221 descriptor->SetMissHandler(
222 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate));
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000223}
224
225
226static void InitializeArrayConstructorDescriptor(
227 Isolate* isolate,
228 CodeStubInterfaceDescriptor* descriptor,
229 int constant_stack_parameter_count) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000230 // register state
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000231 // a0 -- number of arguments
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000232 // a1 -- function
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +0000233 // a2 -- allocation site with elements kind
machenbach@chromium.orgfeecfde2013-11-14 10:55:00 +0000234 static Register registers_variable_args[] = { a1, a2, a0 };
235 static Register registers_no_args[] = { a1, a2 };
236
237 if (constant_stack_parameter_count == 0) {
238 descriptor->register_param_count_ = 2;
239 descriptor->register_params_ = registers_no_args;
240 } else {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000241 // stack param count needs (constructor pointer, and single argument)
machenbach@chromium.orgfeecfde2013-11-14 10:55:00 +0000242 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000243 descriptor->stack_parameter_count_ = a0;
machenbach@chromium.orgfeecfde2013-11-14 10:55:00 +0000244 descriptor->register_param_count_ = 3;
245 descriptor->register_params_ = registers_variable_args;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000246 }
machenbach@chromium.orgfeecfde2013-11-14 10:55:00 +0000247
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000248 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000249 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000250 descriptor->deoptimization_handler_ =
machenbach@chromium.org895f00d2014-03-27 01:04:43 +0000251 Runtime::FunctionForId(Runtime::kHiddenArrayConstructor)->entry;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000252}
253
254
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +0000255static void InitializeInternalArrayConstructorDescriptor(
256 Isolate* isolate,
257 CodeStubInterfaceDescriptor* descriptor,
258 int constant_stack_parameter_count) {
259 // register state
260 // a0 -- number of arguments
261 // a1 -- constructor function
machenbach@chromium.orgfeecfde2013-11-14 10:55:00 +0000262 static Register registers_variable_args[] = { a1, a0 };
263 static Register registers_no_args[] = { a1 };
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +0000264
machenbach@chromium.orgfeecfde2013-11-14 10:55:00 +0000265 if (constant_stack_parameter_count == 0) {
266 descriptor->register_param_count_ = 1;
267 descriptor->register_params_ = registers_no_args;
268 } else {
269 // stack param count needs (constructor pointer, and single argument)
270 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000271 descriptor->stack_parameter_count_ = a0;
machenbach@chromium.orgfeecfde2013-11-14 10:55:00 +0000272 descriptor->register_param_count_ = 2;
273 descriptor->register_params_ = registers_variable_args;
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +0000274 }
machenbach@chromium.orgfeecfde2013-11-14 10:55:00 +0000275
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +0000276 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +0000277 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
278 descriptor->deoptimization_handler_ =
machenbach@chromium.org895f00d2014-03-27 01:04:43 +0000279 Runtime::FunctionForId(Runtime::kHiddenInternalArrayConstructor)->entry;
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +0000280}
281
282
ulan@chromium.org750145a2013-03-07 15:14:13 +0000283void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
284 Isolate* isolate,
285 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000286 InitializeArrayConstructorDescriptor(isolate, descriptor, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000287}
288
289
290void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
291 Isolate* isolate,
292 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000293 InitializeArrayConstructorDescriptor(isolate, descriptor, 1);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000294}
295
296
297void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
298 Isolate* isolate,
299 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000300 InitializeArrayConstructorDescriptor(isolate, descriptor, -1);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000301}
302
303
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000304void ToBooleanStub::InitializeInterfaceDescriptor(
305 Isolate* isolate,
306 CodeStubInterfaceDescriptor* descriptor) {
307 static Register registers[] = { a0 };
308 descriptor->register_param_count_ = 1;
309 descriptor->register_params_ = registers;
310 descriptor->deoptimization_handler_ =
311 FUNCTION_ADDR(ToBooleanIC_Miss);
312 descriptor->SetMissHandler(
313 ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate));
314}
315
316
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +0000317void InternalArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
318 Isolate* isolate,
319 CodeStubInterfaceDescriptor* descriptor) {
320 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 0);
321}
322
323
324void InternalArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
325 Isolate* isolate,
326 CodeStubInterfaceDescriptor* descriptor) {
327 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 1);
328}
329
330
331void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
332 Isolate* isolate,
333 CodeStubInterfaceDescriptor* descriptor) {
334 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1);
335}
336
337
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000338void StoreGlobalStub::InitializeInterfaceDescriptor(
339 Isolate* isolate,
340 CodeStubInterfaceDescriptor* descriptor) {
341 static Register registers[] = { a1, a2, a0 };
342 descriptor->register_param_count_ = 3;
343 descriptor->register_params_ = registers;
344 descriptor->deoptimization_handler_ =
345 FUNCTION_ADDR(StoreIC_MissFromStubFailure);
346}
347
348
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000349void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
350 Isolate* isolate,
351 CodeStubInterfaceDescriptor* descriptor) {
352 static Register registers[] = { a0, a3, a1, a2 };
353 descriptor->register_param_count_ = 4;
354 descriptor->register_params_ = registers;
355 descriptor->deoptimization_handler_ =
356 FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss);
357}
358
359
ulan@chromium.org0f13e742014-01-03 15:51:11 +0000360void BinaryOpICStub::InitializeInterfaceDescriptor(
361 Isolate* isolate,
362 CodeStubInterfaceDescriptor* descriptor) {
363 static Register registers[] = { a1, a0 };
364 descriptor->register_param_count_ = 2;
365 descriptor->register_params_ = registers;
366 descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss);
367 descriptor->SetMissHandler(
368 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
369}
370
371
372void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor(
373 Isolate* isolate,
374 CodeStubInterfaceDescriptor* descriptor) {
375 static Register registers[] = { a2, a1, a0 };
376 descriptor->register_param_count_ = 3;
377 descriptor->register_params_ = registers;
378 descriptor->deoptimization_handler_ =
379 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite);
380}
381
382
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +0000383void StringAddStub::InitializeInterfaceDescriptor(
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000384 Isolate* isolate,
385 CodeStubInterfaceDescriptor* descriptor) {
386 static Register registers[] = { a1, a0 };
387 descriptor->register_param_count_ = 2;
388 descriptor->register_params_ = registers;
389 descriptor->deoptimization_handler_ =
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +0000390 Runtime::FunctionForId(Runtime::kHiddenStringAdd)->entry;
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000391}
392
393
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +0000394void CallDescriptors::InitializeForIsolate(Isolate* isolate) {
395 {
396 CallInterfaceDescriptor* descriptor =
397 isolate->call_descriptor(Isolate::ArgumentAdaptorCall);
398 static Register registers[] = { a1, // JSFunction
399 cp, // context
400 a0, // actual number of arguments
401 a2, // expected number of arguments
402 };
403 static Representation representations[] = {
404 Representation::Tagged(), // JSFunction
405 Representation::Tagged(), // context
406 Representation::Integer32(), // actual number of arguments
407 Representation::Integer32(), // expected number of arguments
408 };
409 descriptor->register_param_count_ = 4;
410 descriptor->register_params_ = registers;
411 descriptor->param_representations_ = representations;
412 }
413 {
414 CallInterfaceDescriptor* descriptor =
415 isolate->call_descriptor(Isolate::KeyedCall);
416 static Register registers[] = { cp, // context
417 a2, // key
418 };
419 static Representation representations[] = {
420 Representation::Tagged(), // context
421 Representation::Tagged(), // key
422 };
423 descriptor->register_param_count_ = 2;
424 descriptor->register_params_ = registers;
425 descriptor->param_representations_ = representations;
426 }
427 {
428 CallInterfaceDescriptor* descriptor =
429 isolate->call_descriptor(Isolate::NamedCall);
430 static Register registers[] = { cp, // context
431 a2, // name
432 };
433 static Representation representations[] = {
434 Representation::Tagged(), // context
435 Representation::Tagged(), // name
436 };
437 descriptor->register_param_count_ = 2;
438 descriptor->register_params_ = registers;
439 descriptor->param_representations_ = representations;
440 }
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +0000441 {
442 CallInterfaceDescriptor* descriptor =
443 isolate->call_descriptor(Isolate::CallHandler);
444 static Register registers[] = { cp, // context
445 a0, // receiver
446 };
447 static Representation representations[] = {
448 Representation::Tagged(), // context
449 Representation::Tagged(), // receiver
450 };
451 descriptor->register_param_count_ = 2;
452 descriptor->register_params_ = registers;
453 descriptor->param_representations_ = representations;
454 }
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +0000455 {
456 CallInterfaceDescriptor* descriptor =
457 isolate->call_descriptor(Isolate::ApiFunctionCall);
458 static Register registers[] = { a0, // callee
459 t0, // call_data
460 a2, // holder
461 a1, // api_function_address
462 cp, // context
463 };
464 static Representation representations[] = {
465 Representation::Tagged(), // callee
466 Representation::Tagged(), // call_data
467 Representation::Tagged(), // holder
468 Representation::External(), // api_function_address
469 Representation::Tagged(), // context
470 };
471 descriptor->register_param_count_ = 5;
472 descriptor->register_params_ = registers;
473 descriptor->param_representations_ = representations;
474 }
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +0000475}
476
477
lrn@chromium.org7516f052011-03-30 08:52:27 +0000478#define __ ACCESS_MASM(masm)
479
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000480
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000481static void EmitIdenticalObjectComparison(MacroAssembler* masm,
482 Label* slow,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000483 Condition cc);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000484static void EmitSmiNonsmiComparison(MacroAssembler* masm,
485 Register lhs,
486 Register rhs,
487 Label* rhs_not_nan,
488 Label* slow,
489 bool strict);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000490static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
491 Register lhs,
492 Register rhs);
493
494
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000495void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) {
496 // Update the static counter each time a new code stub is generated.
497 Isolate* isolate = masm->isolate();
498 isolate->counters()->code_stubs()->Increment();
499
500 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate);
501 int param_count = descriptor->register_param_count_;
502 {
503 // Call the runtime system in a fresh internal frame.
504 FrameScope scope(masm, StackFrame::INTERNAL);
505 ASSERT(descriptor->register_param_count_ == 0 ||
506 a0.is(descriptor->register_params_[param_count - 1]));
machenbach@chromium.org6f1040e2014-02-04 07:54:22 +0000507 // Push arguments, adjust sp.
508 __ Subu(sp, sp, Operand(param_count * kPointerSize));
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000509 for (int i = 0; i < param_count; ++i) {
machenbach@chromium.org6f1040e2014-02-04 07:54:22 +0000510 // Store argument to stack.
511 __ sw(descriptor->register_params_[i],
512 MemOperand(sp, (param_count-1-i) * kPointerSize));
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000513 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000514 ExternalReference miss = descriptor->miss_handler();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000515 __ CallExternalReference(miss, descriptor->register_param_count_);
516 }
517
518 __ Ret();
519}
520
521
lrn@chromium.org7516f052011-03-30 08:52:27 +0000522// Takes a Smi and converts to an IEEE 64 bit floating point value in two
523// registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and
524// 52 fraction bits (20 in the first word, 32 in the second). Zeros is a
525// scratch register. Destroys the source register. No GC occurs during this
526// stub so you don't have to set up the frame.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000527class ConvertToDoubleStub : public PlatformCodeStub {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000528 public:
529 ConvertToDoubleStub(Register result_reg_1,
530 Register result_reg_2,
531 Register source_reg,
532 Register scratch_reg)
533 : result1_(result_reg_1),
534 result2_(result_reg_2),
535 source_(source_reg),
536 zeros_(scratch_reg) { }
537
538 private:
539 Register result1_;
540 Register result2_;
541 Register source_;
542 Register zeros_;
543
544 // Minor key encoding in 16 bits.
545 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
546 class OpBits: public BitField<Token::Value, 2, 14> {};
547
548 Major MajorKey() { return ConvertToDouble; }
549 int MinorKey() {
550 // Encode the parameters in a unique 16 bit value.
551 return result1_.code() +
552 (result2_.code() << 4) +
553 (source_.code() << 8) +
554 (zeros_.code() << 12);
555 }
556
557 void Generate(MacroAssembler* masm);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000558};
559
560
561void ConvertToDoubleStub::Generate(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000562#ifndef BIG_ENDIAN_FLOATING_POINT
563 Register exponent = result1_;
564 Register mantissa = result2_;
565#else
566 Register exponent = result2_;
567 Register mantissa = result1_;
568#endif
569 Label not_special;
570 // Convert from Smi to integer.
571 __ sra(source_, source_, kSmiTagSize);
572 // Move sign bit from source to destination. This works because the sign bit
573 // in the exponent word of the double has the same position and polarity as
574 // the 2's complement sign bit in a Smi.
575 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
576 __ And(exponent, source_, Operand(HeapNumber::kSignMask));
577 // Subtract from 0 if source was negative.
578 __ subu(at, zero_reg, source_);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000579 __ Movn(source_, at, exponent);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000580
581 // We have -1, 0 or 1, which we treat specially. Register source_ contains
582 // absolute value: it is either equal to 1 (special case of -1 and 1),
583 // greater than 1 (not a special case) or less than 1 (special case of 0).
584 __ Branch(&not_special, gt, source_, Operand(1));
585
586 // For 1 or -1 we need to or in the 0 exponent (biased to 1023).
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000587 const uint32_t exponent_word_for_1 =
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000588 HeapNumber::kExponentBias << HeapNumber::kExponentShift;
589 // Safe to use 'at' as dest reg here.
590 __ Or(at, exponent, Operand(exponent_word_for_1));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000591 __ Movn(exponent, at, source_); // Write exp when source not 0.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000592 // 1, 0 and -1 all have 0 for the second word.
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000593 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000594 __ mov(mantissa, zero_reg);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000595
596 __ bind(&not_special);
597 // Count leading zeros.
598 // Gets the wrong answer for 0, but we already checked for that case above.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000599 __ Clz(zeros_, source_);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000600 // Compute exponent and or it into the exponent register.
601 // We use mantissa as a scratch register here.
602 __ li(mantissa, Operand(31 + HeapNumber::kExponentBias));
603 __ subu(mantissa, mantissa, zeros_);
604 __ sll(mantissa, mantissa, HeapNumber::kExponentShift);
605 __ Or(exponent, exponent, mantissa);
606
607 // Shift up the source chopping the top bit off.
608 __ Addu(zeros_, zeros_, Operand(1));
609 // This wouldn't work for 1.0 or -1.0 as the shift would be 32 which means 0.
610 __ sllv(source_, source_, zeros_);
611 // Compute lower part of fraction (last 12 bits).
612 __ sll(mantissa, source_, HeapNumber::kMantissaBitsInTopWord);
613 // And the top (top 20 bits).
614 __ srl(source_, source_, 32 - HeapNumber::kMantissaBitsInTopWord);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000615
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000616 __ Ret(USE_DELAY_SLOT);
617 __ or_(exponent, exponent, source_);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000618}
619
620
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000621void DoubleToIStub::Generate(MacroAssembler* masm) {
622 Label out_of_range, only_low, negate, done;
623 Register input_reg = source();
624 Register result_reg = destination();
625
626 int double_offset = offset();
627 // Account for saved regs if input is sp.
628 if (input_reg.is(sp)) double_offset += 3 * kPointerSize;
629
630 Register scratch =
631 GetRegisterThatIsNotOneOf(input_reg, result_reg);
632 Register scratch2 =
633 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch);
634 Register scratch3 =
635 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch, scratch2);
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000636 DoubleRegister double_scratch = kLithiumScratchDouble;
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000637
638 __ Push(scratch, scratch2, scratch3);
639
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000640 if (!skip_fastpath()) {
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000641 // Load double input.
642 __ ldc1(double_scratch, MemOperand(input_reg, double_offset));
643
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000644 // Clear cumulative exception flags and save the FCSR.
645 __ cfc1(scratch2, FCSR);
646 __ ctc1(zero_reg, FCSR);
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000647
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000648 // Try a conversion to a signed integer.
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000649 __ Trunc_w_d(double_scratch, double_scratch);
650 // Move the converted value into the result register.
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +0000651 __ mfc1(scratch3, double_scratch);
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000652
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000653 // Retrieve and restore the FCSR.
654 __ cfc1(scratch, FCSR);
655 __ ctc1(scratch2, FCSR);
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000656
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000657 // Check for overflow and NaNs.
658 __ And(
659 scratch, scratch,
660 kFCSROverflowFlagMask | kFCSRUnderflowFlagMask
661 | kFCSRInvalidOpFlagMask);
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +0000662 // If we had no exceptions then set result_reg and we are done.
663 Label error;
664 __ Branch(&error, ne, scratch, Operand(zero_reg));
665 __ Move(result_reg, scratch3);
666 __ Branch(&done);
667 __ bind(&error);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000668 }
669
670 // Load the double value and perform a manual truncation.
671 Register input_high = scratch2;
672 Register input_low = scratch3;
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000673
674 __ lw(input_low, MemOperand(input_reg, double_offset));
675 __ lw(input_high, MemOperand(input_reg, double_offset + kIntSize));
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000676
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000677 Label normal_exponent, restore_sign;
678 // Extract the biased exponent in result.
679 __ Ext(result_reg,
680 input_high,
681 HeapNumber::kExponentShift,
682 HeapNumber::kExponentBits);
683
684 // Check for Infinity and NaNs, which should return 0.
685 __ Subu(scratch, result_reg, HeapNumber::kExponentMask);
686 __ Movz(result_reg, zero_reg, scratch);
687 __ Branch(&done, eq, scratch, Operand(zero_reg));
688
689 // Express exponent as delta to (number of mantissa bits + 31).
690 __ Subu(result_reg,
691 result_reg,
692 Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31));
693
694 // If the delta is strictly positive, all bits would be shifted away,
695 // which means that we can return 0.
696 __ Branch(&normal_exponent, le, result_reg, Operand(zero_reg));
697 __ mov(result_reg, zero_reg);
698 __ Branch(&done);
699
700 __ bind(&normal_exponent);
701 const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1;
702 // Calculate shift.
703 __ Addu(scratch, result_reg, Operand(kShiftBase + HeapNumber::kMantissaBits));
704
705 // Save the sign.
706 Register sign = result_reg;
707 result_reg = no_reg;
708 __ And(sign, input_high, Operand(HeapNumber::kSignMask));
709
710 // On ARM shifts > 31 bits are valid and will result in zero. On MIPS we need
711 // to check for this specific case.
712 Label high_shift_needed, high_shift_done;
713 __ Branch(&high_shift_needed, lt, scratch, Operand(32));
714 __ mov(input_high, zero_reg);
715 __ Branch(&high_shift_done);
716 __ bind(&high_shift_needed);
717
718 // Set the implicit 1 before the mantissa part in input_high.
719 __ Or(input_high,
720 input_high,
721 Operand(1 << HeapNumber::kMantissaBitsInTopWord));
722 // Shift the mantissa bits to the correct position.
723 // We don't need to clear non-mantissa bits as they will be shifted away.
724 // If they weren't, it would mean that the answer is in the 32bit range.
725 __ sllv(input_high, input_high, scratch);
726
727 __ bind(&high_shift_done);
728
729 // Replace the shifted bits with bits from the lower mantissa word.
730 Label pos_shift, shift_done;
731 __ li(at, 32);
732 __ subu(scratch, at, scratch);
733 __ Branch(&pos_shift, ge, scratch, Operand(zero_reg));
734
735 // Negate scratch.
736 __ Subu(scratch, zero_reg, scratch);
737 __ sllv(input_low, input_low, scratch);
738 __ Branch(&shift_done);
739
740 __ bind(&pos_shift);
741 __ srlv(input_low, input_low, scratch);
742
743 __ bind(&shift_done);
744 __ Or(input_high, input_high, Operand(input_low));
745 // Restore sign if necessary.
746 __ mov(scratch, sign);
747 result_reg = sign;
748 sign = no_reg;
749 __ Subu(result_reg, zero_reg, input_high);
750 __ Movz(result_reg, input_high, scratch);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000751
752 __ bind(&done);
753
754 __ Pop(scratch, scratch2, scratch3);
755 __ Ret();
756}
757
758
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000759void WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(
760 Isolate* isolate) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000761 WriteInt32ToHeapNumberStub stub1(a1, v0, a2, a3);
762 WriteInt32ToHeapNumberStub stub2(a2, v0, a3, a0);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +0000763 stub1.GetCode(isolate);
764 stub2.GetCode(isolate);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000765}
766
767
lrn@chromium.org7516f052011-03-30 08:52:27 +0000768// See comment for class, this does NOT work for int32's that are in Smi range.
769void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000770 Label max_negative_int;
771 // the_int_ has the answer which is a signed int32 but not a Smi.
772 // We test for the special value that has a different exponent.
773 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
774 // Test sign, and save for later conditionals.
775 __ And(sign_, the_int_, Operand(0x80000000u));
776 __ Branch(&max_negative_int, eq, the_int_, Operand(0x80000000u));
777
778 // Set up the correct exponent in scratch_. All non-Smi int32s have the same.
779 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased).
780 uint32_t non_smi_exponent =
781 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
782 __ li(scratch_, Operand(non_smi_exponent));
783 // Set the sign bit in scratch_ if the value was negative.
784 __ or_(scratch_, scratch_, sign_);
785 // Subtract from 0 if the value was negative.
786 __ subu(at, zero_reg, the_int_);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000787 __ Movn(the_int_, at, sign_);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000788 // We should be masking the implict first digit of the mantissa away here,
789 // but it just ends up combining harmlessly with the last digit of the
790 // exponent that happens to be 1. The sign bit is 0 so we shift 10 to get
791 // the most significant 1 to hit the last bit of the 12 bit sign and exponent.
792 ASSERT(((1 << HeapNumber::kExponentShift) & non_smi_exponent) != 0);
793 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
794 __ srl(at, the_int_, shift_distance);
795 __ or_(scratch_, scratch_, at);
796 __ sw(scratch_, FieldMemOperand(the_heap_number_,
797 HeapNumber::kExponentOffset));
798 __ sll(scratch_, the_int_, 32 - shift_distance);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000799 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000800 __ sw(scratch_, FieldMemOperand(the_heap_number_,
801 HeapNumber::kMantissaOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000802
803 __ bind(&max_negative_int);
804 // The max negative int32 is stored as a positive number in the mantissa of
805 // a double because it uses a sign bit instead of using two's complement.
806 // The actual mantissa bits stored are all 0 because the implicit most
807 // significant 1 bit is not stored.
808 non_smi_exponent += 1 << HeapNumber::kExponentShift;
809 __ li(scratch_, Operand(HeapNumber::kSignMask | non_smi_exponent));
810 __ sw(scratch_,
811 FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset));
812 __ mov(scratch_, zero_reg);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000813 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000814 __ sw(scratch_,
815 FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000816}
817
818
819// Handle the case where the lhs and rhs are the same object.
820// Equality is almost reflexive (everything but NaN), so this is a test
821// for "identity and not NaN".
822static void EmitIdenticalObjectComparison(MacroAssembler* masm,
823 Label* slow,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000824 Condition cc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000825 Label not_identical;
826 Label heap_number, return_equal;
827 Register exp_mask_reg = t5;
828
829 __ Branch(&not_identical, ne, a0, Operand(a1));
830
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000831 __ li(exp_mask_reg, Operand(HeapNumber::kExponentMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000832
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000833 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000834 // so we do the second best thing - test it ourselves.
835 // They are both equal and they are not both Smis so both of them are not
836 // Smis. If it's not a heap number, then return equal.
837 if (cc == less || cc == greater) {
838 __ GetObjectType(a0, t4, t4);
839 __ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE));
840 } else {
841 __ GetObjectType(a0, t4, t4);
842 __ Branch(&heap_number, eq, t4, Operand(HEAP_NUMBER_TYPE));
843 // Comparing JS objects with <=, >= is complicated.
844 if (cc != eq) {
845 __ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE));
846 // Normally here we fall through to return_equal, but undefined is
847 // special: (undefined == undefined) == true, but
848 // (undefined <= undefined) == false! See ECMAScript 11.8.5.
849 if (cc == less_equal || cc == greater_equal) {
850 __ Branch(&return_equal, ne, t4, Operand(ODDBALL_TYPE));
851 __ LoadRoot(t2, Heap::kUndefinedValueRootIndex);
852 __ Branch(&return_equal, ne, a0, Operand(t2));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000853 ASSERT(is_int16(GREATER) && is_int16(LESS));
854 __ Ret(USE_DELAY_SLOT);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000855 if (cc == le) {
856 // undefined <= undefined should fail.
857 __ li(v0, Operand(GREATER));
858 } else {
859 // undefined >= undefined should fail.
860 __ li(v0, Operand(LESS));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000861 }
862 }
863 }
864 }
865
866 __ bind(&return_equal);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000867 ASSERT(is_int16(GREATER) && is_int16(LESS));
868 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000869 if (cc == less) {
870 __ li(v0, Operand(GREATER)); // Things aren't less than themselves.
871 } else if (cc == greater) {
872 __ li(v0, Operand(LESS)); // Things aren't greater than themselves.
873 } else {
874 __ mov(v0, zero_reg); // Things are <=, >=, ==, === themselves.
875 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000876
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000877 // For less and greater we don't have to check for NaN since the result of
878 // x < x is false regardless. For the others here is some code to check
879 // for NaN.
880 if (cc != lt && cc != gt) {
881 __ bind(&heap_number);
882 // It is a heap number, so return non-equal if it's NaN and equal if it's
883 // not NaN.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000884
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000885 // The representation of NaN values has all exponent bits (52..62) set,
886 // and not all mantissa bits (0..51) clear.
887 // Read top bits of double representation (second word of value).
888 __ lw(t2, FieldMemOperand(a0, HeapNumber::kExponentOffset));
889 // Test that exponent bits are all set.
890 __ And(t3, t2, Operand(exp_mask_reg));
891 // If all bits not set (ne cond), then not a NaN, objects are equal.
892 __ Branch(&return_equal, ne, t3, Operand(exp_mask_reg));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000893
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000894 // Shift out flag and all exponent bits, retaining only mantissa.
895 __ sll(t2, t2, HeapNumber::kNonMantissaBitsInTopWord);
896 // Or with all low-bits of mantissa.
897 __ lw(t3, FieldMemOperand(a0, HeapNumber::kMantissaOffset));
898 __ Or(v0, t3, Operand(t2));
899 // For equal we already have the right value in v0: Return zero (equal)
900 // if all bits in mantissa are zero (it's an Infinity) and non-zero if
901 // not (it's a NaN). For <= and >= we need to load v0 with the failing
902 // value if it's a NaN.
903 if (cc != eq) {
904 // All-zero means Infinity means equal.
905 __ Ret(eq, v0, Operand(zero_reg));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000906 ASSERT(is_int16(GREATER) && is_int16(LESS));
907 __ Ret(USE_DELAY_SLOT);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000908 if (cc == le) {
909 __ li(v0, Operand(GREATER)); // NaN <= NaN should fail.
910 } else {
911 __ li(v0, Operand(LESS)); // NaN >= NaN should fail.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000912 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000913 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000914 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000915 // No fall through here.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000916
917 __ bind(&not_identical);
918}
919
920
921static void EmitSmiNonsmiComparison(MacroAssembler* masm,
922 Register lhs,
923 Register rhs,
924 Label* both_loaded_as_doubles,
925 Label* slow,
926 bool strict) {
927 ASSERT((lhs.is(a0) && rhs.is(a1)) ||
928 (lhs.is(a1) && rhs.is(a0)));
929
930 Label lhs_is_smi;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000931 __ JumpIfSmi(lhs, &lhs_is_smi);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000932 // Rhs is a Smi.
933 // Check whether the non-smi is a heap number.
934 __ GetObjectType(lhs, t4, t4);
935 if (strict) {
936 // If lhs was not a number and rhs was a Smi then strict equality cannot
937 // succeed. Return non-equal (lhs is already not zero).
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000938 __ Ret(USE_DELAY_SLOT, ne, t4, Operand(HEAP_NUMBER_TYPE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000939 __ mov(v0, lhs);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000940 } else {
941 // Smi compared non-strictly with a non-Smi non-heap-number. Call
942 // the runtime.
943 __ Branch(slow, ne, t4, Operand(HEAP_NUMBER_TYPE));
944 }
945
946 // Rhs is a smi, lhs is a number.
947 // Convert smi rhs to double.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000948 __ sra(at, rhs, kSmiTagSize);
949 __ mtc1(at, f14);
950 __ cvt_d_w(f14, f14);
951 __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000952
953 // We now have both loaded as doubles.
954 __ jmp(both_loaded_as_doubles);
955
956 __ bind(&lhs_is_smi);
957 // Lhs is a Smi. Check whether the non-smi is a heap number.
958 __ GetObjectType(rhs, t4, t4);
959 if (strict) {
960 // If lhs was not a number and rhs was a Smi then strict equality cannot
961 // succeed. Return non-equal.
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000962 __ Ret(USE_DELAY_SLOT, ne, t4, Operand(HEAP_NUMBER_TYPE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000963 __ li(v0, Operand(1));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000964 } else {
965 // Smi compared non-strictly with a non-Smi non-heap-number. Call
966 // the runtime.
967 __ Branch(slow, ne, t4, Operand(HEAP_NUMBER_TYPE));
968 }
969
970 // Lhs is a smi, rhs is a number.
971 // Convert smi lhs to double.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000972 __ sra(at, lhs, kSmiTagSize);
973 __ mtc1(at, f12);
974 __ cvt_d_w(f12, f12);
975 __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000976 // Fall through to both_loaded_as_doubles.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000977}
978
979
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000980static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
981 Register lhs,
982 Register rhs) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000983 // If either operand is a JS object or an oddball value, then they are
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000984 // not equal since their pointers are different.
985 // There is no test for undetectability in strict equality.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000986 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000987 Label first_non_object;
988 // Get the type of the first operand into a2 and compare it with
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000989 // FIRST_SPEC_OBJECT_TYPE.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000990 __ GetObjectType(lhs, a2, a2);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000991 __ Branch(&first_non_object, less, a2, Operand(FIRST_SPEC_OBJECT_TYPE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000992
993 // Return non-zero.
994 Label return_not_equal;
995 __ bind(&return_not_equal);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000996 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000997 __ li(v0, Operand(1));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000998
999 __ bind(&first_non_object);
1000 // Check for oddballs: true, false, null, undefined.
1001 __ Branch(&return_not_equal, eq, a2, Operand(ODDBALL_TYPE));
1002
1003 __ GetObjectType(rhs, a3, a3);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001004 __ Branch(&return_not_equal, greater, a3, Operand(FIRST_SPEC_OBJECT_TYPE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001005
1006 // Check for oddballs: true, false, null, undefined.
1007 __ Branch(&return_not_equal, eq, a3, Operand(ODDBALL_TYPE));
1008
ulan@chromium.org750145a2013-03-07 15:14:13 +00001009 // Now that we have the types we might as well check for
1010 // internalized-internalized.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001011 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
1012 __ Or(a2, a2, Operand(a3));
1013 __ And(at, a2, Operand(kIsNotStringMask | kIsNotInternalizedMask));
1014 __ Branch(&return_not_equal, eq, at, Operand(zero_reg));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001015}
1016
1017
1018static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
1019 Register lhs,
1020 Register rhs,
1021 Label* both_loaded_as_doubles,
1022 Label* not_heap_numbers,
1023 Label* slow) {
1024 __ GetObjectType(lhs, a3, a2);
1025 __ Branch(not_heap_numbers, ne, a2, Operand(HEAP_NUMBER_TYPE));
1026 __ lw(a2, FieldMemOperand(rhs, HeapObject::kMapOffset));
1027 // If first was a heap number & second wasn't, go to slow case.
1028 __ Branch(slow, ne, a3, Operand(a2));
1029
1030 // Both are heap numbers. Load them up then jump to the code we have
1031 // for that.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001032 __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
1033 __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
1034
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001035 __ jmp(both_loaded_as_doubles);
1036}
1037
1038
ulan@chromium.org750145a2013-03-07 15:14:13 +00001039// Fast negative check for internalized-to-internalized equality.
1040static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
1041 Register lhs,
1042 Register rhs,
1043 Label* possible_strings,
1044 Label* not_both_strings) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001045 ASSERT((lhs.is(a0) && rhs.is(a1)) ||
1046 (lhs.is(a1) && rhs.is(a0)));
1047
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001048 // a2 is object type of rhs.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001049 Label object_test;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001050 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001051 __ And(at, a2, Operand(kIsNotStringMask));
1052 __ Branch(&object_test, ne, at, Operand(zero_reg));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001053 __ And(at, a2, Operand(kIsNotInternalizedMask));
1054 __ Branch(possible_strings, ne, at, Operand(zero_reg));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001055 __ GetObjectType(rhs, a3, a3);
1056 __ Branch(not_both_strings, ge, a3, Operand(FIRST_NONSTRING_TYPE));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001057 __ And(at, a3, Operand(kIsNotInternalizedMask));
1058 __ Branch(possible_strings, ne, at, Operand(zero_reg));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001059
ulan@chromium.org750145a2013-03-07 15:14:13 +00001060 // Both are internalized strings. We already checked they weren't the same
1061 // pointer so they are not equal.
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001062 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001063 __ li(v0, Operand(1)); // Non-zero indicates not equal.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001064
1065 __ bind(&object_test);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001066 __ Branch(not_both_strings, lt, a2, Operand(FIRST_SPEC_OBJECT_TYPE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001067 __ GetObjectType(rhs, a2, a3);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001068 __ Branch(not_both_strings, lt, a3, Operand(FIRST_SPEC_OBJECT_TYPE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001069
1070 // If both objects are undetectable, they are equal. Otherwise, they
1071 // are not equal, since they are different objects and an object is not
1072 // equal to undefined.
1073 __ lw(a3, FieldMemOperand(lhs, HeapObject::kMapOffset));
1074 __ lbu(a2, FieldMemOperand(a2, Map::kBitFieldOffset));
1075 __ lbu(a3, FieldMemOperand(a3, Map::kBitFieldOffset));
1076 __ and_(a0, a2, a3);
1077 __ And(a0, a0, Operand(1 << Map::kIsUndetectable));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001078 __ Ret(USE_DELAY_SLOT);
1079 __ xori(v0, a0, 1 << Map::kIsUndetectable);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001080}
1081
1082
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001083static void ICCompareStub_CheckInputType(MacroAssembler* masm,
1084 Register input,
1085 Register scratch,
1086 CompareIC::State expected,
1087 Label* fail) {
1088 Label ok;
1089 if (expected == CompareIC::SMI) {
1090 __ JumpIfNotSmi(input, fail);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001091 } else if (expected == CompareIC::NUMBER) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001092 __ JumpIfSmi(input, &ok);
1093 __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail,
1094 DONT_DO_SMI_CHECK);
1095 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001096 // We could be strict about internalized/string here, but as long as
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001097 // hydrogen doesn't care, the stub doesn't have to care either.
1098 __ bind(&ok);
1099}
1100
1101
1102// On entry a1 and a2 are the values to be compared.
1103// On exit a0 is 0, positive or negative to indicate the result of
1104// the comparison.
1105void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
1106 Register lhs = a1;
1107 Register rhs = a0;
1108 Condition cc = GetCondition();
1109
1110 Label miss;
1111 ICCompareStub_CheckInputType(masm, lhs, a2, left_, &miss);
1112 ICCompareStub_CheckInputType(masm, rhs, a3, right_, &miss);
1113
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001114 Label slow; // Call builtin.
1115 Label not_smis, both_loaded_as_doubles;
1116
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001117 Label not_two_smis, smi_done;
1118 __ Or(a2, a1, a0);
1119 __ JumpIfNotSmi(a2, &not_two_smis);
1120 __ sra(a1, a1, 1);
1121 __ sra(a0, a0, 1);
1122 __ Ret(USE_DELAY_SLOT);
1123 __ subu(v0, a1, a0);
1124 __ bind(&not_two_smis);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001125
1126 // NOTICE! This code is only reached after a smi-fast-case check, so
1127 // it is certain that at least one operand isn't a smi.
1128
1129 // Handle the case where the objects are identical. Either returns the answer
1130 // or goes to slow. Only falls through if the objects were not identical.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001131 EmitIdenticalObjectComparison(masm, &slow, cc);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001132
1133 // If either is a Smi (we know that not both are), then they can only
1134 // be strictly equal if the other is a HeapNumber.
1135 STATIC_ASSERT(kSmiTag == 0);
1136 ASSERT_EQ(0, Smi::FromInt(0));
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001137 __ And(t2, lhs, Operand(rhs));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001138 __ JumpIfNotSmi(t2, &not_smis, t0);
1139 // One operand is a smi. EmitSmiNonsmiComparison generates code that can:
1140 // 1) Return the answer.
1141 // 2) Go to slow.
1142 // 3) Fall through to both_loaded_as_doubles.
1143 // 4) Jump to rhs_not_nan.
1144 // In cases 3 and 4 we have found out we were dealing with a number-number
1145 // comparison and the numbers have been loaded into f12 and f14 as doubles,
1146 // or in GP registers (a0, a1, a2, a3) depending on the presence of the FPU.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001147 EmitSmiNonsmiComparison(masm, lhs, rhs,
1148 &both_loaded_as_doubles, &slow, strict());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001149
1150 __ bind(&both_loaded_as_doubles);
1151 // f12, f14 are the double representations of the left hand side
1152 // and the right hand side if we have FPU. Otherwise a2, a3 represent
1153 // left hand side and a0, a1 represent right hand side.
1154
1155 Isolate* isolate = masm->isolate();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001156 Label nan;
1157 __ li(t0, Operand(LESS));
1158 __ li(t1, Operand(GREATER));
1159 __ li(t2, Operand(EQUAL));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001160
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001161 // Check if either rhs or lhs is NaN.
1162 __ BranchF(NULL, &nan, eq, f12, f14);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001163
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001164 // Check if LESS condition is satisfied. If true, move conditionally
1165 // result to v0.
1166 __ c(OLT, D, f12, f14);
1167 __ Movt(v0, t0);
1168 // Use previous check to store conditionally to v0 oposite condition
1169 // (GREATER). If rhs is equal to lhs, this will be corrected in next
1170 // check.
1171 __ Movf(v0, t1);
1172 // Check if EQUAL condition is satisfied. If true, move conditionally
1173 // result to v0.
1174 __ c(EQ, D, f12, f14);
1175 __ Movt(v0, t2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001176
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001177 __ Ret();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001178
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001179 __ bind(&nan);
1180 // NaN comparisons always fail.
1181 // Load whatever we need in v0 to make the comparison fail.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001182 ASSERT(is_int16(GREATER) && is_int16(LESS));
1183 __ Ret(USE_DELAY_SLOT);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001184 if (cc == lt || cc == le) {
1185 __ li(v0, Operand(GREATER));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001186 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001187 __ li(v0, Operand(LESS));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001188 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001189
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001190
1191 __ bind(&not_smis);
1192 // At this point we know we are dealing with two different objects,
1193 // and neither of them is a Smi. The objects are in lhs_ and rhs_.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001194 if (strict()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001195 // This returns non-equal for some object types, or falls through if it
1196 // was not lucky.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001197 EmitStrictTwoHeapObjectCompare(masm, lhs, rhs);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001198 }
1199
ulan@chromium.org750145a2013-03-07 15:14:13 +00001200 Label check_for_internalized_strings;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001201 Label flat_string_check;
1202 // Check for heap-number-heap-number comparison. Can jump to slow case,
1203 // or load both doubles and jump to the code that handles
ulan@chromium.org750145a2013-03-07 15:14:13 +00001204 // that case. If the inputs are not doubles then jumps to
1205 // check_for_internalized_strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001206 // In this case a2 will contain the type of lhs_.
1207 EmitCheckForTwoHeapNumbers(masm,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001208 lhs,
1209 rhs,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001210 &both_loaded_as_doubles,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001211 &check_for_internalized_strings,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001212 &flat_string_check);
1213
ulan@chromium.org750145a2013-03-07 15:14:13 +00001214 __ bind(&check_for_internalized_strings);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001215 if (cc == eq && !strict()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001216 // Returns an answer for two internalized strings or two
1217 // detectable objects.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001218 // Otherwise jumps to string case or not both strings case.
1219 // Assumes that a2 is the type of lhs_ on entry.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001220 EmitCheckForInternalizedStringsOrObjects(
1221 masm, lhs, rhs, &flat_string_check, &slow);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001222 }
1223
1224 // Check for both being sequential ASCII strings, and inline if that is the
1225 // case.
1226 __ bind(&flat_string_check);
1227
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001228 __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs, rhs, a2, a3, &slow);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001229
1230 __ IncrementCounter(isolate->counters()->string_compare_native(), 1, a2, a3);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001231 if (cc == eq) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001232 StringCompareStub::GenerateFlatAsciiStringEquals(masm,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001233 lhs,
1234 rhs,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001235 a2,
1236 a3,
1237 t0);
1238 } else {
1239 StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001240 lhs,
1241 rhs,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001242 a2,
1243 a3,
1244 t0,
1245 t1);
1246 }
1247 // Never falls through to here.
1248
1249 __ bind(&slow);
1250 // Prepare for call to builtin. Push object pointers, a0 (lhs) first,
1251 // a1 (rhs) second.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001252 __ Push(lhs, rhs);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001253 // Figure out which native to call and setup the arguments.
1254 Builtins::JavaScript native;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001255 if (cc == eq) {
1256 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001257 } else {
1258 native = Builtins::COMPARE;
1259 int ncr; // NaN compare result.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001260 if (cc == lt || cc == le) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001261 ncr = GREATER;
1262 } else {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001263 ASSERT(cc == gt || cc == ge); // Remaining cases.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001264 ncr = LESS;
1265 }
1266 __ li(a0, Operand(Smi::FromInt(ncr)));
1267 __ push(a0);
1268 }
1269
1270 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
1271 // tagged as a small integer.
1272 __ InvokeBuiltin(native, JUMP_FUNCTION);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001273
1274 __ bind(&miss);
1275 GenerateMiss(masm);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001276}
1277
1278
yangguo@chromium.org49546742013-12-23 16:17:49 +00001279void StoreRegistersStateStub::Generate(MacroAssembler* masm) {
1280 __ mov(t9, ra);
1281 __ pop(ra);
1282 if (save_doubles_ == kSaveFPRegs) {
1283 __ PushSafepointRegistersAndDoubles();
1284 } else {
1285 __ PushSafepointRegisters();
1286 }
1287 __ Jump(t9);
1288}
1289
1290
1291void RestoreRegistersStateStub::Generate(MacroAssembler* masm) {
1292 __ mov(t9, ra);
1293 __ pop(ra);
1294 __ StoreToSafepointRegisterSlot(t9, t9);
1295 if (save_doubles_ == kSaveFPRegs) {
1296 __ PopSafepointRegistersAndDoubles();
1297 } else {
1298 __ PopSafepointRegisters();
1299 }
1300 __ Jump(t9);
1301}
1302
1303
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001304void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
1305 // We don't allow a GC during a store buffer overflow so there is no need to
1306 // store the registers in any particular way, but we do have to store and
1307 // restore them.
1308 __ MultiPush(kJSCallerSaved | ra.bit());
1309 if (save_doubles_ == kSaveFPRegs) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001310 __ MultiPushFPU(kCallerSavedFPU);
1311 }
1312 const int argument_count = 1;
1313 const int fp_argument_count = 0;
1314 const Register scratch = a1;
1315
1316 AllowExternalCallThatCantCauseGC scope(masm);
1317 __ PrepareCallCFunction(argument_count, fp_argument_count, scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001318 __ li(a0, Operand(ExternalReference::isolate_address(masm->isolate())));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001319 __ CallCFunction(
1320 ExternalReference::store_buffer_overflow_function(masm->isolate()),
1321 argument_count);
1322 if (save_doubles_ == kSaveFPRegs) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001323 __ MultiPopFPU(kCallerSavedFPU);
1324 }
1325
1326 __ MultiPop(kJSCallerSaved | ra.bit());
1327 __ Ret();
1328}
1329
1330
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001331void MathPowStub::Generate(MacroAssembler* masm) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001332 const Register base = a1;
1333 const Register exponent = a2;
1334 const Register heapnumbermap = t1;
1335 const Register heapnumber = v0;
1336 const DoubleRegister double_base = f2;
1337 const DoubleRegister double_exponent = f4;
1338 const DoubleRegister double_result = f0;
1339 const DoubleRegister double_scratch = f6;
1340 const FPURegister single_scratch = f8;
1341 const Register scratch = t5;
1342 const Register scratch2 = t3;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001343
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001344 Label call_runtime, done, int_exponent;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001345 if (exponent_type_ == ON_STACK) {
1346 Label base_is_smi, unpack_exponent;
1347 // The exponent and base are supplied as arguments on the stack.
1348 // This can only happen if the stub is called from non-optimized code.
1349 // Load input parameters from stack to double registers.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001350 __ lw(base, MemOperand(sp, 1 * kPointerSize));
1351 __ lw(exponent, MemOperand(sp, 0 * kPointerSize));
1352
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001353 __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001354
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001355 __ UntagAndJumpIfSmi(scratch, base, &base_is_smi);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001356 __ lw(scratch, FieldMemOperand(base, JSObject::kMapOffset));
1357 __ Branch(&call_runtime, ne, scratch, Operand(heapnumbermap));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001358
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001359 __ ldc1(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
1360 __ jmp(&unpack_exponent);
1361
1362 __ bind(&base_is_smi);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001363 __ mtc1(scratch, single_scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001364 __ cvt_d_w(double_base, single_scratch);
1365 __ bind(&unpack_exponent);
1366
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001367 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001368
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001369 __ lw(scratch, FieldMemOperand(exponent, JSObject::kMapOffset));
1370 __ Branch(&call_runtime, ne, scratch, Operand(heapnumbermap));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001371 __ ldc1(double_exponent,
1372 FieldMemOperand(exponent, HeapNumber::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001373 } else if (exponent_type_ == TAGGED) {
1374 // Base is already in double_base.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001375 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001376
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001377 __ ldc1(double_exponent,
1378 FieldMemOperand(exponent, HeapNumber::kValueOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001379 }
1380
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001381 if (exponent_type_ != INTEGER) {
1382 Label int_exponent_convert;
1383 // Detect integer exponents stored as double.
1384 __ EmitFPUTruncate(kRoundToMinusInf,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001385 scratch,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001386 double_exponent,
1387 at,
1388 double_scratch,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001389 scratch2,
1390 kCheckForInexactConversion);
1391 // scratch2 == 0 means there was no conversion error.
1392 __ Branch(&int_exponent_convert, eq, scratch2, Operand(zero_reg));
1393
1394 if (exponent_type_ == ON_STACK) {
1395 // Detect square root case. Crankshaft detects constant +/-0.5 at
1396 // compile time and uses DoMathPowHalf instead. We then skip this check
1397 // for non-constant cases of +/-0.5 as these hardly occur.
1398 Label not_plus_half;
1399
1400 // Test for 0.5.
1401 __ Move(double_scratch, 0.5);
1402 __ BranchF(USE_DELAY_SLOT,
1403 &not_plus_half,
1404 NULL,
1405 ne,
1406 double_exponent,
1407 double_scratch);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001408 // double_scratch can be overwritten in the delay slot.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001409 // Calculates square root of base. Check for the special case of
1410 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
1411 __ Move(double_scratch, -V8_INFINITY);
1412 __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
1413 __ neg_d(double_result, double_scratch);
1414
1415 // Add +0 to convert -0 to +0.
1416 __ add_d(double_scratch, double_base, kDoubleRegZero);
1417 __ sqrt_d(double_result, double_scratch);
1418 __ jmp(&done);
1419
1420 __ bind(&not_plus_half);
1421 __ Move(double_scratch, -0.5);
1422 __ BranchF(USE_DELAY_SLOT,
1423 &call_runtime,
1424 NULL,
1425 ne,
1426 double_exponent,
1427 double_scratch);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001428 // double_scratch can be overwritten in the delay slot.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001429 // Calculates square root of base. Check for the special case of
1430 // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
1431 __ Move(double_scratch, -V8_INFINITY);
1432 __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
1433 __ Move(double_result, kDoubleRegZero);
1434
1435 // Add +0 to convert -0 to +0.
1436 __ add_d(double_scratch, double_base, kDoubleRegZero);
1437 __ Move(double_result, 1);
1438 __ sqrt_d(double_scratch, double_scratch);
1439 __ div_d(double_result, double_result, double_scratch);
1440 __ jmp(&done);
1441 }
1442
1443 __ push(ra);
1444 {
1445 AllowExternalCallThatCantCauseGC scope(masm);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001446 __ PrepareCallCFunction(0, 2, scratch2);
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00001447 __ MovToFloatParameters(double_base, double_exponent);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001448 __ CallCFunction(
1449 ExternalReference::power_double_double_function(masm->isolate()),
1450 0, 2);
1451 }
1452 __ pop(ra);
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00001453 __ MovFromFloatResult(double_result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001454 __ jmp(&done);
1455
1456 __ bind(&int_exponent_convert);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001457 }
1458
1459 // Calculate power with integer exponent.
1460 __ bind(&int_exponent);
1461
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001462 // Get two copies of exponent in the registers scratch and exponent.
1463 if (exponent_type_ == INTEGER) {
1464 __ mov(scratch, exponent);
1465 } else {
1466 // Exponent has previously been stored into scratch as untagged integer.
1467 __ mov(exponent, scratch);
1468 }
1469
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001470 __ mov_d(double_scratch, double_base); // Back up base.
1471 __ Move(double_result, 1.0);
1472
1473 // Get absolute value of exponent.
1474 Label positive_exponent;
1475 __ Branch(&positive_exponent, ge, scratch, Operand(zero_reg));
1476 __ Subu(scratch, zero_reg, scratch);
1477 __ bind(&positive_exponent);
1478
1479 Label while_true, no_carry, loop_end;
1480 __ bind(&while_true);
1481
1482 __ And(scratch2, scratch, 1);
1483
1484 __ Branch(&no_carry, eq, scratch2, Operand(zero_reg));
1485 __ mul_d(double_result, double_result, double_scratch);
1486 __ bind(&no_carry);
1487
1488 __ sra(scratch, scratch, 1);
1489
1490 __ Branch(&loop_end, eq, scratch, Operand(zero_reg));
1491 __ mul_d(double_scratch, double_scratch, double_scratch);
1492
1493 __ Branch(&while_true);
1494
1495 __ bind(&loop_end);
1496
1497 __ Branch(&done, ge, exponent, Operand(zero_reg));
1498 __ Move(double_scratch, 1.0);
1499 __ div_d(double_result, double_scratch, double_result);
1500 // Test whether result is zero. Bail out to check for subnormal result.
1501 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
1502 __ BranchF(&done, NULL, ne, double_result, kDoubleRegZero);
1503
1504 // double_exponent may not contain the exponent value if the input was a
1505 // smi. We set it with exponent value before bailing out.
1506 __ mtc1(exponent, single_scratch);
1507 __ cvt_d_w(double_exponent, single_scratch);
1508
1509 // Returning or bailing out.
1510 Counters* counters = masm->isolate()->counters();
1511 if (exponent_type_ == ON_STACK) {
1512 // The arguments are still on the stack.
1513 __ bind(&call_runtime);
machenbach@chromium.org2f599e52014-03-31 14:24:38 +00001514 __ TailCallRuntime(Runtime::kHiddenMathPow, 2, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001515
1516 // The stub is called from non-optimized code, which expects the result
1517 // as heap number in exponent.
1518 __ bind(&done);
1519 __ AllocateHeapNumber(
1520 heapnumber, scratch, scratch2, heapnumbermap, &call_runtime);
1521 __ sdc1(double_result,
1522 FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
1523 ASSERT(heapnumber.is(v0));
1524 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
1525 __ DropAndRet(2);
1526 } else {
1527 __ push(ra);
1528 {
1529 AllowExternalCallThatCantCauseGC scope(masm);
1530 __ PrepareCallCFunction(0, 2, scratch);
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00001531 __ MovToFloatParameters(double_base, double_exponent);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001532 __ CallCFunction(
1533 ExternalReference::power_double_double_function(masm->isolate()),
1534 0, 2);
1535 }
1536 __ pop(ra);
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00001537 __ MovFromFloatResult(double_result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001538
1539 __ bind(&done);
1540 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
1541 __ Ret();
1542 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001543}
1544
1545
lrn@chromium.org7516f052011-03-30 08:52:27 +00001546bool CEntryStub::NeedsImmovableCode() {
1547 return true;
1548}
1549
1550
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001551void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
1552 CEntryStub::GenerateAheadOfTime(isolate);
1553 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
1554 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001555 StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001556 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001557 CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00001558 BinaryOpICStub::GenerateAheadOfTime(isolate);
yangguo@chromium.org49546742013-12-23 16:17:49 +00001559 StoreRegistersStateStub::GenerateAheadOfTime(isolate);
1560 RestoreRegistersStateStub::GenerateAheadOfTime(isolate);
ulan@chromium.org0f13e742014-01-03 15:51:11 +00001561 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
yangguo@chromium.org49546742013-12-23 16:17:49 +00001562}
1563
1564
1565void StoreRegistersStateStub::GenerateAheadOfTime(
1566 Isolate* isolate) {
1567 StoreRegistersStateStub stub1(kDontSaveFPRegs);
1568 stub1.GetCode(isolate);
1569 // Hydrogen code stubs need stub2 at snapshot time.
1570 StoreRegistersStateStub stub2(kSaveFPRegs);
1571 stub2.GetCode(isolate);
1572}
1573
1574
1575void RestoreRegistersStateStub::GenerateAheadOfTime(
1576 Isolate* isolate) {
1577 RestoreRegistersStateStub stub1(kDontSaveFPRegs);
1578 stub1.GetCode(isolate);
1579 // Hydrogen code stubs need stub2 at snapshot time.
1580 RestoreRegistersStateStub stub2(kSaveFPRegs);
1581 stub2.GetCode(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001582}
1583
1584
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001585void CodeStub::GenerateFPStubs(Isolate* isolate) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001586 SaveFPRegsMode mode = kSaveFPRegs;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001587 CEntryStub save_doubles(1, mode);
1588 StoreBufferOverflowStub stub(mode);
1589 // These stubs might already be in the snapshot, detect that and don't
1590 // regenerate, which would lead to code stub initialization state being messed
1591 // up.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001592 Code* save_doubles_code;
1593 if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) {
1594 save_doubles_code = *save_doubles.GetCode(isolate);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001595 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001596 Code* store_buffer_overflow_code;
1597 if (!stub.FindCodeInCache(&store_buffer_overflow_code, isolate)) {
1598 store_buffer_overflow_code = *stub.GetCode(isolate);
1599 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001600 isolate->set_fp_stubs_generated(true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001601}
1602
1603
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001604void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001605 CEntryStub stub(1, kDontSaveFPRegs);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00001606 stub.GetCode(isolate);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001607}
1608
1609
lrn@chromium.org7516f052011-03-30 08:52:27 +00001610void CEntryStub::GenerateCore(MacroAssembler* masm,
1611 Label* throw_normal_exception,
1612 Label* throw_termination_exception,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001613 bool do_gc,
1614 bool always_allocate) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001615 // v0: result parameter for PerformGC, if any
1616 // s0: number of arguments including receiver (C callee-saved)
1617 // s1: pointer to the first argument (C callee-saved)
1618 // s2: pointer to builtin function (C callee-saved)
1619
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001620 Isolate* isolate = masm->isolate();
1621
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001622 if (do_gc) {
1623 // Move result passed in v0 into a0 to call PerformGC.
1624 __ mov(a0, v0);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001625 __ PrepareCallCFunction(2, 0, a1);
1626 __ li(a1, Operand(ExternalReference::isolate_address(masm->isolate())));
1627 __ CallCFunction(ExternalReference::perform_gc_function(isolate), 2, 0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001628 }
1629
1630 ExternalReference scope_depth =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001631 ExternalReference::heap_always_allocate_scope_depth(isolate);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001632 if (always_allocate) {
1633 __ li(a0, Operand(scope_depth));
1634 __ lw(a1, MemOperand(a0));
1635 __ Addu(a1, a1, Operand(1));
1636 __ sw(a1, MemOperand(a0));
1637 }
1638
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001639 // Prepare arguments for C routine.
1640 // a0 = argc
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001641 __ mov(a0, s0);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001642 // a1 = argv (set in the delay slot after find_ra below).
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001643
1644 // We are calling compiled C/C++ code. a0 and a1 hold our two arguments. We
1645 // also need to reserve the 4 argument slots on the stack.
1646
1647 __ AssertStackIsAligned();
1648
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001649 __ li(a2, Operand(ExternalReference::isolate_address(isolate)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001650
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001651 // To let the GC traverse the return address of the exit frames, we need to
1652 // know where the return address is. The CEntryStub is unmovable, so
1653 // we can store the address on the stack to be able to find it again and
1654 // we never have to restore it, because it will not change.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001655 { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
1656 // This branch-and-link sequence is needed to find the current PC on mips,
1657 // saved to the ra register.
1658 // Use masm-> here instead of the double-underscore macro since extra
1659 // coverage code can interfere with the proper calculation of ra.
1660 Label find_ra;
1661 masm->bal(&find_ra); // bal exposes branch delay slot.
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001662 masm->mov(a1, s1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001663 masm->bind(&find_ra);
1664
1665 // Adjust the value in ra to point to the correct return location, 2nd
1666 // instruction past the real call into C code (the jalr(t9)), and push it.
1667 // This is the return address of the exit frame.
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001668 const int kNumInstructionsToJump = 5;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001669 masm->Addu(ra, ra, kNumInstructionsToJump * kPointerSize);
1670 masm->sw(ra, MemOperand(sp)); // This spot was reserved in EnterExitFrame.
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001671 // Stack space reservation moved to the branch delay slot below.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001672 // Stack is still aligned.
1673
1674 // Call the C routine.
1675 masm->mov(t9, s2); // Function pointer to t9 to conform to ABI for PIC.
1676 masm->jalr(t9);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001677 // Set up sp in the delay slot.
1678 masm->addiu(sp, sp, -kCArgsSlotsSize);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001679 // Make sure the stored 'ra' points to this position.
1680 ASSERT_EQ(kNumInstructionsToJump,
1681 masm->InstructionsGeneratedSince(&find_ra));
1682 }
1683
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001684 if (always_allocate) {
1685 // It's okay to clobber a2 and a3 here. v0 & v1 contain result.
1686 __ li(a2, Operand(scope_depth));
1687 __ lw(a3, MemOperand(a2));
1688 __ Subu(a3, a3, Operand(1));
1689 __ sw(a3, MemOperand(a2));
1690 }
1691
1692 // Check for failure result.
1693 Label failure_returned;
1694 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
1695 __ addiu(a2, v0, 1);
1696 __ andi(t0, a2, kFailureTagMask);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001697 __ Branch(USE_DELAY_SLOT, &failure_returned, eq, t0, Operand(zero_reg));
1698 // Restore stack (remove arg slots) in branch delay slot.
1699 __ addiu(sp, sp, kCArgsSlotsSize);
1700
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001701
1702 // Exit C frame and return.
1703 // v0:v1: result
1704 // sp: stack pointer
1705 // fp: frame pointer
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001706 __ LeaveExitFrame(save_doubles_, s0, true, EMIT_RETURN);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001707
1708 // Check if we should retry or throw exception.
1709 Label retry;
1710 __ bind(&failure_returned);
1711 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
1712 __ andi(t0, v0, ((1 << kFailureTypeTagSize) - 1) << kFailureTagSize);
1713 __ Branch(&retry, eq, t0, Operand(zero_reg));
1714
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001715 // Retrieve the pending exception.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001716 __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001717 isolate)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001718 __ lw(v0, MemOperand(t0));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001719
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001720 // Clear the pending exception.
1721 __ li(a3, Operand(isolate->factory()->the_hole_value()));
1722 __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
1723 isolate)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001724 __ sw(a3, MemOperand(t0));
1725
1726 // Special handling of termination exceptions which are uncatchable
1727 // by javascript code.
danno@chromium.org88aa0582012-03-23 15:11:57 +00001728 __ LoadRoot(t0, Heap::kTerminationExceptionRootIndex);
1729 __ Branch(throw_termination_exception, eq, v0, Operand(t0));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001730
1731 // Handle normal exception.
1732 __ jmp(throw_normal_exception);
1733
1734 __ bind(&retry);
1735 // Last failure (v0) will be moved to (a0) for parameter when retrying.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001736}
1737
1738
1739void CEntryStub::Generate(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001740 // Called from JavaScript; parameters are on stack as if calling JS function
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001741 // s0: number of arguments including receiver
1742 // s1: size of arguments excluding receiver
1743 // s2: pointer to builtin function
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001744 // fp: frame pointer (restored after C call)
1745 // sp: stack pointer (restored as callee's sp after C call)
1746 // cp: current context (C callee-saved)
1747
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00001748 ProfileEntryHookStub::MaybeCallEntryHook(masm);
1749
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001750 // NOTE: Invocations of builtins may return failure objects
1751 // instead of a proper result. The builtin entry handles
1752 // this by performing a garbage collection and retrying the
1753 // builtin once.
1754
ulan@chromium.org6ff65142012-03-21 09:52:17 +00001755 // NOTE: s0-s2 hold the arguments of this function instead of a0-a2.
1756 // The reason for this is that these arguments would need to be saved anyway
1757 // so it's faster to set them up directly.
1758 // See MacroAssembler::PrepareCEntryArgs and PrepareCEntryFunction.
1759
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001760 // Compute the argv pointer in a callee-saved register.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001761 __ Addu(s1, sp, s1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001762
1763 // Enter the exit frame that transitions from JavaScript to C++.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001764 FrameScope scope(masm, StackFrame::MANUAL);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001765 __ EnterExitFrame(save_doubles_);
1766
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001767 // s0: number of arguments (C callee-saved)
1768 // s1: pointer to first argument (C callee-saved)
1769 // s2: pointer to builtin function (C callee-saved)
1770
1771 Label throw_normal_exception;
1772 Label throw_termination_exception;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001773
1774 // Call into the runtime system.
1775 GenerateCore(masm,
1776 &throw_normal_exception,
1777 &throw_termination_exception,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001778 false,
1779 false);
1780
1781 // Do space-specific GC and retry runtime call.
1782 GenerateCore(masm,
1783 &throw_normal_exception,
1784 &throw_termination_exception,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001785 true,
1786 false);
1787
1788 // Do full GC and retry runtime call one final time.
1789 Failure* failure = Failure::InternalError();
1790 __ li(v0, Operand(reinterpret_cast<int32_t>(failure)));
1791 GenerateCore(masm,
1792 &throw_normal_exception,
1793 &throw_termination_exception,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001794 true,
1795 true);
1796
svenpanne@chromium.orga87904f2014-03-27 14:14:22 +00001797 { FrameScope scope(masm, StackFrame::MANUAL);
1798 __ PrepareCallCFunction(0, v0);
1799 __ CallCFunction(
1800 ExternalReference::out_of_memory_function(masm->isolate()), 0);
1801 }
1802
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001803 __ bind(&throw_termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001804 __ ThrowUncatchable(v0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001805
1806 __ bind(&throw_normal_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001807 __ Throw(v0);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001808}
1809
1810
1811void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001812 Label invoke, handler_entry, exit;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001813 Isolate* isolate = masm->isolate();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001814
1815 // Registers:
1816 // a0: entry address
1817 // a1: function
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001818 // a2: receiver
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001819 // a3: argc
1820 //
1821 // Stack:
1822 // 4 args slots
1823 // args
1824
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00001825 ProfileEntryHookStub::MaybeCallEntryHook(masm);
1826
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001827 // Save callee saved registers on the stack.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001828 __ MultiPush(kCalleeSaved | ra.bit());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001829
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001830 // Save callee-saved FPU registers.
1831 __ MultiPushFPU(kCalleeSavedFPU);
1832 // Set up the reserved register for 0.0.
1833 __ Move(kDoubleRegZero, 0.0);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001834
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001835
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001836 // Load argv in s0 register.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001837 int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001838 offset_to_argv += kNumCalleeSavedFPU * kDoubleSize;
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001839
danno@chromium.org88aa0582012-03-23 15:11:57 +00001840 __ InitializeRootRegister();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001841 __ lw(s0, MemOperand(sp, offset_to_argv + kCArgsSlotsSize));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001842
1843 // We build an EntryFrame.
1844 __ li(t3, Operand(-1)); // Push a bad frame pointer to fail if it is used.
1845 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
1846 __ li(t2, Operand(Smi::FromInt(marker)));
1847 __ li(t1, Operand(Smi::FromInt(marker)));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001848 __ li(t0, Operand(ExternalReference(Isolate::kCEntryFPAddress,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001849 isolate)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001850 __ lw(t0, MemOperand(t0));
1851 __ Push(t3, t2, t1, t0);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001852 // Set up frame pointer for the frame to be pushed.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001853 __ addiu(fp, sp, -EntryFrameConstants::kCallerFPOffset);
1854
1855 // Registers:
1856 // a0: entry_address
1857 // a1: function
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001858 // a2: receiver_pointer
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001859 // a3: argc
1860 // s0: argv
1861 //
1862 // Stack:
1863 // caller fp |
1864 // function slot | entry frame
1865 // context slot |
1866 // bad fp (0xff...f) |
1867 // callee saved registers + ra
1868 // 4 args slots
1869 // args
1870
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001871 // If this is the outermost JS call, set js_entry_sp value.
1872 Label non_outermost_js;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001873 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001874 __ li(t1, Operand(ExternalReference(js_entry_sp)));
1875 __ lw(t2, MemOperand(t1));
1876 __ Branch(&non_outermost_js, ne, t2, Operand(zero_reg));
1877 __ sw(fp, MemOperand(t1));
1878 __ li(t0, Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
1879 Label cont;
1880 __ b(&cont);
1881 __ nop(); // Branch delay slot nop.
1882 __ bind(&non_outermost_js);
1883 __ li(t0, Operand(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
1884 __ bind(&cont);
1885 __ push(t0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001886
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001887 // Jump to a faked try block that does the invoke, with a faked catch
1888 // block that sets the pending exception.
1889 __ jmp(&invoke);
1890 __ bind(&handler_entry);
1891 handler_offset_ = handler_entry.pos();
1892 // Caught exception: Store result (exception) in the pending exception
1893 // field in the JSEnv and return a failure sentinel. Coming in here the
1894 // fp will be invalid because the PushTryHandler below sets it to 0 to
1895 // signal the existence of the JSEntry frame.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001896 __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001897 isolate)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001898 __ sw(v0, MemOperand(t0)); // We come back from 'invoke'. result is in v0.
1899 __ li(v0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
1900 __ b(&exit); // b exposes branch delay slot.
1901 __ nop(); // Branch delay slot nop.
1902
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00001903 // Invoke: Link this frame into the handler chain. There's only one
1904 // handler block in this code object, so its index is 0.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001905 __ bind(&invoke);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001906 __ PushTryHandler(StackHandler::JS_ENTRY, 0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001907 // If an exception not caught by another handler occurs, this handler
1908 // returns control to the code after the bal(&invoke) above, which
1909 // restores all kCalleeSaved registers (including cp and fp) to their
1910 // saved values before returning a failure to C.
1911
1912 // Clear any pending exceptions.
danno@chromium.org88aa0582012-03-23 15:11:57 +00001913 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001914 __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001915 isolate)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001916 __ sw(t1, MemOperand(t0));
1917
1918 // Invoke the function by calling through JS entry trampoline builtin.
1919 // Notice that we cannot store a reference to the trampoline code directly in
1920 // this stub, because runtime stubs are not traversed when doing GC.
1921
1922 // Registers:
1923 // a0: entry_address
1924 // a1: function
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001925 // a2: receiver_pointer
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001926 // a3: argc
1927 // s0: argv
1928 //
1929 // Stack:
1930 // handler frame
1931 // entry frame
1932 // callee saved registers + ra
1933 // 4 args slots
1934 // args
1935
1936 if (is_construct) {
1937 ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001938 isolate);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001939 __ li(t0, Operand(construct_entry));
1940 } else {
1941 ExternalReference entry(Builtins::kJSEntryTrampoline, masm->isolate());
1942 __ li(t0, Operand(entry));
1943 }
1944 __ lw(t9, MemOperand(t0)); // Deref address.
1945
1946 // Call JSEntryTrampoline.
1947 __ addiu(t9, t9, Code::kHeaderSize - kHeapObjectTag);
1948 __ Call(t9);
1949
danno@chromium.org40cb8782011-05-25 07:58:50 +00001950 // Unlink this frame from the handler chain.
1951 __ PopTryHandler();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001952
danno@chromium.org40cb8782011-05-25 07:58:50 +00001953 __ bind(&exit); // v0 holds result
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001954 // Check if the current stack frame is marked as the outermost JS frame.
1955 Label non_outermost_js_2;
1956 __ pop(t1);
danno@chromium.org88aa0582012-03-23 15:11:57 +00001957 __ Branch(&non_outermost_js_2,
1958 ne,
1959 t1,
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001960 Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
1961 __ li(t1, Operand(ExternalReference(js_entry_sp)));
1962 __ sw(zero_reg, MemOperand(t1));
1963 __ bind(&non_outermost_js_2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001964
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001965 // Restore the top frame descriptors from the stack.
1966 __ pop(t1);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001967 __ li(t0, Operand(ExternalReference(Isolate::kCEntryFPAddress,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001968 isolate)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001969 __ sw(t1, MemOperand(t0));
1970
1971 // Reset the stack to the callee saved registers.
1972 __ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset);
1973
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001974 // Restore callee-saved fpu registers.
1975 __ MultiPopFPU(kCalleeSavedFPU);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001976
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001977 // Restore callee saved registers from the stack.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001978 __ MultiPop(kCalleeSaved | ra.bit());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001979 // Return.
1980 __ Jump(ra);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001981}
1982
1983
danno@chromium.org40cb8782011-05-25 07:58:50 +00001984// Uses registers a0 to t0.
1985// Expected input (depending on whether args are in registers or on the stack):
1986// * object: a0 or at sp + 1 * kPointerSize.
1987// * function: a1 or at sp.
1988//
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001989// An inlined call site may have been generated before calling this stub.
1990// In this case the offset to the inline site to patch is passed on the stack,
1991// in the safepoint slot for register t0.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001992void InstanceofStub::Generate(MacroAssembler* masm) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001993 // Call site inlining and patching implies arguments in registers.
1994 ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck());
1995 // ReturnTrueFalse is only implemented for inlined call sites.
1996 ASSERT(!ReturnTrueFalseObject() || HasCallSiteInlineCheck());
1997
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001998 // Fixed register usage throughout the stub:
1999 const Register object = a0; // Object (lhs).
danno@chromium.org40cb8782011-05-25 07:58:50 +00002000 Register map = a3; // Map of the object.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002001 const Register function = a1; // Function (rhs).
2002 const Register prototype = t0; // Prototype of the function.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002003 const Register inline_site = t5;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002004 const Register scratch = a2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002005
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002006 const int32_t kDeltaToLoadBoolResult = 5 * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002007
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002008 Label slow, loop, is_instance, is_not_instance, not_js_object;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002009
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002010 if (!HasArgsInRegisters()) {
2011 __ lw(object, MemOperand(sp, 1 * kPointerSize));
2012 __ lw(function, MemOperand(sp, 0));
2013 }
2014
2015 // Check that the left hand is a JS object and load map.
2016 __ JumpIfSmi(object, &not_js_object);
2017 __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
2018
danno@chromium.org40cb8782011-05-25 07:58:50 +00002019 // If there is a call site cache don't look in the global cache, but do the
2020 // real lookup and update the call site cache.
2021 if (!HasCallSiteInlineCheck()) {
2022 Label miss;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002023 __ LoadRoot(at, Heap::kInstanceofCacheFunctionRootIndex);
2024 __ Branch(&miss, ne, function, Operand(at));
2025 __ LoadRoot(at, Heap::kInstanceofCacheMapRootIndex);
2026 __ Branch(&miss, ne, map, Operand(at));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002027 __ LoadRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
2028 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002029
danno@chromium.org40cb8782011-05-25 07:58:50 +00002030 __ bind(&miss);
2031 }
2032
2033 // Get the prototype of the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002034 __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002035
2036 // Check that the function prototype is a JS object.
2037 __ JumpIfSmi(prototype, &slow);
2038 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
2039
danno@chromium.org40cb8782011-05-25 07:58:50 +00002040 // Update the global instanceof or call site inlined cache with the current
2041 // map and function. The cached answer will be set when it is known below.
2042 if (!HasCallSiteInlineCheck()) {
2043 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
2044 __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);
2045 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002046 ASSERT(HasArgsInRegisters());
2047 // Patch the (relocated) inlined map check.
2048
2049 // The offset was stored in t0 safepoint slot.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002050 // (See LCodeGen::DoDeferredLInstanceOfKnownGlobal).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002051 __ LoadFromSafepointRegisterSlot(scratch, t0);
2052 __ Subu(inline_site, ra, scratch);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002053 // Get the map location in scratch and patch it.
2054 __ GetRelocatedValue(inline_site, scratch, v1); // v1 used as scratch.
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002055 __ sw(map, FieldMemOperand(scratch, Cell::kValueOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002056 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002057
2058 // Register mapping: a3 is object map and t0 is function prototype.
2059 // Get prototype of object into a2.
2060 __ lw(scratch, FieldMemOperand(map, Map::kPrototypeOffset));
2061
danno@chromium.org40cb8782011-05-25 07:58:50 +00002062 // We don't need map any more. Use it as a scratch register.
2063 Register scratch2 = map;
2064 map = no_reg;
2065
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002066 // Loop through the prototype chain looking for the function prototype.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002067 __ LoadRoot(scratch2, Heap::kNullValueRootIndex);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002068 __ bind(&loop);
2069 __ Branch(&is_instance, eq, scratch, Operand(prototype));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002070 __ Branch(&is_not_instance, eq, scratch, Operand(scratch2));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002071 __ lw(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset));
2072 __ lw(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
2073 __ Branch(&loop);
2074
2075 __ bind(&is_instance);
2076 ASSERT(Smi::FromInt(0) == 0);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002077 if (!HasCallSiteInlineCheck()) {
2078 __ mov(v0, zero_reg);
2079 __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
2080 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002081 // Patch the call site to return true.
2082 __ LoadRoot(v0, Heap::kTrueValueRootIndex);
2083 __ Addu(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
2084 // Get the boolean result location in scratch and patch it.
2085 __ PatchRelocatedValue(inline_site, scratch, v0);
2086
2087 if (!ReturnTrueFalseObject()) {
2088 ASSERT_EQ(Smi::FromInt(0), 0);
2089 __ mov(v0, zero_reg);
2090 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002091 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002092 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
2093
2094 __ bind(&is_not_instance);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002095 if (!HasCallSiteInlineCheck()) {
2096 __ li(v0, Operand(Smi::FromInt(1)));
2097 __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
2098 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002099 // Patch the call site to return false.
2100 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
2101 __ Addu(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
2102 // Get the boolean result location in scratch and patch it.
2103 __ PatchRelocatedValue(inline_site, scratch, v0);
2104
2105 if (!ReturnTrueFalseObject()) {
2106 __ li(v0, Operand(Smi::FromInt(1)));
2107 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002108 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002109
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002110 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
2111
2112 Label object_not_null, object_not_null_or_smi;
2113 __ bind(&not_js_object);
2114 // Before null, smi and string value checks, check that the rhs is a function
2115 // as for a non-function rhs an exception needs to be thrown.
2116 __ JumpIfSmi(function, &slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002117 __ GetObjectType(function, scratch2, scratch);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002118 __ Branch(&slow, ne, scratch, Operand(JS_FUNCTION_TYPE));
2119
2120 // Null is not instance of anything.
danno@chromium.org88aa0582012-03-23 15:11:57 +00002121 __ Branch(&object_not_null,
2122 ne,
2123 scratch,
2124 Operand(masm->isolate()->factory()->null_value()));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002125 __ li(v0, Operand(Smi::FromInt(1)));
2126 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
2127
2128 __ bind(&object_not_null);
2129 // Smi values are not instances of anything.
2130 __ JumpIfNotSmi(object, &object_not_null_or_smi);
2131 __ li(v0, Operand(Smi::FromInt(1)));
2132 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
2133
2134 __ bind(&object_not_null_or_smi);
2135 // String values are not instances of anything.
2136 __ IsObjectJSStringType(object, scratch, &slow);
2137 __ li(v0, Operand(Smi::FromInt(1)));
2138 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
2139
2140 // Slow-case. Tail call builtin.
2141 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002142 if (!ReturnTrueFalseObject()) {
2143 if (HasArgsInRegisters()) {
2144 __ Push(a0, a1);
2145 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002146 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002147 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002148 {
2149 FrameScope scope(masm, StackFrame::INTERNAL);
2150 __ Push(a0, a1);
2151 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
2152 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002153 __ mov(a0, v0);
2154 __ LoadRoot(v0, Heap::kTrueValueRootIndex);
2155 __ DropAndRet(HasArgsInRegisters() ? 0 : 2, eq, a0, Operand(zero_reg));
2156 __ LoadRoot(v0, Heap::kFalseValueRootIndex);
2157 __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
2158 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00002159}
2160
2161
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002162void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
2163 Label miss;
2164 Register receiver;
2165 if (kind() == Code::KEYED_LOAD_IC) {
2166 // ----------- S t a t e -------------
2167 // -- ra : return address
2168 // -- a0 : key
2169 // -- a1 : receiver
2170 // -----------------------------------
2171 __ Branch(&miss, ne, a0,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002172 Operand(masm->isolate()->factory()->prototype_string()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002173 receiver = a1;
2174 } else {
2175 ASSERT(kind() == Code::LOAD_IC);
2176 // ----------- S t a t e -------------
2177 // -- a2 : name
2178 // -- ra : return address
2179 // -- a0 : receiver
2180 // -- sp[0] : receiver
2181 // -----------------------------------
2182 receiver = a0;
2183 }
2184
2185 StubCompiler::GenerateLoadFunctionPrototype(masm, receiver, a3, t0, &miss);
2186 __ bind(&miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +00002187 StubCompiler::TailCallBuiltin(
2188 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002189}
2190
2191
danno@chromium.org40cb8782011-05-25 07:58:50 +00002192Register InstanceofStub::left() { return a0; }
2193
2194
2195Register InstanceofStub::right() { return a1; }
2196
2197
lrn@chromium.org7516f052011-03-30 08:52:27 +00002198void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002199 // The displacement is the offset of the last parameter (if any)
2200 // relative to the frame pointer.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002201 const int kDisplacement =
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002202 StandardFrameConstants::kCallerSPOffset - kPointerSize;
2203
2204 // Check that the key is a smiGenerateReadElement.
2205 Label slow;
2206 __ JumpIfNotSmi(a1, &slow);
2207
2208 // Check if the calling frame is an arguments adaptor frame.
2209 Label adaptor;
2210 __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2211 __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
2212 __ Branch(&adaptor,
2213 eq,
2214 a3,
2215 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2216
2217 // Check index (a1) against formal parameters count limit passed in
2218 // through register a0. Use unsigned comparison to get negative
2219 // check for free.
2220 __ Branch(&slow, hs, a1, Operand(a0));
2221
2222 // Read the argument from the stack and return it.
2223 __ subu(a3, a0, a1);
2224 __ sll(t3, a3, kPointerSizeLog2 - kSmiTagSize);
2225 __ Addu(a3, fp, Operand(t3));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002226 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002227 __ lw(v0, MemOperand(a3, kDisplacement));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002228
2229 // Arguments adaptor case: Check index (a1) against actual arguments
2230 // limit found in the arguments adaptor frame. Use unsigned
2231 // comparison to get negative check for free.
2232 __ bind(&adaptor);
2233 __ lw(a0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
2234 __ Branch(&slow, Ugreater_equal, a1, Operand(a0));
2235
2236 // Read the argument from the adaptor frame and return it.
2237 __ subu(a3, a0, a1);
2238 __ sll(t3, a3, kPointerSizeLog2 - kSmiTagSize);
2239 __ Addu(a3, a2, Operand(t3));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002240 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002241 __ lw(v0, MemOperand(a3, kDisplacement));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002242
2243 // Slow-case: Handle non-smi or out-of-bounds access to arguments
2244 // by calling the runtime system.
2245 __ bind(&slow);
2246 __ push(a1);
2247 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002248}
2249
2250
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002251void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002252 // sp[0] : number of parameters
2253 // sp[4] : receiver displacement
2254 // sp[8] : function
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002255 // Check if the calling frame is an arguments adaptor frame.
2256 Label runtime;
2257 __ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2258 __ lw(a2, MemOperand(a3, StandardFrameConstants::kContextOffset));
danno@chromium.org88aa0582012-03-23 15:11:57 +00002259 __ Branch(&runtime,
2260 ne,
2261 a2,
2262 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002263
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002264 // Patch the arguments.length and the parameters pointer in the current frame.
2265 __ lw(a2, MemOperand(a3, ArgumentsAdaptorFrameConstants::kLengthOffset));
2266 __ sw(a2, MemOperand(sp, 0 * kPointerSize));
2267 __ sll(t3, a2, 1);
2268 __ Addu(a3, a3, Operand(t3));
2269 __ addiu(a3, a3, StandardFrameConstants::kCallerSPOffset);
2270 __ sw(a3, MemOperand(sp, 1 * kPointerSize));
2271
2272 __ bind(&runtime);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002273 __ TailCallRuntime(Runtime::kHiddenNewArgumentsFast, 3, 1);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002274}
2275
2276
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002277void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002278 // Stack layout:
2279 // sp[0] : number of parameters (tagged)
2280 // sp[4] : address of receiver argument
2281 // sp[8] : function
2282 // Registers used over whole function:
2283 // t2 : allocated object (tagged)
2284 // t5 : mapped parameter count (tagged)
2285
2286 __ lw(a1, MemOperand(sp, 0 * kPointerSize));
2287 // a1 = parameter count (tagged)
2288
2289 // Check if the calling frame is an arguments adaptor frame.
2290 Label runtime;
2291 Label adaptor_frame, try_allocate;
2292 __ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2293 __ lw(a2, MemOperand(a3, StandardFrameConstants::kContextOffset));
danno@chromium.org88aa0582012-03-23 15:11:57 +00002294 __ Branch(&adaptor_frame,
2295 eq,
2296 a2,
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002297 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2298
2299 // No adaptor, parameter count = argument count.
2300 __ mov(a2, a1);
2301 __ b(&try_allocate);
2302 __ nop(); // Branch delay slot nop.
2303
2304 // We have an adaptor frame. Patch the parameters pointer.
2305 __ bind(&adaptor_frame);
2306 __ lw(a2, MemOperand(a3, ArgumentsAdaptorFrameConstants::kLengthOffset));
2307 __ sll(t6, a2, 1);
2308 __ Addu(a3, a3, Operand(t6));
2309 __ Addu(a3, a3, Operand(StandardFrameConstants::kCallerSPOffset));
2310 __ sw(a3, MemOperand(sp, 1 * kPointerSize));
2311
2312 // a1 = parameter count (tagged)
2313 // a2 = argument count (tagged)
2314 // Compute the mapped parameter count = min(a1, a2) in a1.
2315 Label skip_min;
2316 __ Branch(&skip_min, lt, a1, Operand(a2));
2317 __ mov(a1, a2);
2318 __ bind(&skip_min);
2319
2320 __ bind(&try_allocate);
2321
2322 // Compute the sizes of backing store, parameter map, and arguments object.
2323 // 1. Parameter map, has 2 extra words containing context and backing store.
2324 const int kParameterMapHeaderSize =
2325 FixedArray::kHeaderSize + 2 * kPointerSize;
2326 // If there are no mapped parameters, we do not need the parameter_map.
2327 Label param_map_size;
2328 ASSERT_EQ(0, Smi::FromInt(0));
2329 __ Branch(USE_DELAY_SLOT, &param_map_size, eq, a1, Operand(zero_reg));
2330 __ mov(t5, zero_reg); // In delay slot: param map size = 0 when a1 == 0.
2331 __ sll(t5, a1, 1);
2332 __ addiu(t5, t5, kParameterMapHeaderSize);
2333 __ bind(&param_map_size);
2334
2335 // 2. Backing store.
2336 __ sll(t6, a2, 1);
2337 __ Addu(t5, t5, Operand(t6));
2338 __ Addu(t5, t5, Operand(FixedArray::kHeaderSize));
2339
2340 // 3. Arguments object.
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002341 __ Addu(t5, t5, Operand(Heap::kSloppyArgumentsObjectSize));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002342
2343 // Do the allocation of all three objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002344 __ Allocate(t5, v0, a3, t0, &runtime, TAG_OBJECT);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002345
2346 // v0 = address of new object(s) (tagged)
2347 // a2 = argument count (tagged)
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002348 // Get the arguments boilerplate from the current native context into t0.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002349 const int kNormalOffset =
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002350 Context::SlotOffset(Context::SLOPPY_ARGUMENTS_BOILERPLATE_INDEX);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002351 const int kAliasedOffset =
2352 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX);
2353
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002354 __ lw(t0, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2355 __ lw(t0, FieldMemOperand(t0, GlobalObject::kNativeContextOffset));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002356 Label skip2_ne, skip2_eq;
2357 __ Branch(&skip2_ne, ne, a1, Operand(zero_reg));
2358 __ lw(t0, MemOperand(t0, kNormalOffset));
2359 __ bind(&skip2_ne);
2360
2361 __ Branch(&skip2_eq, eq, a1, Operand(zero_reg));
2362 __ lw(t0, MemOperand(t0, kAliasedOffset));
2363 __ bind(&skip2_eq);
2364
2365 // v0 = address of new object (tagged)
2366 // a1 = mapped parameter count (tagged)
2367 // a2 = argument count (tagged)
2368 // t0 = address of boilerplate object (tagged)
2369 // Copy the JS object part.
2370 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
2371 __ lw(a3, FieldMemOperand(t0, i));
2372 __ sw(a3, FieldMemOperand(v0, i));
2373 }
2374
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002375 // Set up the callee in-object property.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002376 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
2377 __ lw(a3, MemOperand(sp, 2 * kPointerSize));
2378 const int kCalleeOffset = JSObject::kHeaderSize +
2379 Heap::kArgumentsCalleeIndex * kPointerSize;
2380 __ sw(a3, FieldMemOperand(v0, kCalleeOffset));
2381
2382 // Use the length (smi tagged) and set that as an in-object property too.
2383 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
2384 const int kLengthOffset = JSObject::kHeaderSize +
2385 Heap::kArgumentsLengthIndex * kPointerSize;
2386 __ sw(a2, FieldMemOperand(v0, kLengthOffset));
2387
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002388 // Set up the elements pointer in the allocated arguments object.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002389 // If we allocated a parameter map, t0 will point there, otherwise
2390 // it will point to the backing store.
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002391 __ Addu(t0, v0, Operand(Heap::kSloppyArgumentsObjectSize));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002392 __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
2393
2394 // v0 = address of new object (tagged)
2395 // a1 = mapped parameter count (tagged)
2396 // a2 = argument count (tagged)
2397 // t0 = address of parameter map or backing store (tagged)
2398 // Initialize parameter map. If there are no mapped arguments, we're done.
2399 Label skip_parameter_map;
2400 Label skip3;
2401 __ Branch(&skip3, ne, a1, Operand(Smi::FromInt(0)));
2402 // Move backing store address to a3, because it is
2403 // expected there when filling in the unmapped arguments.
2404 __ mov(a3, t0);
2405 __ bind(&skip3);
2406
2407 __ Branch(&skip_parameter_map, eq, a1, Operand(Smi::FromInt(0)));
2408
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002409 __ LoadRoot(t2, Heap::kSloppyArgumentsElementsMapRootIndex);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002410 __ sw(t2, FieldMemOperand(t0, FixedArray::kMapOffset));
2411 __ Addu(t2, a1, Operand(Smi::FromInt(2)));
2412 __ sw(t2, FieldMemOperand(t0, FixedArray::kLengthOffset));
2413 __ sw(cp, FieldMemOperand(t0, FixedArray::kHeaderSize + 0 * kPointerSize));
2414 __ sll(t6, a1, 1);
2415 __ Addu(t2, t0, Operand(t6));
2416 __ Addu(t2, t2, Operand(kParameterMapHeaderSize));
2417 __ sw(t2, FieldMemOperand(t0, FixedArray::kHeaderSize + 1 * kPointerSize));
2418
2419 // Copy the parameter slots and the holes in the arguments.
2420 // We need to fill in mapped_parameter_count slots. They index the context,
2421 // where parameters are stored in reverse order, at
2422 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
2423 // The mapped parameter thus need to get indices
2424 // MIN_CONTEXT_SLOTS+parameter_count-1 ..
2425 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
2426 // We loop from right to left.
2427 Label parameters_loop, parameters_test;
2428 __ mov(t2, a1);
2429 __ lw(t5, MemOperand(sp, 0 * kPointerSize));
2430 __ Addu(t5, t5, Operand(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
2431 __ Subu(t5, t5, Operand(a1));
2432 __ LoadRoot(t3, Heap::kTheHoleValueRootIndex);
2433 __ sll(t6, t2, 1);
2434 __ Addu(a3, t0, Operand(t6));
2435 __ Addu(a3, a3, Operand(kParameterMapHeaderSize));
2436
2437 // t2 = loop variable (tagged)
2438 // a1 = mapping index (tagged)
2439 // a3 = address of backing store (tagged)
2440 // t0 = address of parameter map (tagged)
2441 // t1 = temporary scratch (a.o., for address calculation)
2442 // t3 = the hole value
2443 __ jmp(&parameters_test);
2444
2445 __ bind(&parameters_loop);
2446 __ Subu(t2, t2, Operand(Smi::FromInt(1)));
2447 __ sll(t1, t2, 1);
2448 __ Addu(t1, t1, Operand(kParameterMapHeaderSize - kHeapObjectTag));
2449 __ Addu(t6, t0, t1);
2450 __ sw(t5, MemOperand(t6));
2451 __ Subu(t1, t1, Operand(kParameterMapHeaderSize - FixedArray::kHeaderSize));
2452 __ Addu(t6, a3, t1);
2453 __ sw(t3, MemOperand(t6));
2454 __ Addu(t5, t5, Operand(Smi::FromInt(1)));
2455 __ bind(&parameters_test);
2456 __ Branch(&parameters_loop, ne, t2, Operand(Smi::FromInt(0)));
2457
2458 __ bind(&skip_parameter_map);
2459 // a2 = argument count (tagged)
2460 // a3 = address of backing store (tagged)
2461 // t1 = scratch
2462 // Copy arguments header and remaining slots (if there are any).
2463 __ LoadRoot(t1, Heap::kFixedArrayMapRootIndex);
2464 __ sw(t1, FieldMemOperand(a3, FixedArray::kMapOffset));
2465 __ sw(a2, FieldMemOperand(a3, FixedArray::kLengthOffset));
2466
2467 Label arguments_loop, arguments_test;
2468 __ mov(t5, a1);
2469 __ lw(t0, MemOperand(sp, 1 * kPointerSize));
2470 __ sll(t6, t5, 1);
2471 __ Subu(t0, t0, Operand(t6));
2472 __ jmp(&arguments_test);
2473
2474 __ bind(&arguments_loop);
2475 __ Subu(t0, t0, Operand(kPointerSize));
2476 __ lw(t2, MemOperand(t0, 0));
2477 __ sll(t6, t5, 1);
2478 __ Addu(t1, a3, Operand(t6));
2479 __ sw(t2, FieldMemOperand(t1, FixedArray::kHeaderSize));
2480 __ Addu(t5, t5, Operand(Smi::FromInt(1)));
2481
2482 __ bind(&arguments_test);
2483 __ Branch(&arguments_loop, lt, t5, Operand(a2));
2484
2485 // Return and remove the on-stack parameters.
ulan@chromium.org6ff65142012-03-21 09:52:17 +00002486 __ DropAndRet(3);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002487
2488 // Do the runtime call to allocate the arguments object.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002489 // a2 = argument count (tagged)
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002490 __ bind(&runtime);
2491 __ sw(a2, MemOperand(sp, 0 * kPointerSize)); // Patch argument count.
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002492 __ TailCallRuntime(Runtime::kHiddenNewArgumentsFast, 3, 1);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002493}
2494
2495
2496void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
2497 // sp[0] : number of parameters
2498 // sp[4] : receiver displacement
2499 // sp[8] : function
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002500 // Check if the calling frame is an arguments adaptor frame.
2501 Label adaptor_frame, try_allocate, runtime;
2502 __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2503 __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
2504 __ Branch(&adaptor_frame,
2505 eq,
2506 a3,
2507 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2508
2509 // Get the length from the frame.
2510 __ lw(a1, MemOperand(sp, 0));
2511 __ Branch(&try_allocate);
2512
2513 // Patch the arguments.length and the parameters pointer.
2514 __ bind(&adaptor_frame);
2515 __ lw(a1, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
2516 __ sw(a1, MemOperand(sp, 0));
2517 __ sll(at, a1, kPointerSizeLog2 - kSmiTagSize);
2518 __ Addu(a3, a2, Operand(at));
2519
2520 __ Addu(a3, a3, Operand(StandardFrameConstants::kCallerSPOffset));
2521 __ sw(a3, MemOperand(sp, 1 * kPointerSize));
2522
2523 // Try the new space allocation. Start out with computing the size
2524 // of the arguments object and the elements array in words.
2525 Label add_arguments_object;
2526 __ bind(&try_allocate);
2527 __ Branch(&add_arguments_object, eq, a1, Operand(zero_reg));
2528 __ srl(a1, a1, kSmiTagSize);
2529
2530 __ Addu(a1, a1, Operand(FixedArray::kHeaderSize / kPointerSize));
2531 __ bind(&add_arguments_object);
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002532 __ Addu(a1, a1, Operand(Heap::kStrictArgumentsObjectSize / kPointerSize));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002533
2534 // Do the allocation of both objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002535 __ Allocate(a1, v0, a2, a3, &runtime,
2536 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002537
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002538 // Get the arguments boilerplate from the current native context.
2539 __ lw(t0, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2540 __ lw(t0, FieldMemOperand(t0, GlobalObject::kNativeContextOffset));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002541 __ lw(t0, MemOperand(t0, Context::SlotOffset(
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002542 Context::STRICT_ARGUMENTS_BOILERPLATE_INDEX)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002543
2544 // Copy the JS object part.
2545 __ CopyFields(v0, t0, a3.bit(), JSObject::kHeaderSize / kPointerSize);
2546
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002547 // Get the length (smi tagged) and set that as an in-object property too.
2548 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
2549 __ lw(a1, MemOperand(sp, 0 * kPointerSize));
2550 __ sw(a1, FieldMemOperand(v0, JSObject::kHeaderSize +
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002551 Heap::kArgumentsLengthIndex * kPointerSize));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002552
2553 Label done;
2554 __ Branch(&done, eq, a1, Operand(zero_reg));
2555
2556 // Get the parameters pointer from the stack.
2557 __ lw(a2, MemOperand(sp, 1 * kPointerSize));
2558
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002559 // Set up the elements pointer in the allocated arguments object and
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002560 // initialize the header in the elements fixed array.
dslomov@chromium.org486536d2014-03-12 13:09:18 +00002561 __ Addu(t0, v0, Operand(Heap::kStrictArgumentsObjectSize));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002562 __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
2563 __ LoadRoot(a3, Heap::kFixedArrayMapRootIndex);
2564 __ sw(a3, FieldMemOperand(t0, FixedArray::kMapOffset));
2565 __ sw(a1, FieldMemOperand(t0, FixedArray::kLengthOffset));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002566 // Untag the length for the loop.
2567 __ srl(a1, a1, kSmiTagSize);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002568
2569 // Copy the fixed array slots.
2570 Label loop;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002571 // Set up t0 to point to the first array slot.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002572 __ Addu(t0, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
2573 __ bind(&loop);
2574 // Pre-decrement a2 with kPointerSize on each iteration.
2575 // Pre-decrement in order to skip receiver.
2576 __ Addu(a2, a2, Operand(-kPointerSize));
2577 __ lw(a3, MemOperand(a2));
2578 // Post-increment t0 with kPointerSize on each iteration.
2579 __ sw(a3, MemOperand(t0));
2580 __ Addu(t0, t0, Operand(kPointerSize));
2581 __ Subu(a1, a1, Operand(1));
2582 __ Branch(&loop, ne, a1, Operand(zero_reg));
2583
2584 // Return and remove the on-stack parameters.
2585 __ bind(&done);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00002586 __ DropAndRet(3);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002587
2588 // Do the runtime call to allocate the arguments object.
2589 __ bind(&runtime);
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00002590 __ TailCallRuntime(Runtime::kHiddenNewStrictArgumentsFast, 3, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002591}
2592
2593
2594void RegExpExecStub::Generate(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002595 // Just jump directly to runtime if native RegExp is not selected at compile
2596 // time or if regexp entry in generated code is turned off runtime switch or
2597 // at compilation.
2598#ifdef V8_INTERPRETED_REGEXP
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +00002599 __ TailCallRuntime(Runtime::kHiddenRegExpExec, 4, 1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002600#else // V8_INTERPRETED_REGEXP
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002601
2602 // Stack frame on entry.
2603 // sp[0]: last_match_info (expected JSArray)
2604 // sp[4]: previous index
2605 // sp[8]: subject string
2606 // sp[12]: JSRegExp object
2607
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002608 const int kLastMatchInfoOffset = 0 * kPointerSize;
2609 const int kPreviousIndexOffset = 1 * kPointerSize;
2610 const int kSubjectOffset = 2 * kPointerSize;
2611 const int kJSRegExpOffset = 3 * kPointerSize;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002612
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002613 Isolate* isolate = masm->isolate();
2614
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002615 Label runtime;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002616 // Allocation of registers for this function. These are in callee save
2617 // registers and will be preserved by the call to the native RegExp code, as
2618 // this code is called using the normal C calling convention. When calling
2619 // directly from generated code the native RegExp code will not do a GC and
2620 // therefore the content of these registers are safe to use after the call.
2621 // MIPS - using s0..s2, since we are not using CEntry Stub.
2622 Register subject = s0;
2623 Register regexp_data = s1;
2624 Register last_match_info_elements = s2;
2625
2626 // Ensure that a RegExp stack is allocated.
2627 ExternalReference address_of_regexp_stack_memory_address =
2628 ExternalReference::address_of_regexp_stack_memory_address(
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002629 isolate);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002630 ExternalReference address_of_regexp_stack_memory_size =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002631 ExternalReference::address_of_regexp_stack_memory_size(isolate);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002632 __ li(a0, Operand(address_of_regexp_stack_memory_size));
2633 __ lw(a0, MemOperand(a0, 0));
2634 __ Branch(&runtime, eq, a0, Operand(zero_reg));
2635
2636 // Check that the first argument is a JSRegExp object.
2637 __ lw(a0, MemOperand(sp, kJSRegExpOffset));
2638 STATIC_ASSERT(kSmiTag == 0);
2639 __ JumpIfSmi(a0, &runtime);
2640 __ GetObjectType(a0, a1, a1);
2641 __ Branch(&runtime, ne, a1, Operand(JS_REGEXP_TYPE));
2642
2643 // Check that the RegExp has been compiled (data contains a fixed array).
2644 __ lw(regexp_data, FieldMemOperand(a0, JSRegExp::kDataOffset));
2645 if (FLAG_debug_code) {
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00002646 __ SmiTst(regexp_data, t0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002647 __ Check(nz,
danno@chromium.org59400602013-08-13 17:09:37 +00002648 kUnexpectedTypeForRegExpDataFixedArrayExpected,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002649 t0,
2650 Operand(zero_reg));
2651 __ GetObjectType(regexp_data, a0, a0);
2652 __ Check(eq,
danno@chromium.org59400602013-08-13 17:09:37 +00002653 kUnexpectedTypeForRegExpDataFixedArrayExpected,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002654 a0,
2655 Operand(FIXED_ARRAY_TYPE));
2656 }
2657
2658 // regexp_data: RegExp data (FixedArray)
2659 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
2660 __ lw(a0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset));
2661 __ Branch(&runtime, ne, a0, Operand(Smi::FromInt(JSRegExp::IRREGEXP)));
2662
2663 // regexp_data: RegExp data (FixedArray)
2664 // Check that the number of captures fit in the static offsets vector buffer.
2665 __ lw(a2,
2666 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002667 // Check (number_of_captures + 1) * 2 <= offsets vector size
2668 // Or number_of_captures * 2 <= offsets vector size - 2
2669 // Multiplying by 2 comes for free since a2 is smi-tagged.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002670 STATIC_ASSERT(kSmiTag == 0);
2671 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002672 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002673 __ Branch(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002674 &runtime, hi, a2, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize - 2));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002675
2676 // Reset offset for possibly sliced string.
2677 __ mov(t0, zero_reg);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002678 __ lw(subject, MemOperand(sp, kSubjectOffset));
2679 __ JumpIfSmi(subject, &runtime);
2680 __ mov(a3, subject); // Make a copy of the original subject string.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002681 __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
2682 __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002683 // subject: subject string
2684 // a3: subject string
2685 // a0: subject string instance type
2686 // regexp_data: RegExp data (FixedArray)
2687 // Handle subject string according to its encoding and representation:
2688 // (1) Sequential string? If yes, go to (5).
2689 // (2) Anything but sequential or cons? If yes, go to (6).
2690 // (3) Cons string. If the string is flat, replace subject with first string.
2691 // Otherwise bailout.
2692 // (4) Is subject external? If yes, go to (7).
2693 // (5) Sequential string. Load regexp code according to encoding.
2694 // (E) Carry on.
2695 /// [...]
2696
2697 // Deferred code at the end of the stub:
2698 // (6) Not a long external string? If yes, go to (8).
2699 // (7) External string. Make it, offset-wise, look like a sequential string.
2700 // Go to (5).
2701 // (8) Short external string or not a string? If yes, bail out to runtime.
2702 // (9) Sliced string. Replace subject with parent. Go to (4).
2703
2704 Label seq_string /* 5 */, external_string /* 7 */,
2705 check_underlying /* 4 */, not_seq_nor_cons /* 6 */,
2706 not_long_external /* 8 */;
2707
2708 // (1) Sequential string? If yes, go to (5).
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002709 __ And(a1,
2710 a0,
2711 Operand(kIsNotStringMask |
2712 kStringRepresentationMask |
2713 kShortExternalStringMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002714 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002715 __ Branch(&seq_string, eq, a1, Operand(zero_reg)); // Go to (5).
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002716
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002717 // (2) Anything but sequential or cons? If yes, go to (6).
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002718 STATIC_ASSERT(kConsStringTag < kExternalStringTag);
2719 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00002720 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002721 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002722 // Go to (6).
2723 __ Branch(&not_seq_nor_cons, ge, a1, Operand(kExternalStringTag));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002724
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002725 // (3) Cons string. Check that it's flat.
2726 // Replace subject with first string and reload instance type.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002727 __ lw(a0, FieldMemOperand(subject, ConsString::kSecondOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002728 __ LoadRoot(a1, Heap::kempty_stringRootIndex);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002729 __ Branch(&runtime, ne, a0, Operand(a1));
2730 __ lw(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002731
2732 // (4) Is subject external? If yes, go to (7).
2733 __ bind(&check_underlying);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002734 __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
2735 __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002736 STATIC_ASSERT(kSeqStringTag == 0);
2737 __ And(at, a0, Operand(kStringRepresentationMask));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002738 // The underlying external string is never a short external string.
2739 STATIC_CHECK(ExternalString::kMaxShortLength < ConsString::kMinLength);
2740 STATIC_CHECK(ExternalString::kMaxShortLength < SlicedString::kMinLength);
2741 __ Branch(&external_string, ne, at, Operand(zero_reg)); // Go to (7).
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002742
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002743 // (5) Sequential string. Load regexp code according to encoding.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002744 __ bind(&seq_string);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002745 // subject: sequential subject string (or look-alike, external string)
2746 // a3: original subject string
2747 // Load previous index and check range before a3 is overwritten. We have to
2748 // use a3 instead of subject here because subject might have been only made
2749 // to look like a sequential string when it actually is an external string.
2750 __ lw(a1, MemOperand(sp, kPreviousIndexOffset));
2751 __ JumpIfNotSmi(a1, &runtime);
2752 __ lw(a3, FieldMemOperand(a3, String::kLengthOffset));
2753 __ Branch(&runtime, ls, a3, Operand(a1));
2754 __ sra(a1, a1, kSmiTagSize); // Untag the Smi.
2755
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002756 STATIC_ASSERT(kStringEncodingMask == 4);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002757 STATIC_ASSERT(kOneByteStringTag == 4);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002758 STATIC_ASSERT(kTwoByteStringTag == 0);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002759 __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ASCII.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002760 __ lw(t9, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002761 __ sra(a3, a0, 2); // a3 is 1 for ASCII, 0 for UC16 (used below).
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002762 __ lw(t1, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00002763 __ Movz(t9, t1, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002764
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002765 // (E) Carry on. String handling is done.
2766 // t9: irregexp code
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002767 // Check that the irregexp code has been generated for the actual string
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002768 // encoding. If it has, the field contains a code object otherwise it contains
2769 // a smi (code flushing support).
2770 __ JumpIfSmi(t9, &runtime);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002771
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002772 // a1: previous index
2773 // a3: encoding of subject string (1 if ASCII, 0 if two_byte);
2774 // t9: code
2775 // subject: Subject string
2776 // regexp_data: RegExp data (FixedArray)
2777 // All checks done. Now push arguments for native regexp code.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002778 __ IncrementCounter(isolate->counters()->regexp_entry_native(),
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002779 1, a0, a2);
2780
2781 // Isolates: note we add an additional parameter here (isolate pointer).
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00002782 const int kRegExpExecuteArguments = 9;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002783 const int kParameterRegisters = 4;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002784 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters);
2785
2786 // Stack pointer now points to cell where return address is to be written.
2787 // Arguments are before that on the stack or in registers, meaning we
2788 // treat the return address as argument 5. Thus every argument after that
2789 // needs to be shifted back by 1. Since DirectCEntryStub will handle
2790 // allocating space for the c argument slots, we don't need to calculate
2791 // that into the argument positions on the stack. This is how the stack will
2792 // look (sp meaning the value of sp at this moment):
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00002793 // [sp + 5] - Argument 9
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002794 // [sp + 4] - Argument 8
2795 // [sp + 3] - Argument 7
2796 // [sp + 2] - Argument 6
2797 // [sp + 1] - Argument 5
2798 // [sp + 0] - saved ra
2799
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00002800 // Argument 9: Pass current isolate address.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002801 // CFunctionArgumentOperand handles MIPS stack argument slots.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002802 __ li(a0, Operand(ExternalReference::isolate_address(isolate)));
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00002803 __ sw(a0, MemOperand(sp, 5 * kPointerSize));
2804
2805 // Argument 8: Indicate that this is a direct call from JavaScript.
2806 __ li(a0, Operand(1));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002807 __ sw(a0, MemOperand(sp, 4 * kPointerSize));
2808
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00002809 // Argument 7: Start (high end) of backtracking stack memory area.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002810 __ li(a0, Operand(address_of_regexp_stack_memory_address));
2811 __ lw(a0, MemOperand(a0, 0));
2812 __ li(a2, Operand(address_of_regexp_stack_memory_size));
2813 __ lw(a2, MemOperand(a2, 0));
2814 __ addu(a0, a0, a2);
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00002815 __ sw(a0, MemOperand(sp, 3 * kPointerSize));
2816
2817 // Argument 6: Set the number of capture registers to zero to force global
2818 // regexps to behave as non-global. This does not affect non-global regexps.
2819 __ mov(a0, zero_reg);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002820 __ sw(a0, MemOperand(sp, 2 * kPointerSize));
2821
2822 // Argument 5: static offsets vector buffer.
2823 __ li(a0, Operand(
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002824 ExternalReference::address_of_static_offsets_vector(isolate)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002825 __ sw(a0, MemOperand(sp, 1 * kPointerSize));
2826
2827 // For arguments 4 and 3 get string length, calculate start of string data
2828 // and calculate the shift of the index (0 for ASCII and 1 for two byte).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002829 __ Addu(t2, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002830 __ Xor(a3, a3, Operand(1)); // 1 for 2-byte str, 0 for 1-byte.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002831 // Load the length from the original subject string from the previous stack
2832 // frame. Therefore we have to use fp, which points exactly to two pointer
2833 // sizes below the previous sp. (Because creating a new stack frame pushes
2834 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.)
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002835 __ lw(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002836 // If slice offset is not 0, load the length from the original sliced string.
2837 // Argument 4, a3: End of string data
2838 // Argument 3, a2: Start of string data
2839 // Prepare start and end index of the input.
2840 __ sllv(t1, t0, a3);
2841 __ addu(t0, t2, t1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002842 __ sllv(t1, a1, a3);
2843 __ addu(a2, t0, t1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002844
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002845 __ lw(t2, FieldMemOperand(subject, String::kLengthOffset));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002846 __ sra(t2, t2, kSmiTagSize);
2847 __ sllv(t1, t2, a3);
2848 __ addu(a3, t0, t1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002849 // Argument 2 (a1): Previous index.
2850 // Already there
2851
2852 // Argument 1 (a0): Subject string.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002853 __ mov(a0, subject);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002854
2855 // Locate the code entry and call it.
2856 __ Addu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag));
2857 DirectCEntryStub stub;
2858 stub.GenerateCall(masm, t9);
2859
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002860 __ LeaveExitFrame(false, no_reg, true);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002861
2862 // v0: result
2863 // subject: subject string (callee saved)
2864 // regexp_data: RegExp data (callee saved)
2865 // last_match_info_elements: Last match info elements (callee saved)
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002866 // Check the result.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002867 Label success;
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00002868 __ Branch(&success, eq, v0, Operand(1));
2869 // We expect exactly one result since we force the called regexp to behave
2870 // as non-global.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002871 Label failure;
danno@chromium.org88aa0582012-03-23 15:11:57 +00002872 __ Branch(&failure, eq, v0, Operand(NativeRegExpMacroAssembler::FAILURE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002873 // If not exception it can only be retry. Handle that in the runtime system.
danno@chromium.org88aa0582012-03-23 15:11:57 +00002874 __ Branch(&runtime, ne, v0, Operand(NativeRegExpMacroAssembler::EXCEPTION));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002875 // Result must now be exception. If there is no pending exception already a
2876 // stack overflow (on the backtrack stack) was detected in RegExp code but
2877 // haven't created the exception yet. Handle that in the runtime system.
2878 // TODO(592): Rerunning the RegExp to get the stack overflow exception.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002879 __ li(a1, Operand(isolate->factory()->the_hole_value()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002880 __ li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002881 isolate)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002882 __ lw(v0, MemOperand(a2, 0));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002883 __ Branch(&runtime, eq, v0, Operand(a1));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002884
2885 __ sw(a1, MemOperand(a2, 0)); // Clear pending exception.
2886
2887 // Check if the exception is a termination. If so, throw as uncatchable.
2888 __ LoadRoot(a0, Heap::kTerminationExceptionRootIndex);
2889 Label termination_exception;
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002890 __ Branch(&termination_exception, eq, v0, Operand(a0));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002891
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002892 __ Throw(v0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002893
2894 __ bind(&termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002895 __ ThrowUncatchable(v0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002896
2897 __ bind(&failure);
2898 // For failure and exception return null.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002899 __ li(v0, Operand(isolate->factory()->null_value()));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00002900 __ DropAndRet(4);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002901
2902 // Process the result from the native regexp code.
2903 __ bind(&success);
2904 __ lw(a1,
2905 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
2906 // Calculate number of capture registers (number_of_captures + 1) * 2.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002907 // Multiplying by 2 comes for free since r1 is smi-tagged.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002908 STATIC_ASSERT(kSmiTag == 0);
2909 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
2910 __ Addu(a1, a1, Operand(2)); // a1 was a smi.
2911
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002912 __ lw(a0, MemOperand(sp, kLastMatchInfoOffset));
2913 __ JumpIfSmi(a0, &runtime);
2914 __ GetObjectType(a0, a2, a2);
2915 __ Branch(&runtime, ne, a2, Operand(JS_ARRAY_TYPE));
2916 // Check that the JSArray is in fast case.
2917 __ lw(last_match_info_elements,
2918 FieldMemOperand(a0, JSArray::kElementsOffset));
2919 __ lw(a0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
2920 __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
2921 __ Branch(&runtime, ne, a0, Operand(at));
2922 // Check that the last match info has space for the capture registers and the
2923 // additional information.
2924 __ lw(a0,
2925 FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset));
2926 __ Addu(a2, a1, Operand(RegExpImpl::kLastMatchOverhead));
2927 __ sra(at, a0, kSmiTagSize);
2928 __ Branch(&runtime, gt, a2, Operand(at));
2929
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002930 // a1: number of capture registers
2931 // subject: subject string
2932 // Store the capture count.
2933 __ sll(a2, a1, kSmiTagSize + kSmiShiftSize); // To smi.
2934 __ sw(a2, FieldMemOperand(last_match_info_elements,
2935 RegExpImpl::kLastCaptureCountOffset));
2936 // Store last subject and last input.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002937 __ sw(subject,
2938 FieldMemOperand(last_match_info_elements,
2939 RegExpImpl::kLastSubjectOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002940 __ mov(a2, subject);
2941 __ RecordWriteField(last_match_info_elements,
2942 RegExpImpl::kLastSubjectOffset,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002943 subject,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002944 t3,
2945 kRAHasNotBeenSaved,
2946 kDontSaveFPRegs);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002947 __ mov(subject, a2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002948 __ sw(subject,
2949 FieldMemOperand(last_match_info_elements,
2950 RegExpImpl::kLastInputOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002951 __ RecordWriteField(last_match_info_elements,
2952 RegExpImpl::kLastInputOffset,
2953 subject,
2954 t3,
2955 kRAHasNotBeenSaved,
2956 kDontSaveFPRegs);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002957
2958 // Get the static offsets vector filled by the native regexp code.
2959 ExternalReference address_of_static_offsets_vector =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002960 ExternalReference::address_of_static_offsets_vector(isolate);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002961 __ li(a2, Operand(address_of_static_offsets_vector));
2962
2963 // a1: number of capture registers
2964 // a2: offsets vector
2965 Label next_capture, done;
2966 // Capture register counter starts from number of capture registers and
2967 // counts down until wrapping after zero.
2968 __ Addu(a0,
2969 last_match_info_elements,
2970 Operand(RegExpImpl::kFirstCaptureOffset - kHeapObjectTag));
2971 __ bind(&next_capture);
2972 __ Subu(a1, a1, Operand(1));
2973 __ Branch(&done, lt, a1, Operand(zero_reg));
2974 // Read the value from the static offsets vector buffer.
2975 __ lw(a3, MemOperand(a2, 0));
2976 __ addiu(a2, a2, kPointerSize);
2977 // Store the smi value in the last match info.
2978 __ sll(a3, a3, kSmiTagSize); // Convert to Smi.
2979 __ sw(a3, MemOperand(a0, 0));
2980 __ Branch(&next_capture, USE_DELAY_SLOT);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00002981 __ addiu(a0, a0, kPointerSize); // In branch delay slot.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002982
2983 __ bind(&done);
2984
2985 // Return last match info.
2986 __ lw(v0, MemOperand(sp, kLastMatchInfoOffset));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00002987 __ DropAndRet(4);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002988
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002989 // Do the runtime call to execute the regexp.
2990 __ bind(&runtime);
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +00002991 __ TailCallRuntime(Runtime::kHiddenRegExpExec, 4, 1);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002992
2993 // Deferred code for string handling.
2994 // (6) Not a long external string? If yes, go to (8).
2995 __ bind(&not_seq_nor_cons);
2996 // Go to (8).
2997 __ Branch(&not_long_external, gt, a1, Operand(kExternalStringTag));
2998
2999 // (7) External string. Make it, offset-wise, look like a sequential string.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003000 __ bind(&external_string);
3001 __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
3002 __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
3003 if (FLAG_debug_code) {
3004 // Assert that we do not have a cons or slice (indirect strings) here.
3005 // Sequential strings have already been ruled out.
3006 __ And(at, a0, Operand(kIsIndirectStringMask));
3007 __ Assert(eq,
danno@chromium.org59400602013-08-13 17:09:37 +00003008 kExternalStringExpectedButNotFound,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003009 at,
3010 Operand(zero_reg));
3011 }
3012 __ lw(subject,
3013 FieldMemOperand(subject, ExternalString::kResourceDataOffset));
3014 // Move the pointer so that offset-wise, it looks like a sequential string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003015 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003016 __ Subu(subject,
3017 subject,
3018 SeqTwoByteString::kHeaderSize - kHeapObjectTag);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003019 __ jmp(&seq_string); // Go to (5).
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003020
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003021 // (8) Short external string or not a string? If yes, bail out to runtime.
3022 __ bind(&not_long_external);
3023 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
3024 __ And(at, a1, Operand(kIsNotStringMask | kShortExternalStringMask));
3025 __ Branch(&runtime, ne, at, Operand(zero_reg));
3026
3027 // (9) Sliced string. Replace subject with parent. Go to (4).
3028 // Load offset into t0 and replace subject string with parent.
3029 __ lw(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset));
3030 __ sra(t0, t0, kSmiTagSize);
3031 __ lw(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
3032 __ jmp(&check_underlying); // Go to (4).
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003033#endif // V8_INTERPRETED_REGEXP
lrn@chromium.org7516f052011-03-30 08:52:27 +00003034}
3035
3036
ulan@chromium.org750145a2013-03-07 15:14:13 +00003037static void GenerateRecordCallTarget(MacroAssembler* masm) {
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003038 // Cache the called function in a feedback vector slot. Cache states
ulan@chromium.org750145a2013-03-07 15:14:13 +00003039 // are uninitialized, monomorphic (indicated by a JSFunction), and
3040 // megamorphic.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003041 // a0 : number of arguments to the construct function
ulan@chromium.org750145a2013-03-07 15:14:13 +00003042 // a1 : the function to call
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003043 // a2 : Feedback vector
3044 // a3 : slot in feedback vector (Smi)
machenbach@chromium.org3a9c5d92014-02-21 08:10:27 +00003045 Label initialize, done, miss, megamorphic, not_array_function;
ulan@chromium.org750145a2013-03-07 15:14:13 +00003046
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003047 ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(masm->isolate()),
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00003048 masm->isolate()->heap()->megamorphic_symbol());
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003049 ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()),
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00003050 masm->isolate()->heap()->uninitialized_symbol());
ulan@chromium.org750145a2013-03-07 15:14:13 +00003051
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003052 // Load the cache state into t0.
3053 __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
3054 __ Addu(t0, a2, Operand(t0));
3055 __ lw(t0, FieldMemOperand(t0, FixedArray::kHeaderSize));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003056
3057 // A monomorphic cache hit or an already megamorphic state: invoke the
3058 // function without changing the state.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003059 __ Branch(&done, eq, t0, Operand(a1));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003060
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00003061 if (!FLAG_pretenuring_call_new) {
3062 // If we came here, we need to see if we are the array function.
3063 // If we didn't have a matching function, and we didn't find the megamorph
3064 // sentinel, then we have in the slot either some other function or an
3065 // AllocationSite. Do a map check on the object in a3.
3066 __ lw(t1, FieldMemOperand(t0, 0));
3067 __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
3068 __ Branch(&miss, ne, t1, Operand(at));
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00003069
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00003070 // Make sure the function is the Array() function
3071 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, t0);
3072 __ Branch(&megamorphic, ne, a1, Operand(t0));
3073 __ jmp(&done);
3074 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00003075
machenbach@chromium.org3a9c5d92014-02-21 08:10:27 +00003076 __ bind(&miss);
3077
3078 // A monomorphic miss (i.e, here the cache is not uninitialized) goes
3079 // megamorphic.
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00003080 __ LoadRoot(at, Heap::kUninitializedSymbolRootIndex);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003081 __ Branch(&initialize, eq, t0, Operand(at));
machenbach@chromium.org3a9c5d92014-02-21 08:10:27 +00003082 // MegamorphicSentinel is an immortal immovable object (undefined) so no
3083 // write-barrier is needed.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003084 __ bind(&megamorphic);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003085 __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
3086 __ Addu(t0, a2, Operand(t0));
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00003087 __ LoadRoot(at, Heap::kMegamorphicSymbolRootIndex);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003088 __ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize));
machenbach@chromium.org3a9c5d92014-02-21 08:10:27 +00003089 __ jmp(&done);
ulan@chromium.org750145a2013-03-07 15:14:13 +00003090
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00003091 // An uninitialized cache is patched with the function.
machenbach@chromium.org3a9c5d92014-02-21 08:10:27 +00003092 __ bind(&initialize);
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00003093 if (!FLAG_pretenuring_call_new) {
3094 // Make sure the function is the Array() function.
3095 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, t0);
3096 __ Branch(&not_array_function, ne, a1, Operand(t0));
machenbach@chromium.org3a9c5d92014-02-21 08:10:27 +00003097
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00003098 // The target function is the Array constructor,
3099 // Create an AllocationSite if we don't already have it, store it in the
3100 // slot.
3101 {
3102 FrameScope scope(masm, StackFrame::INTERNAL);
3103 const RegList kSavedRegs =
3104 1 << 4 | // a0
3105 1 << 5 | // a1
3106 1 << 6 | // a2
3107 1 << 7; // a3
danno@chromium.orgbee51992013-07-10 14:57:15 +00003108
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00003109 // Arguments register must be smi-tagged to call out.
3110 __ SmiTag(a0);
3111 __ MultiPush(kSavedRegs);
danno@chromium.orgbee51992013-07-10 14:57:15 +00003112
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00003113 CreateAllocationSiteStub create_stub;
3114 __ CallStub(&create_stub);
danno@chromium.orgbee51992013-07-10 14:57:15 +00003115
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00003116 __ MultiPop(kSavedRegs);
3117 __ SmiUntag(a0);
3118 }
3119 __ Branch(&done);
3120
3121 __ bind(&not_array_function);
danno@chromium.orgbee51992013-07-10 14:57:15 +00003122 }
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003123
3124 __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
3125 __ Addu(t0, a2, Operand(t0));
3126 __ Addu(t0, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3127 __ sw(a1, MemOperand(t0, 0));
3128
3129 __ Push(t0, a2, a1);
3130 __ RecordWrite(a2, t0, a1, kRAHasNotBeenSaved, kDontSaveFPRegs,
3131 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3132 __ Pop(t0, a2, a1);
ulan@chromium.org750145a2013-03-07 15:14:13 +00003133
3134 __ bind(&done);
3135}
3136
3137
lrn@chromium.org7516f052011-03-30 08:52:27 +00003138void CallFunctionStub::Generate(MacroAssembler* masm) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003139 // a1 : the function to call
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003140 // a2 : feedback vector
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00003141 // a3 : (only if a2 is not the megamorphic symbol) slot in feedback
3142 // vector (Smi)
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003143 Label slow, non_function, wrap, cont;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003144
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003145 if (NeedsChecks()) {
3146 // Check that the function is really a JavaScript function.
3147 // a1: pushed function (to be verified)
3148 __ JumpIfSmi(a1, &non_function);
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00003149
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003150 // Goto slow case if we do not have a function.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003151 __ GetObjectType(a1, t0, t0);
3152 __ Branch(&slow, ne, t0, Operand(JS_FUNCTION_TYPE));
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003153
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003154 if (RecordCallTarget()) {
3155 GenerateRecordCallTarget(masm);
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00003156 // Type information was updated. Because we may call Array, which
3157 // expects either undefined or an AllocationSite in a2 we need
3158 // to set a2 to undefined.
3159 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003160 }
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003161 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003162
3163 // Fast-case: Invoke the function now.
3164 // a1: pushed function
3165 ParameterCount actual(argc_);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003166
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003167 if (CallAsMethod()) {
3168 if (NeedsChecks()) {
3169 // Do not transform the receiver for strict mode functions and natives.
machenbach@chromium.org0e76f002014-02-03 07:23:16 +00003170 __ lw(a3, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3171 __ lw(t0, FieldMemOperand(a3, SharedFunctionInfo::kCompilerHintsOffset));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003172 int32_t strict_mode_function_mask =
3173 1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize);
3174 int32_t native_mask = 1 << (SharedFunctionInfo::kNative + kSmiTagSize);
machenbach@chromium.org0e76f002014-02-03 07:23:16 +00003175 __ And(at, t0, Operand(strict_mode_function_mask | native_mask));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003176 __ Branch(&cont, ne, at, Operand(zero_reg));
3177 }
3178
dslomov@chromium.org486536d2014-03-12 13:09:18 +00003179 // Compute the receiver in sloppy mode.
machenbach@chromium.org0e76f002014-02-03 07:23:16 +00003180 __ lw(a3, MemOperand(sp, argc_ * kPointerSize));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003181
3182 if (NeedsChecks()) {
machenbach@chromium.org0e76f002014-02-03 07:23:16 +00003183 __ JumpIfSmi(a3, &wrap);
3184 __ GetObjectType(a3, t0, t0);
3185 __ Branch(&wrap, lt, t0, Operand(FIRST_SPEC_OBJECT_TYPE));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003186 } else {
3187 __ jmp(&wrap);
3188 }
3189
3190 __ bind(&cont);
3191 }
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003192 __ InvokeFunction(a1, actual, JUMP_FUNCTION, NullCallWrapper());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003193
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003194 if (NeedsChecks()) {
3195 // Slow-case: Non-function called.
3196 __ bind(&slow);
3197 if (RecordCallTarget()) {
3198 // If there is a call target cache, mark it megamorphic in the
3199 // non-function case. MegamorphicSentinel is an immortal immovable
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00003200 // object (megamorphic symbol) so no write barrier is needed.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003201 ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(masm->isolate()),
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00003202 masm->isolate()->heap()->megamorphic_symbol());
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003203 __ sll(t1, a3, kPointerSizeLog2 - kSmiTagSize);
3204 __ Addu(t1, a2, Operand(t1));
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00003205 __ LoadRoot(at, Heap::kMegamorphicSymbolRootIndex);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003206 __ sw(at, FieldMemOperand(t1, FixedArray::kHeaderSize));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003207 }
3208 // Check for function proxy.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003209 __ Branch(&non_function, ne, t0, Operand(JS_FUNCTION_PROXY_TYPE));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003210 __ push(a1); // Put proxy as additional argument.
3211 __ li(a0, Operand(argc_ + 1, RelocInfo::NONE32));
3212 __ li(a2, Operand(0, RelocInfo::NONE32));
3213 __ GetBuiltinFunction(a1, Builtins::CALL_FUNCTION_PROXY);
3214 {
3215 Handle<Code> adaptor =
3216 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
3217 __ Jump(adaptor, RelocInfo::CODE_TARGET);
3218 }
3219
3220 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
3221 // of the original receiver from the call site).
3222 __ bind(&non_function);
3223 __ sw(a1, MemOperand(sp, argc_ * kPointerSize));
3224 __ li(a0, Operand(argc_)); // Set up the number of arguments.
3225 __ li(a2, Operand(0, RelocInfo::NONE32));
3226 __ GetBuiltinFunction(a1, Builtins::CALL_NON_FUNCTION);
3227 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
3228 RelocInfo::CODE_TARGET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003229 }
3230
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003231 if (CallAsMethod()) {
3232 __ bind(&wrap);
3233 // Wrap the receiver and patch it back onto the stack.
3234 { FrameScope frame_scope(masm, StackFrame::INTERNAL);
machenbach@chromium.org0e76f002014-02-03 07:23:16 +00003235 __ Push(a1, a3);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003236 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
3237 __ pop(a1);
3238 }
3239 __ mov(a0, v0);
3240 __ sw(a0, MemOperand(sp, argc_ * kPointerSize));
3241 __ jmp(&cont);
3242 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00003243}
3244
3245
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003246void CallConstructStub::Generate(MacroAssembler* masm) {
3247 // a0 : number of arguments
3248 // a1 : the function to call
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003249 // a2 : feedback vector
3250 // a3 : (only if a2 is not undefined) slot in feedback vector (Smi)
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003251 Label slow, non_function_call;
3252
3253 // Check that the function is not a smi.
3254 __ JumpIfSmi(a1, &non_function_call);
3255 // Check that the function is a JSFunction.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003256 __ GetObjectType(a1, t0, t0);
3257 __ Branch(&slow, ne, t0, Operand(JS_FUNCTION_TYPE));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003258
3259 if (RecordCallTarget()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003260 GenerateRecordCallTarget(masm);
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00003261
3262 __ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
3263 __ Addu(t1, a2, at);
3264 if (FLAG_pretenuring_call_new) {
3265 // Put the AllocationSite from the feedback vector into a2.
3266 // By adding kPointerSize we encode that we know the AllocationSite
3267 // entry is at the feedback vector slot given by a3 + 1.
3268 __ lw(a2, FieldMemOperand(t1, FixedArray::kHeaderSize + kPointerSize));
3269 } else {
3270 Label feedback_register_initialized;
3271 // Put the AllocationSite from the feedback vector into a2, or undefined.
3272 __ lw(a2, FieldMemOperand(t1, FixedArray::kHeaderSize));
3273 __ lw(t1, FieldMemOperand(a2, AllocationSite::kMapOffset));
3274 __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
3275 __ Branch(&feedback_register_initialized, eq, t1, Operand(at));
3276 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
3277 __ bind(&feedback_register_initialized);
3278 }
3279
3280 __ AssertUndefinedOrAllocationSite(a2, t1);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003281 }
3282
3283 // Jump to the function-specific construct stub.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003284 Register jmp_reg = t0;
ulan@chromium.org750145a2013-03-07 15:14:13 +00003285 __ lw(jmp_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3286 __ lw(jmp_reg, FieldMemOperand(jmp_reg,
3287 SharedFunctionInfo::kConstructStubOffset));
3288 __ Addu(at, jmp_reg, Operand(Code::kHeaderSize - kHeapObjectTag));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003289 __ Jump(at);
3290
3291 // a0: number of arguments
3292 // a1: called object
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003293 // t0: object type
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003294 Label do_call;
3295 __ bind(&slow);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003296 __ Branch(&non_function_call, ne, t0, Operand(JS_FUNCTION_PROXY_TYPE));
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +00003297 __ GetBuiltinFunction(a1, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003298 __ jmp(&do_call);
3299
3300 __ bind(&non_function_call);
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +00003301 __ GetBuiltinFunction(a1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003302 __ bind(&do_call);
3303 // Set expected number of arguments to zero (not changing r0).
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003304 __ li(a2, Operand(0, RelocInfo::NONE32));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003305 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
3306 RelocInfo::CODE_TARGET);
3307}
3308
3309
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003310// StringCharCodeAtGenerator.
lrn@chromium.org7516f052011-03-30 08:52:27 +00003311void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003312 Label flat_string;
3313 Label ascii_string;
3314 Label got_char_code;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003315 Label sliced_string;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003316
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003317 ASSERT(!t0.is(index_));
3318 ASSERT(!t0.is(result_));
3319 ASSERT(!t0.is(object_));
3320
3321 // If the receiver is a smi trigger the non-string case.
3322 __ JumpIfSmi(object_, receiver_not_string_);
3323
3324 // Fetch the instance type of the receiver into result register.
3325 __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
3326 __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
3327 // If the receiver is not a string trigger the non-string case.
3328 __ And(t0, result_, Operand(kIsNotStringMask));
3329 __ Branch(receiver_not_string_, ne, t0, Operand(zero_reg));
3330
3331 // If the index is non-smi trigger the non-smi case.
3332 __ JumpIfNotSmi(index_, &index_not_smi_);
3333
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003334 __ bind(&got_smi_index_);
3335
3336 // Check for index out of range.
3337 __ lw(t0, FieldMemOperand(object_, String::kLengthOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003338 __ Branch(index_out_of_range_, ls, t0, Operand(index_));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003339
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003340 __ sra(index_, index_, kSmiTagSize);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003341
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003342 StringCharLoadGenerator::Generate(masm,
3343 object_,
3344 index_,
3345 result_,
3346 &call_runtime_);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003347
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003348 __ sll(result_, result_, kSmiTagSize);
3349 __ bind(&exit_);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003350}
3351
3352
3353void StringCharCodeAtGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003354 MacroAssembler* masm,
3355 const RuntimeCallHelper& call_helper) {
danno@chromium.org59400602013-08-13 17:09:37 +00003356 __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003357
3358 // Index is not a smi.
3359 __ bind(&index_not_smi_);
3360 // If index is a heap number, try converting it to an integer.
3361 __ CheckMap(index_,
danno@chromium.orgc612e022011-11-10 11:38:15 +00003362 result_,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003363 Heap::kHeapNumberMapRootIndex,
3364 index_not_number_,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003365 DONT_DO_SMI_CHECK);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003366 call_helper.BeforeCall(masm);
3367 // Consumed by runtime conversion function:
danno@chromium.orgc612e022011-11-10 11:38:15 +00003368 __ Push(object_, index_);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003369 if (index_flags_ == STRING_INDEX_IS_NUMBER) {
3370 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
3371 } else {
3372 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
3373 // NumberToSmi discards numbers that are not exact integers.
machenbach@chromium.org895f00d2014-03-27 01:04:43 +00003374 __ CallRuntime(Runtime::kHiddenNumberToSmi, 1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003375 }
3376
3377 // Save the conversion result before the pop instructions below
3378 // have a chance to overwrite it.
3379
danno@chromium.orgc612e022011-11-10 11:38:15 +00003380 __ Move(index_, v0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003381 __ pop(object_);
3382 // Reload the instance type.
3383 __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
3384 __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
3385 call_helper.AfterCall(masm);
3386 // If index is still not a smi, it must be out of range.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003387 __ JumpIfNotSmi(index_, index_out_of_range_);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003388 // Otherwise, return to the fast path.
3389 __ Branch(&got_smi_index_);
3390
3391 // Call runtime. We get here when the receiver is a string and the
3392 // index is a number, but the code of getting the actual character
3393 // is too complex (e.g., when the string needs to be flattened).
3394 __ bind(&call_runtime_);
3395 call_helper.BeforeCall(masm);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003396 __ sll(index_, index_, kSmiTagSize);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003397 __ Push(object_, index_);
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +00003398 __ CallRuntime(Runtime::kHiddenStringCharCodeAt, 2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003399
3400 __ Move(result_, v0);
3401
3402 call_helper.AfterCall(masm);
3403 __ jmp(&exit_);
3404
danno@chromium.org59400602013-08-13 17:09:37 +00003405 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003406}
3407
3408
3409// -------------------------------------------------------------------------
3410// StringCharFromCodeGenerator
3411
3412void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003413 // Fast case of Heap::LookupSingleCharacterStringFromCode.
3414
3415 ASSERT(!t0.is(result_));
3416 ASSERT(!t0.is(code_));
3417
3418 STATIC_ASSERT(kSmiTag == 0);
3419 STATIC_ASSERT(kSmiShiftSize == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003420 ASSERT(IsPowerOf2(String::kMaxOneByteCharCode + 1));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003421 __ And(t0,
3422 code_,
3423 Operand(kSmiTagMask |
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003424 ((~String::kMaxOneByteCharCode) << kSmiTagSize)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003425 __ Branch(&slow_case_, ne, t0, Operand(zero_reg));
3426
3427 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
3428 // At this point code register contains smi tagged ASCII char code.
3429 STATIC_ASSERT(kSmiTag == 0);
3430 __ sll(t0, code_, kPointerSizeLog2 - kSmiTagSize);
3431 __ Addu(result_, result_, t0);
3432 __ lw(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
3433 __ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
3434 __ Branch(&slow_case_, eq, result_, Operand(t0));
3435 __ bind(&exit_);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003436}
3437
3438
3439void StringCharFromCodeGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003440 MacroAssembler* masm,
3441 const RuntimeCallHelper& call_helper) {
danno@chromium.org59400602013-08-13 17:09:37 +00003442 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003443
3444 __ bind(&slow_case_);
3445 call_helper.BeforeCall(masm);
3446 __ push(code_);
3447 __ CallRuntime(Runtime::kCharFromCode, 1);
3448 __ Move(result_, v0);
3449
3450 call_helper.AfterCall(masm);
3451 __ Branch(&exit_);
3452
danno@chromium.org59400602013-08-13 17:09:37 +00003453 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003454}
3455
3456
lrn@chromium.org7516f052011-03-30 08:52:27 +00003457enum CopyCharactersFlags {
3458 COPY_ASCII = 1,
3459 DEST_ALWAYS_ALIGNED = 2
3460};
3461
3462
3463void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm,
3464 Register dest,
3465 Register src,
3466 Register count,
3467 Register scratch1,
3468 Register scratch2,
3469 Register scratch3,
3470 Register scratch4,
3471 Register scratch5,
3472 int flags) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003473 bool ascii = (flags & COPY_ASCII) != 0;
3474 bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0;
3475
3476 if (dest_always_aligned && FLAG_debug_code) {
3477 // Check that destination is actually word aligned if the flag says
3478 // that it is.
3479 __ And(scratch4, dest, Operand(kPointerAlignmentMask));
3480 __ Check(eq,
danno@chromium.org59400602013-08-13 17:09:37 +00003481 kDestinationOfCopyNotAligned,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003482 scratch4,
3483 Operand(zero_reg));
3484 }
3485
3486 const int kReadAlignment = 4;
3487 const int kReadAlignmentMask = kReadAlignment - 1;
3488 // Ensure that reading an entire aligned word containing the last character
3489 // of a string will not read outside the allocated area (because we pad up
3490 // to kObjectAlignment).
3491 STATIC_ASSERT(kObjectAlignment >= kReadAlignment);
3492 // Assumes word reads and writes are little endian.
3493 // Nothing to do for zero characters.
3494 Label done;
3495
3496 if (!ascii) {
3497 __ addu(count, count, count);
3498 }
3499 __ Branch(&done, eq, count, Operand(zero_reg));
3500
3501 Label byte_loop;
3502 // Must copy at least eight bytes, otherwise just do it one byte at a time.
3503 __ Subu(scratch1, count, Operand(8));
3504 __ Addu(count, dest, Operand(count));
3505 Register limit = count; // Read until src equals this.
3506 __ Branch(&byte_loop, lt, scratch1, Operand(zero_reg));
3507
3508 if (!dest_always_aligned) {
3509 // Align dest by byte copying. Copies between zero and three bytes.
3510 __ And(scratch4, dest, Operand(kReadAlignmentMask));
3511 Label dest_aligned;
3512 __ Branch(&dest_aligned, eq, scratch4, Operand(zero_reg));
3513 Label aligned_loop;
3514 __ bind(&aligned_loop);
3515 __ lbu(scratch1, MemOperand(src));
3516 __ addiu(src, src, 1);
3517 __ sb(scratch1, MemOperand(dest));
3518 __ addiu(dest, dest, 1);
3519 __ addiu(scratch4, scratch4, 1);
3520 __ Branch(&aligned_loop, le, scratch4, Operand(kReadAlignmentMask));
3521 __ bind(&dest_aligned);
3522 }
3523
3524 Label simple_loop;
3525
3526 __ And(scratch4, src, Operand(kReadAlignmentMask));
3527 __ Branch(&simple_loop, eq, scratch4, Operand(zero_reg));
3528
3529 // Loop for src/dst that are not aligned the same way.
3530 // This loop uses lwl and lwr instructions. These instructions
3531 // depend on the endianness, and the implementation assumes little-endian.
3532 {
3533 Label loop;
3534 __ bind(&loop);
3535 __ lwr(scratch1, MemOperand(src));
3536 __ Addu(src, src, Operand(kReadAlignment));
3537 __ lwl(scratch1, MemOperand(src, -1));
3538 __ sw(scratch1, MemOperand(dest));
3539 __ Addu(dest, dest, Operand(kReadAlignment));
3540 __ Subu(scratch2, limit, dest);
3541 __ Branch(&loop, ge, scratch2, Operand(kReadAlignment));
3542 }
3543
3544 __ Branch(&byte_loop);
3545
3546 // Simple loop.
3547 // Copy words from src to dest, until less than four bytes left.
3548 // Both src and dest are word aligned.
3549 __ bind(&simple_loop);
3550 {
3551 Label loop;
3552 __ bind(&loop);
3553 __ lw(scratch1, MemOperand(src));
3554 __ Addu(src, src, Operand(kReadAlignment));
3555 __ sw(scratch1, MemOperand(dest));
3556 __ Addu(dest, dest, Operand(kReadAlignment));
3557 __ Subu(scratch2, limit, dest);
3558 __ Branch(&loop, ge, scratch2, Operand(kReadAlignment));
3559 }
3560
3561 // Copy bytes from src to dest until dest hits limit.
3562 __ bind(&byte_loop);
3563 // Test if dest has already reached the limit.
3564 __ Branch(&done, ge, dest, Operand(limit));
3565 __ lbu(scratch1, MemOperand(src));
3566 __ addiu(src, src, 1);
3567 __ sb(scratch1, MemOperand(dest));
3568 __ addiu(dest, dest, 1);
3569 __ Branch(&byte_loop);
3570
3571 __ bind(&done);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003572}
3573
3574
lrn@chromium.org7516f052011-03-30 08:52:27 +00003575void StringHelper::GenerateHashInit(MacroAssembler* masm,
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003576 Register hash,
3577 Register character) {
3578 // hash = seed + character + ((seed + character) << 10);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003579 __ LoadRoot(hash, Heap::kHashSeedRootIndex);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003580 // Untag smi seed and add the character.
3581 __ SmiUntag(hash);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003582 __ addu(hash, hash, character);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003583 __ sll(at, hash, 10);
3584 __ addu(hash, hash, at);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003585 // hash ^= hash >> 6;
danno@chromium.org2c456792011-11-11 12:00:53 +00003586 __ srl(at, hash, 6);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003587 __ xor_(hash, hash, at);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003588}
3589
3590
3591void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003592 Register hash,
3593 Register character) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003594 // hash += character;
3595 __ addu(hash, hash, character);
3596 // hash += hash << 10;
3597 __ sll(at, hash, 10);
3598 __ addu(hash, hash, at);
3599 // hash ^= hash >> 6;
danno@chromium.org2c456792011-11-11 12:00:53 +00003600 __ srl(at, hash, 6);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003601 __ xor_(hash, hash, at);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003602}
3603
3604
3605void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003606 Register hash) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003607 // hash += hash << 3;
3608 __ sll(at, hash, 3);
3609 __ addu(hash, hash, at);
3610 // hash ^= hash >> 11;
danno@chromium.org2c456792011-11-11 12:00:53 +00003611 __ srl(at, hash, 11);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003612 __ xor_(hash, hash, at);
3613 // hash += hash << 15;
3614 __ sll(at, hash, 15);
3615 __ addu(hash, hash, at);
3616
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003617 __ li(at, Operand(String::kHashBitMask));
danno@chromium.org2c456792011-11-11 12:00:53 +00003618 __ and_(hash, hash, at);
3619
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003620 // if (hash == 0) hash = 27;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003621 __ ori(at, zero_reg, StringHasher::kZeroHash);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003622 __ Movz(hash, at, hash);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003623}
3624
3625
3626void SubStringStub::Generate(MacroAssembler* masm) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003627 Label runtime;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003628 // Stack frame on entry.
3629 // ra: return address
3630 // sp[0]: to
3631 // sp[4]: from
3632 // sp[8]: string
3633
3634 // This stub is called from the native-call %_SubString(...), so
3635 // nothing can be assumed about the arguments. It is tested that:
3636 // "string" is a sequential string,
3637 // both "from" and "to" are smis, and
3638 // 0 <= from <= to <= string.length.
3639 // If any of these assumptions fail, we call the runtime system.
3640
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003641 const int kToOffset = 0 * kPointerSize;
3642 const int kFromOffset = 1 * kPointerSize;
3643 const int kStringOffset = 2 * kPointerSize;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003644
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003645 __ lw(a2, MemOperand(sp, kToOffset));
3646 __ lw(a3, MemOperand(sp, kFromOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003647 STATIC_ASSERT(kFromOffset == kToOffset + 4);
3648 STATIC_ASSERT(kSmiTag == 0);
3649 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
3650
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003651 // Utilize delay slots. SmiUntag doesn't emit a jump, everything else is
3652 // safe in this case.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003653 __ UntagAndJumpIfNotSmi(a2, a2, &runtime);
3654 __ UntagAndJumpIfNotSmi(a3, a3, &runtime);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003655 // Both a2 and a3 are untagged integers.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003656
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003657 __ Branch(&runtime, lt, a3, Operand(zero_reg)); // From < 0.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003658
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003659 __ Branch(&runtime, gt, a3, Operand(a2)); // Fail if from > to.
3660 __ Subu(a2, a2, a3);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003661
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003662 // Make sure first argument is a string.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003663 __ lw(v0, MemOperand(sp, kStringOffset));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003664 __ JumpIfSmi(v0, &runtime);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003665 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003666 __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003667 __ And(t0, a1, Operand(kIsNotStringMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003668
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003669 __ Branch(&runtime, ne, t0, Operand(zero_reg));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003670
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003671 Label single_char;
3672 __ Branch(&single_char, eq, a2, Operand(1));
3673
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003674 // Short-cut for the case of trivial substring.
3675 Label return_v0;
3676 // v0: original string
3677 // a2: result string length
3678 __ lw(t0, FieldMemOperand(v0, String::kLengthOffset));
3679 __ sra(t0, t0, 1);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003680 // Return original string.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003681 __ Branch(&return_v0, eq, a2, Operand(t0));
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003682 // Longer than original string's length or negative: unsafe arguments.
3683 __ Branch(&runtime, hi, a2, Operand(t0));
3684 // Shorter than original string's length: an actual substring.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003685
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003686 // Deal with different string types: update the index if necessary
3687 // and put the underlying string into t1.
3688 // v0: original string
3689 // a1: instance type
3690 // a2: length
3691 // a3: from index (untagged)
3692 Label underlying_unpacked, sliced_string, seq_or_external_string;
3693 // If the string is not indirect, it can only be sequential or external.
3694 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
3695 STATIC_ASSERT(kIsIndirectStringMask != 0);
3696 __ And(t0, a1, Operand(kIsIndirectStringMask));
3697 __ Branch(USE_DELAY_SLOT, &seq_or_external_string, eq, t0, Operand(zero_reg));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00003698 // t0 is used as a scratch register and can be overwritten in either case.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003699 __ And(t0, a1, Operand(kSlicedNotConsMask));
3700 __ Branch(&sliced_string, ne, t0, Operand(zero_reg));
3701 // Cons string. Check whether it is flat, then fetch first part.
3702 __ lw(t1, FieldMemOperand(v0, ConsString::kSecondOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003703 __ LoadRoot(t0, Heap::kempty_stringRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003704 __ Branch(&runtime, ne, t1, Operand(t0));
3705 __ lw(t1, FieldMemOperand(v0, ConsString::kFirstOffset));
3706 // Update instance type.
3707 __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset));
3708 __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
3709 __ jmp(&underlying_unpacked);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003710
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003711 __ bind(&sliced_string);
3712 // Sliced string. Fetch parent and correct start index by offset.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003713 __ lw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003714 __ lw(t0, FieldMemOperand(v0, SlicedString::kOffsetOffset));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003715 __ sra(t0, t0, 1); // Add offset to index.
3716 __ Addu(a3, a3, t0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003717 // Update instance type.
3718 __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset));
3719 __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
3720 __ jmp(&underlying_unpacked);
3721
3722 __ bind(&seq_or_external_string);
3723 // Sequential or external string. Just move string to the expected register.
3724 __ mov(t1, v0);
3725
3726 __ bind(&underlying_unpacked);
3727
3728 if (FLAG_string_slices) {
3729 Label copy_routine;
3730 // t1: underlying subject string
3731 // a1: instance type of underlying subject string
3732 // a2: length
3733 // a3: adjusted start index (untagged)
3734 // Short slice. Copy instead of slicing.
3735 __ Branch(&copy_routine, lt, a2, Operand(SlicedString::kMinLength));
3736 // Allocate new sliced string. At this point we do not reload the instance
3737 // type including the string encoding because we simply rely on the info
3738 // provided by the original string. It does not matter if the original
3739 // string's encoding is wrong because we always have to recheck encoding of
3740 // the newly created string's parent anyways due to externalized strings.
3741 Label two_byte_slice, set_slice_header;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003742 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003743 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
3744 __ And(t0, a1, Operand(kStringEncodingMask));
3745 __ Branch(&two_byte_slice, eq, t0, Operand(zero_reg));
3746 __ AllocateAsciiSlicedString(v0, a2, t2, t3, &runtime);
3747 __ jmp(&set_slice_header);
3748 __ bind(&two_byte_slice);
3749 __ AllocateTwoByteSlicedString(v0, a2, t2, t3, &runtime);
3750 __ bind(&set_slice_header);
3751 __ sll(a3, a3, 1);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003752 __ sw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003753 __ sw(a3, FieldMemOperand(v0, SlicedString::kOffsetOffset));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003754 __ jmp(&return_v0);
3755
3756 __ bind(&copy_routine);
3757 }
3758
3759 // t1: underlying subject string
3760 // a1: instance type of underlying subject string
3761 // a2: length
3762 // a3: adjusted start index (untagged)
3763 Label two_byte_sequential, sequential_string, allocate_result;
3764 STATIC_ASSERT(kExternalStringTag != 0);
3765 STATIC_ASSERT(kSeqStringTag == 0);
3766 __ And(t0, a1, Operand(kExternalStringTag));
3767 __ Branch(&sequential_string, eq, t0, Operand(zero_reg));
3768
3769 // Handle external string.
3770 // Rule out short external strings.
3771 STATIC_CHECK(kShortExternalStringTag != 0);
3772 __ And(t0, a1, Operand(kShortExternalStringTag));
3773 __ Branch(&runtime, ne, t0, Operand(zero_reg));
3774 __ lw(t1, FieldMemOperand(t1, ExternalString::kResourceDataOffset));
3775 // t1 already points to the first character of underlying string.
3776 __ jmp(&allocate_result);
3777
3778 __ bind(&sequential_string);
3779 // Locate first character of underlying subject string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003780 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
3781 __ Addu(t1, t1, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003782
3783 __ bind(&allocate_result);
3784 // Sequential acii string. Allocate the result.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003785 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003786 __ And(t0, a1, Operand(kStringEncodingMask));
3787 __ Branch(&two_byte_sequential, eq, t0, Operand(zero_reg));
3788
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003789 // Allocate and copy the resulting ASCII string.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003790 __ AllocateAsciiString(v0, a2, t0, t2, t3, &runtime);
3791
3792 // Locate first character of substring to copy.
3793 __ Addu(t1, t1, a3);
3794
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003795 // Locate first character of result.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003796 __ Addu(a1, v0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003797
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003798 // v0: result string
3799 // a1: first character of result string
3800 // a2: result string length
3801 // t1: first character of substring to copy
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003802 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003803 StringHelper::GenerateCopyCharactersLong(
3804 masm, a1, t1, a2, a3, t0, t2, t3, t4, COPY_ASCII | DEST_ALWAYS_ALIGNED);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003805 __ jmp(&return_v0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003806
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003807 // Allocate and copy the resulting two-byte string.
3808 __ bind(&two_byte_sequential);
3809 __ AllocateTwoByteString(v0, a2, t0, t2, t3, &runtime);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003810
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003811 // Locate first character of substring to copy.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003812 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003813 __ sll(t0, a3, 1);
3814 __ Addu(t1, t1, t0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003815 // Locate first character of result.
3816 __ Addu(a1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003817
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003818 // v0: result string.
3819 // a1: first character of result.
3820 // a2: result length.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003821 // t1: first character of substring to copy.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003822 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
3823 StringHelper::GenerateCopyCharactersLong(
3824 masm, a1, t1, a2, a3, t0, t2, t3, t4, DEST_ALWAYS_ALIGNED);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003825
3826 __ bind(&return_v0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003827 Counters* counters = masm->isolate()->counters();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003828 __ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003829 __ DropAndRet(3);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003830
3831 // Just jump to runtime to create the sub string.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003832 __ bind(&runtime);
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +00003833 __ TailCallRuntime(Runtime::kHiddenSubString, 3, 1);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003834
3835 __ bind(&single_char);
3836 // v0: original string
3837 // a1: instance type
3838 // a2: length
3839 // a3: from index (untagged)
3840 __ SmiTag(a3, a3);
3841 StringCharAtGenerator generator(
3842 v0, a3, a2, v0, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
3843 generator.GenerateFast(masm);
3844 __ DropAndRet(3);
3845 generator.SkipSlow(masm, &runtime);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003846}
3847
3848
3849void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
3850 Register left,
3851 Register right,
3852 Register scratch1,
3853 Register scratch2,
3854 Register scratch3) {
3855 Register length = scratch1;
3856
3857 // Compare lengths.
3858 Label strings_not_equal, check_zero_length;
3859 __ lw(length, FieldMemOperand(left, String::kLengthOffset));
3860 __ lw(scratch2, FieldMemOperand(right, String::kLengthOffset));
3861 __ Branch(&check_zero_length, eq, length, Operand(scratch2));
3862 __ bind(&strings_not_equal);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003863 ASSERT(is_int16(NOT_EQUAL));
3864 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003865 __ li(v0, Operand(Smi::FromInt(NOT_EQUAL)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003866
3867 // Check if the length is zero.
3868 Label compare_chars;
3869 __ bind(&check_zero_length);
3870 STATIC_ASSERT(kSmiTag == 0);
3871 __ Branch(&compare_chars, ne, length, Operand(zero_reg));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003872 ASSERT(is_int16(EQUAL));
3873 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003874 __ li(v0, Operand(Smi::FromInt(EQUAL)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003875
3876 // Compare characters.
3877 __ bind(&compare_chars);
3878
3879 GenerateAsciiCharsCompareLoop(masm,
3880 left, right, length, scratch2, scratch3, v0,
3881 &strings_not_equal);
3882
3883 // Characters are equal.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003884 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003885 __ li(v0, Operand(Smi::FromInt(EQUAL)));
lrn@chromium.org7516f052011-03-30 08:52:27 +00003886}
3887
3888
3889void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003890 Register left,
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003891 Register right,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003892 Register scratch1,
3893 Register scratch2,
3894 Register scratch3,
3895 Register scratch4) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003896 Label result_not_equal, compare_lengths;
3897 // Find minimum length and length difference.
3898 __ lw(scratch1, FieldMemOperand(left, String::kLengthOffset));
3899 __ lw(scratch2, FieldMemOperand(right, String::kLengthOffset));
3900 __ Subu(scratch3, scratch1, Operand(scratch2));
3901 Register length_delta = scratch3;
3902 __ slt(scratch4, scratch2, scratch1);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003903 __ Movn(scratch1, scratch2, scratch4);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003904 Register min_length = scratch1;
3905 STATIC_ASSERT(kSmiTag == 0);
3906 __ Branch(&compare_lengths, eq, min_length, Operand(zero_reg));
3907
3908 // Compare loop.
3909 GenerateAsciiCharsCompareLoop(masm,
3910 left, right, min_length, scratch2, scratch4, v0,
3911 &result_not_equal);
3912
3913 // Compare lengths - strings up to min-length are equal.
3914 __ bind(&compare_lengths);
3915 ASSERT(Smi::FromInt(EQUAL) == static_cast<Smi*>(0));
3916 // Use length_delta as result if it's zero.
3917 __ mov(scratch2, length_delta);
3918 __ mov(scratch4, zero_reg);
3919 __ mov(v0, zero_reg);
3920
3921 __ bind(&result_not_equal);
3922 // Conditionally update the result based either on length_delta or
3923 // the last comparion performed in the loop above.
3924 Label ret;
3925 __ Branch(&ret, eq, scratch2, Operand(scratch4));
3926 __ li(v0, Operand(Smi::FromInt(GREATER)));
3927 __ Branch(&ret, gt, scratch2, Operand(scratch4));
3928 __ li(v0, Operand(Smi::FromInt(LESS)));
3929 __ bind(&ret);
3930 __ Ret();
3931}
3932
3933
3934void StringCompareStub::GenerateAsciiCharsCompareLoop(
3935 MacroAssembler* masm,
3936 Register left,
3937 Register right,
3938 Register length,
3939 Register scratch1,
3940 Register scratch2,
3941 Register scratch3,
3942 Label* chars_not_equal) {
3943 // Change index to run from -length to -1 by adding length to string
3944 // start. This means that loop ends when index reaches zero, which
3945 // doesn't need an additional compare.
3946 __ SmiUntag(length);
3947 __ Addu(scratch1, length,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003948 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003949 __ Addu(left, left, Operand(scratch1));
3950 __ Addu(right, right, Operand(scratch1));
3951 __ Subu(length, zero_reg, length);
3952 Register index = length; // index = -length;
3953
3954
3955 // Compare loop.
3956 Label loop;
3957 __ bind(&loop);
3958 __ Addu(scratch3, left, index);
3959 __ lbu(scratch1, MemOperand(scratch3));
3960 __ Addu(scratch3, right, index);
3961 __ lbu(scratch2, MemOperand(scratch3));
3962 __ Branch(chars_not_equal, ne, scratch1, Operand(scratch2));
3963 __ Addu(index, index, 1);
3964 __ Branch(&loop, ne, index, Operand(zero_reg));
lrn@chromium.org7516f052011-03-30 08:52:27 +00003965}
3966
3967
3968void StringCompareStub::Generate(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003969 Label runtime;
3970
3971 Counters* counters = masm->isolate()->counters();
3972
3973 // Stack frame on entry.
3974 // sp[0]: right string
3975 // sp[4]: left string
3976 __ lw(a1, MemOperand(sp, 1 * kPointerSize)); // Left.
3977 __ lw(a0, MemOperand(sp, 0 * kPointerSize)); // Right.
3978
3979 Label not_same;
3980 __ Branch(&not_same, ne, a0, Operand(a1));
3981 STATIC_ASSERT(EQUAL == 0);
3982 STATIC_ASSERT(kSmiTag == 0);
3983 __ li(v0, Operand(Smi::FromInt(EQUAL)));
3984 __ IncrementCounter(counters->string_compare_native(), 1, a1, a2);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00003985 __ DropAndRet(2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003986
3987 __ bind(&not_same);
3988
3989 // Check that both objects are sequential ASCII strings.
3990 __ JumpIfNotBothSequentialAsciiStrings(a1, a0, a2, a3, &runtime);
3991
3992 // Compare flat ASCII strings natively. Remove arguments from stack first.
3993 __ IncrementCounter(counters->string_compare_native(), 1, a2, a3);
3994 __ Addu(sp, sp, Operand(2 * kPointerSize));
3995 GenerateCompareFlatAsciiStrings(masm, a1, a0, a2, a3, t0, t1);
3996
3997 __ bind(&runtime);
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +00003998 __ TailCallRuntime(Runtime::kHiddenStringCompare, 2, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003999}
4000
4001
machenbach@chromium.orgc8cbc432014-01-21 09:01:57 +00004002void ArrayPushStub::Generate(MacroAssembler* masm) {
4003 Register receiver = a0;
4004 Register scratch = a1;
4005
4006 int argc = arguments_count();
4007
4008 if (argc == 0) {
4009 // Nothing to do, just return the length.
4010 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
4011 __ DropAndRet(argc + 1);
4012 return;
4013 }
4014
4015 Isolate* isolate = masm->isolate();
4016
4017 if (argc != 1) {
4018 __ TailCallExternalReference(
4019 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4020 return;
4021 }
4022
4023 Label call_builtin, attempt_to_grow_elements, with_write_barrier;
4024
4025 Register elements = t2;
4026 Register end_elements = t1;
4027 // Get the elements array of the object.
4028 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
4029
4030 if (IsFastSmiOrObjectElementsKind(elements_kind())) {
4031 // Check that the elements are in fast mode and writable.
4032 __ CheckMap(elements,
4033 scratch,
4034 Heap::kFixedArrayMapRootIndex,
4035 &call_builtin,
4036 DONT_DO_SMI_CHECK);
4037 }
4038
4039 // Get the array's length into scratch and calculate new length.
4040 __ lw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
4041 __ Addu(scratch, scratch, Operand(Smi::FromInt(argc)));
4042
4043 // Get the elements' length.
4044 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
4045
4046 const int kEndElementsOffset =
4047 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
4048
4049 if (IsFastSmiOrObjectElementsKind(elements_kind())) {
4050 // Check if we could survive without allocation.
4051 __ Branch(&attempt_to_grow_elements, gt, scratch, Operand(t0));
4052
4053 // Check if value is a smi.
4054 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
4055 __ JumpIfNotSmi(t0, &with_write_barrier);
4056
4057 // Store the value.
4058 // We may need a register containing the address end_elements below,
4059 // so write back the value in end_elements.
4060 __ sll(end_elements, scratch, kPointerSizeLog2 - kSmiTagSize);
4061 __ Addu(end_elements, elements, end_elements);
4062 __ Addu(end_elements, end_elements, kEndElementsOffset);
4063 __ sw(t0, MemOperand(end_elements));
4064 } else {
4065 // Check if we could survive without allocation.
4066 __ Branch(&call_builtin, gt, scratch, Operand(t0));
4067
4068 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
4069 __ StoreNumberToDoubleElements(t0, scratch, elements, a3, t1, a2,
4070 &call_builtin, argc * kDoubleSize);
4071 }
4072
4073 // Save new length.
4074 __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
4075 __ mov(v0, scratch);
4076 __ DropAndRet(argc + 1);
4077
4078 if (IsFastDoubleElementsKind(elements_kind())) {
4079 __ bind(&call_builtin);
4080 __ TailCallExternalReference(
4081 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4082 return;
4083 }
4084
4085 __ bind(&with_write_barrier);
4086
4087 if (IsFastSmiElementsKind(elements_kind())) {
4088 if (FLAG_trace_elements_transitions) __ jmp(&call_builtin);
4089
4090 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
4091 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4092 __ Branch(&call_builtin, eq, t3, Operand(at));
4093
4094 ElementsKind target_kind = IsHoleyElementsKind(elements_kind())
4095 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
4096 __ lw(a3, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
4097 __ lw(a3, FieldMemOperand(a3, GlobalObject::kNativeContextOffset));
4098 __ lw(a3, ContextOperand(a3, Context::JS_ARRAY_MAPS_INDEX));
4099 const int header_size = FixedArrayBase::kHeaderSize;
4100 // Verify that the object can be transitioned in place.
4101 const int origin_offset = header_size + elements_kind() * kPointerSize;
4102 __ lw(a2, FieldMemOperand(receiver, origin_offset));
4103 __ lw(at, FieldMemOperand(a3, HeapObject::kMapOffset));
4104 __ Branch(&call_builtin, ne, a2, Operand(at));
4105
4106
4107 const int target_offset = header_size + target_kind * kPointerSize;
4108 __ lw(a3, FieldMemOperand(a3, target_offset));
4109 __ mov(a2, receiver);
4110 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
4111 masm, DONT_TRACK_ALLOCATION_SITE, NULL);
4112 }
4113
4114 // Save new length.
4115 __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
4116
4117 // Store the value.
4118 // We may need a register containing the address end_elements below, so write
4119 // back the value in end_elements.
4120 __ sll(end_elements, scratch, kPointerSizeLog2 - kSmiTagSize);
4121 __ Addu(end_elements, elements, end_elements);
4122 __ Addu(end_elements, end_elements, kEndElementsOffset);
4123 __ sw(t0, MemOperand(end_elements));
4124
4125 __ RecordWrite(elements,
4126 end_elements,
4127 t0,
4128 kRAHasNotBeenSaved,
4129 kDontSaveFPRegs,
4130 EMIT_REMEMBERED_SET,
4131 OMIT_SMI_CHECK);
4132 __ mov(v0, scratch);
4133 __ DropAndRet(argc + 1);
4134
4135 __ bind(&attempt_to_grow_elements);
4136 // scratch: array's length + 1.
4137
4138 if (!FLAG_inline_new) {
4139 __ bind(&call_builtin);
4140 __ TailCallExternalReference(
4141 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4142 return;
4143 }
4144
4145 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
4146 // Growing elements that are SMI-only requires special handling in case the
4147 // new element is non-Smi. For now, delegate to the builtin.
4148 if (IsFastSmiElementsKind(elements_kind())) {
4149 __ JumpIfNotSmi(a2, &call_builtin);
4150 }
4151
4152 // We could be lucky and the elements array could be at the top of new-space.
4153 // In this case we can just grow it in place by moving the allocation pointer
4154 // up.
4155 ExternalReference new_space_allocation_top =
4156 ExternalReference::new_space_allocation_top_address(isolate);
4157 ExternalReference new_space_allocation_limit =
4158 ExternalReference::new_space_allocation_limit_address(isolate);
4159
4160 const int kAllocationDelta = 4;
4161 ASSERT(kAllocationDelta >= argc);
4162 // Load top and check if it is the end of elements.
4163 __ sll(end_elements, scratch, kPointerSizeLog2 - kSmiTagSize);
4164 __ Addu(end_elements, elements, end_elements);
4165 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
4166 __ li(t0, Operand(new_space_allocation_top));
4167 __ lw(a3, MemOperand(t0));
4168 __ Branch(&call_builtin, ne, a3, Operand(end_elements));
4169
4170 __ li(t3, Operand(new_space_allocation_limit));
4171 __ lw(t3, MemOperand(t3));
4172 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
4173 __ Branch(&call_builtin, hi, a3, Operand(t3));
4174
4175 // We fit and could grow elements.
4176 // Update new_space_allocation_top.
4177 __ sw(a3, MemOperand(t0));
4178 // Push the argument.
4179 __ sw(a2, MemOperand(end_elements));
4180 // Fill the rest with holes.
4181 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
4182 for (int i = 1; i < kAllocationDelta; i++) {
4183 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
4184 }
4185
4186 // Update elements' and array's sizes.
4187 __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
4188 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
4189 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
4190 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
4191
4192 // Elements are in new space, so write barrier is not required.
4193 __ mov(v0, scratch);
4194 __ DropAndRet(argc + 1);
4195
4196 __ bind(&call_builtin);
4197 __ TailCallExternalReference(
4198 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4199}
4200
4201
ulan@chromium.org0f13e742014-01-03 15:51:11 +00004202void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
4203 // ----------- S t a t e -------------
4204 // -- a1 : left
4205 // -- a0 : right
4206 // -- ra : return address
4207 // -----------------------------------
4208 Isolate* isolate = masm->isolate();
4209
4210 // Load a2 with the allocation site. We stick an undefined dummy value here
4211 // and replace it with the real allocation site later when we instantiate this
4212 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
4213 __ li(a2, handle(isolate->heap()->undefined_value()));
4214
4215 // Make sure that we actually patched the allocation site.
4216 if (FLAG_debug_code) {
4217 __ And(at, a2, Operand(kSmiTagMask));
4218 __ Assert(ne, kExpectedAllocationSite, at, Operand(zero_reg));
4219 __ lw(t0, FieldMemOperand(a2, HeapObject::kMapOffset));
4220 __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
4221 __ Assert(eq, kExpectedAllocationSite, t0, Operand(at));
4222 }
4223
4224 // Tail call into the stub that handles binary operations with allocation
4225 // sites.
4226 BinaryOpWithAllocationSiteStub stub(state_);
4227 __ TailCallStub(&stub);
4228}
4229
4230
lrn@chromium.org7516f052011-03-30 08:52:27 +00004231void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004232 ASSERT(state_ == CompareIC::SMI);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004233 Label miss;
4234 __ Or(a2, a1, a0);
4235 __ JumpIfNotSmi(a2, &miss);
4236
4237 if (GetCondition() == eq) {
4238 // For equality we do not care about the sign of the result.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00004239 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004240 __ Subu(v0, a0, a1);
4241 } else {
4242 // Untag before subtracting to avoid handling overflow.
4243 __ SmiUntag(a1);
4244 __ SmiUntag(a0);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00004245 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004246 __ Subu(v0, a1, a0);
4247 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004248
4249 __ bind(&miss);
4250 GenerateMiss(masm);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004251}
4252
4253
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004254void ICCompareStub::GenerateNumbers(MacroAssembler* masm) {
4255 ASSERT(state_ == CompareIC::NUMBER);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004256
4257 Label generic_stub;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004258 Label unordered, maybe_undefined1, maybe_undefined2;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004259 Label miss;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004260
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004261 if (left_ == CompareIC::SMI) {
4262 __ JumpIfNotSmi(a1, &miss);
4263 }
4264 if (right_ == CompareIC::SMI) {
4265 __ JumpIfNotSmi(a0, &miss);
4266 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004267
4268 // Inlining the double comparison and falling back to the general compare
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004269 // stub if NaN is involved.
4270 // Load left and right operand.
4271 Label done, left, left_smi, right_smi;
4272 __ JumpIfSmi(a0, &right_smi);
4273 __ CheckMap(a0, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
4274 DONT_DO_SMI_CHECK);
4275 __ Subu(a2, a0, Operand(kHeapObjectTag));
4276 __ ldc1(f2, MemOperand(a2, HeapNumber::kValueOffset));
4277 __ Branch(&left);
4278 __ bind(&right_smi);
4279 __ SmiUntag(a2, a0); // Can't clobber a0 yet.
4280 FPURegister single_scratch = f6;
4281 __ mtc1(a2, single_scratch);
4282 __ cvt_d_w(f2, single_scratch);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004283
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004284 __ bind(&left);
4285 __ JumpIfSmi(a1, &left_smi);
4286 __ CheckMap(a1, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
4287 DONT_DO_SMI_CHECK);
4288 __ Subu(a2, a1, Operand(kHeapObjectTag));
4289 __ ldc1(f0, MemOperand(a2, HeapNumber::kValueOffset));
4290 __ Branch(&done);
4291 __ bind(&left_smi);
4292 __ SmiUntag(a2, a1); // Can't clobber a1 yet.
4293 single_scratch = f8;
4294 __ mtc1(a2, single_scratch);
4295 __ cvt_d_w(f0, single_scratch);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004296
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004297 __ bind(&done);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004298
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004299 // Return a result of -1, 0, or 1, or use CompareStub for NaNs.
4300 Label fpu_eq, fpu_lt;
4301 // Test if equal, and also handle the unordered/NaN case.
4302 __ BranchF(&fpu_eq, &unordered, eq, f0, f2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004303
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004304 // Test if less (unordered case is already handled).
4305 __ BranchF(&fpu_lt, NULL, lt, f0, f2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004306
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004307 // Otherwise it's greater, so just fall thru, and return.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00004308 ASSERT(is_int16(GREATER) && is_int16(EQUAL) && is_int16(LESS));
4309 __ Ret(USE_DELAY_SLOT);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004310 __ li(v0, Operand(GREATER));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004311
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004312 __ bind(&fpu_eq);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00004313 __ Ret(USE_DELAY_SLOT);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004314 __ li(v0, Operand(EQUAL));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004315
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004316 __ bind(&fpu_lt);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00004317 __ Ret(USE_DELAY_SLOT);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004318 __ li(v0, Operand(LESS));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004319
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004320 __ bind(&unordered);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004321 __ bind(&generic_stub);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004322 ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
4323 CompareIC::GENERIC);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004324 __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004325
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004326 __ bind(&maybe_undefined1);
4327 if (Token::IsOrderedRelationalCompareOp(op_)) {
4328 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
4329 __ Branch(&miss, ne, a0, Operand(at));
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004330 __ JumpIfSmi(a1, &unordered);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004331 __ GetObjectType(a1, a2, a2);
4332 __ Branch(&maybe_undefined2, ne, a2, Operand(HEAP_NUMBER_TYPE));
4333 __ jmp(&unordered);
4334 }
4335
4336 __ bind(&maybe_undefined2);
4337 if (Token::IsOrderedRelationalCompareOp(op_)) {
4338 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
4339 __ Branch(&unordered, eq, a1, Operand(at));
4340 }
4341
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004342 __ bind(&miss);
4343 GenerateMiss(masm);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004344}
4345
4346
ulan@chromium.org750145a2013-03-07 15:14:13 +00004347void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004348 ASSERT(state_ == CompareIC::INTERNALIZED_STRING);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004349 Label miss;
4350
4351 // Registers containing left and right operands respectively.
4352 Register left = a1;
4353 Register right = a0;
4354 Register tmp1 = a2;
4355 Register tmp2 = a3;
4356
4357 // Check that both operands are heap objects.
4358 __ JumpIfEitherSmi(left, right, &miss);
4359
ulan@chromium.org750145a2013-03-07 15:14:13 +00004360 // Check that both operands are internalized strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004361 __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
4362 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
4363 __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
4364 __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004365 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
4366 __ Or(tmp1, tmp1, Operand(tmp2));
4367 __ And(at, tmp1, Operand(kIsNotStringMask | kIsNotInternalizedMask));
4368 __ Branch(&miss, ne, at, Operand(zero_reg));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004369
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004370 // Make sure a0 is non-zero. At this point input operands are
4371 // guaranteed to be non-zero.
4372 ASSERT(right.is(a0));
4373 STATIC_ASSERT(EQUAL == 0);
4374 STATIC_ASSERT(kSmiTag == 0);
4375 __ mov(v0, right);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004376 // Internalized strings are compared by identity.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004377 __ Ret(ne, left, Operand(right));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00004378 ASSERT(is_int16(EQUAL));
4379 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004380 __ li(v0, Operand(Smi::FromInt(EQUAL)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004381
4382 __ bind(&miss);
4383 GenerateMiss(masm);
4384}
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004385
4386
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004387void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) {
4388 ASSERT(state_ == CompareIC::UNIQUE_NAME);
4389 ASSERT(GetCondition() == eq);
4390 Label miss;
4391
4392 // Registers containing left and right operands respectively.
4393 Register left = a1;
4394 Register right = a0;
4395 Register tmp1 = a2;
4396 Register tmp2 = a3;
4397
4398 // Check that both operands are heap objects.
4399 __ JumpIfEitherSmi(left, right, &miss);
4400
4401 // Check that both operands are unique names. This leaves the instance
4402 // types loaded in tmp1 and tmp2.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004403 __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
4404 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
4405 __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
4406 __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
4407
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004408 __ JumpIfNotUniqueName(tmp1, &miss);
4409 __ JumpIfNotUniqueName(tmp2, &miss);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004410
4411 // Use a0 as result
4412 __ mov(v0, a0);
4413
4414 // Unique names are compared by identity.
4415 Label done;
4416 __ Branch(&done, ne, left, Operand(right));
4417 // Make sure a0 is non-zero. At this point input operands are
4418 // guaranteed to be non-zero.
4419 ASSERT(right.is(a0));
4420 STATIC_ASSERT(EQUAL == 0);
4421 STATIC_ASSERT(kSmiTag == 0);
4422 __ li(v0, Operand(Smi::FromInt(EQUAL)));
4423 __ bind(&done);
4424 __ Ret();
4425
4426 __ bind(&miss);
4427 GenerateMiss(masm);
4428}
4429
4430
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004431void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004432 ASSERT(state_ == CompareIC::STRING);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004433 Label miss;
4434
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004435 bool equality = Token::IsEqualityOp(op_);
4436
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004437 // Registers containing left and right operands respectively.
4438 Register left = a1;
4439 Register right = a0;
4440 Register tmp1 = a2;
4441 Register tmp2 = a3;
4442 Register tmp3 = t0;
4443 Register tmp4 = t1;
4444 Register tmp5 = t2;
4445
4446 // Check that both operands are heap objects.
4447 __ JumpIfEitherSmi(left, right, &miss);
4448
4449 // Check that both operands are strings. This leaves the instance
4450 // types loaded in tmp1 and tmp2.
4451 __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
4452 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
4453 __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
4454 __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
4455 STATIC_ASSERT(kNotStringTag != 0);
4456 __ Or(tmp3, tmp1, tmp2);
4457 __ And(tmp5, tmp3, Operand(kIsNotStringMask));
4458 __ Branch(&miss, ne, tmp5, Operand(zero_reg));
4459
4460 // Fast check for identical strings.
4461 Label left_ne_right;
4462 STATIC_ASSERT(EQUAL == 0);
4463 STATIC_ASSERT(kSmiTag == 0);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004464 __ Branch(&left_ne_right, ne, left, Operand(right));
4465 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004466 __ mov(v0, zero_reg); // In the delay slot.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004467 __ bind(&left_ne_right);
4468
4469 // Handle not identical strings.
4470
ulan@chromium.org750145a2013-03-07 15:14:13 +00004471 // Check that both strings are internalized strings. If they are, we're done
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004472 // because we already know they are not identical. We know they are both
4473 // strings.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004474 if (equality) {
4475 ASSERT(GetCondition() == eq);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004476 STATIC_ASSERT(kInternalizedTag == 0);
4477 __ Or(tmp3, tmp1, Operand(tmp2));
4478 __ And(tmp5, tmp3, Operand(kIsNotInternalizedMask));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004479 Label is_symbol;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004480 __ Branch(&is_symbol, ne, tmp5, Operand(zero_reg));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004481 // Make sure a0 is non-zero. At this point input operands are
4482 // guaranteed to be non-zero.
4483 ASSERT(right.is(a0));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004484 __ Ret(USE_DELAY_SLOT);
4485 __ mov(v0, a0); // In the delay slot.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004486 __ bind(&is_symbol);
4487 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004488
4489 // Check that both strings are sequential ASCII.
4490 Label runtime;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004491 __ JumpIfBothInstanceTypesAreNotSequentialAscii(
4492 tmp1, tmp2, tmp3, tmp4, &runtime);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004493
4494 // Compare flat ASCII strings. Returns when done.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004495 if (equality) {
4496 StringCompareStub::GenerateFlatAsciiStringEquals(
4497 masm, left, right, tmp1, tmp2, tmp3);
4498 } else {
4499 StringCompareStub::GenerateCompareFlatAsciiStrings(
4500 masm, left, right, tmp1, tmp2, tmp3, tmp4);
4501 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004502
4503 // Handle more complex cases in runtime.
4504 __ bind(&runtime);
4505 __ Push(left, right);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004506 if (equality) {
4507 __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
4508 } else {
machenbach@chromium.org9b95fd72014-03-26 01:04:35 +00004509 __ TailCallRuntime(Runtime::kHiddenStringCompare, 2, 1);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004510 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004511
4512 __ bind(&miss);
4513 GenerateMiss(masm);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004514}
4515
4516
lrn@chromium.org7516f052011-03-30 08:52:27 +00004517void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004518 ASSERT(state_ == CompareIC::OBJECT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004519 Label miss;
4520 __ And(a2, a1, Operand(a0));
4521 __ JumpIfSmi(a2, &miss);
4522
4523 __ GetObjectType(a0, a2, a2);
4524 __ Branch(&miss, ne, a2, Operand(JS_OBJECT_TYPE));
4525 __ GetObjectType(a1, a2, a2);
4526 __ Branch(&miss, ne, a2, Operand(JS_OBJECT_TYPE));
4527
4528 ASSERT(GetCondition() == eq);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004529 __ Ret(USE_DELAY_SLOT);
4530 __ subu(v0, a0, a1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004531
4532 __ bind(&miss);
4533 GenerateMiss(masm);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004534}
4535
4536
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004537void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
4538 Label miss;
4539 __ And(a2, a1, a0);
4540 __ JumpIfSmi(a2, &miss);
4541 __ lw(a2, FieldMemOperand(a0, HeapObject::kMapOffset));
4542 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
4543 __ Branch(&miss, ne, a2, Operand(known_map_));
4544 __ Branch(&miss, ne, a3, Operand(known_map_));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004545
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004546 __ Ret(USE_DELAY_SLOT);
4547 __ subu(v0, a0, a1);
4548
4549 __ bind(&miss);
4550 GenerateMiss(masm);
4551}
4552
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00004553
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004554void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004555 {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004556 // Call the runtime system in a fresh internal frame.
4557 ExternalReference miss =
4558 ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004559 FrameScope scope(masm, StackFrame::INTERNAL);
4560 __ Push(a1, a0);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004561 __ Push(ra, a1, a0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004562 __ li(t0, Operand(Smi::FromInt(op_)));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004563 __ addiu(sp, sp, -kPointerSize);
4564 __ CallExternalReference(miss, 3, USE_DELAY_SLOT);
4565 __ sw(t0, MemOperand(sp)); // In the delay slot.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004566 // Compute the entry point of the rewritten stub.
4567 __ Addu(a2, v0, Operand(Code::kHeaderSize - kHeapObjectTag));
4568 // Restore registers.
4569 __ Pop(a1, a0, ra);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004570 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004571 __ Jump(a2);
4572}
4573
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004574
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004575void DirectCEntryStub::Generate(MacroAssembler* masm) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004576 // Make place for arguments to fit C calling convention. Most of the callers
4577 // of DirectCEntryStub::GenerateCall are using EnterExitFrame/LeaveExitFrame
4578 // so they handle stack restoring and we don't have to do that here.
4579 // Any caller of DirectCEntryStub::GenerateCall must take care of dropping
4580 // kCArgsSlotsSize stack space after the call.
4581 __ Subu(sp, sp, Operand(kCArgsSlotsSize));
4582 // Place the return address on the stack, making the call
4583 // GC safe. The RegExp backend also relies on this.
4584 __ sw(ra, MemOperand(sp, kCArgsSlotsSize));
4585 __ Call(t9); // Call the C++ function.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004586 __ lw(t9, MemOperand(sp, kCArgsSlotsSize));
4587
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004588 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004589 // In case of an error the return address may point to a memory area
4590 // filled with kZapValue by the GC.
4591 // Dereference the address and check for this.
4592 __ lw(t0, MemOperand(t9));
danno@chromium.org59400602013-08-13 17:09:37 +00004593 __ Assert(ne, kReceivedInvalidReturnAddress, t0,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004594 Operand(reinterpret_cast<uint32_t>(kZapValue)));
4595 }
4596 __ Jump(t9);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004597}
4598
4599
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004600void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004601 Register target) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004602 intptr_t loc =
4603 reinterpret_cast<intptr_t>(GetCode(masm->isolate()).location());
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004604 __ Move(t9, target);
4605 __ li(ra, Operand(loc, RelocInfo::CODE_TARGET), CONSTANT_SIZE);
4606 __ Call(ra);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004607}
4608
4609
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004610void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
4611 Label* miss,
4612 Label* done,
4613 Register receiver,
4614 Register properties,
4615 Handle<Name> name,
4616 Register scratch0) {
4617 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004618 // If names of slots in range from 1 to kProbes - 1 for the hash value are
4619 // not equal to the name and kProbes-th slot is not used (its name is the
4620 // undefined value), it guarantees the hash table doesn't contain the
4621 // property. It's true even if some slots represent deleted properties
ulan@chromium.org967e2702012-02-28 09:49:15 +00004622 // (their names are the hole value).
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004623 for (int i = 0; i < kInlinedProbes; i++) {
4624 // scratch0 points to properties hash.
4625 // Compute the masked index: (hash + i + i * i) & mask.
4626 Register index = scratch0;
4627 // Capacity is smi 2^n.
4628 __ lw(index, FieldMemOperand(properties, kCapacityOffset));
4629 __ Subu(index, index, Operand(1));
4630 __ And(index, index, Operand(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004631 Smi::FromInt(name->Hash() + NameDictionary::GetProbeOffset(i))));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004632
4633 // Scale the index by multiplying by the entry size.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004634 ASSERT(NameDictionary::kEntrySize == 3);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004635 __ sll(at, index, 1);
4636 __ Addu(index, index, at);
4637
4638 Register entity_name = scratch0;
4639 // Having undefined at this place means the name is not contained.
4640 ASSERT_EQ(kSmiTagSize, 1);
4641 Register tmp = properties;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004642 __ sll(scratch0, index, 1);
4643 __ Addu(tmp, properties, scratch0);
4644 __ lw(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
4645
4646 ASSERT(!tmp.is(entity_name));
4647 __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
4648 __ Branch(done, eq, entity_name, Operand(tmp));
4649
ulan@chromium.org77802e82013-03-26 11:54:42 +00004650 // Load the hole ready for use below:
4651 __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex);
ulan@chromium.org967e2702012-02-28 09:49:15 +00004652
ulan@chromium.org77802e82013-03-26 11:54:42 +00004653 // Stop if found the property.
4654 __ Branch(miss, eq, entity_name, Operand(Handle<Name>(name)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004655
ulan@chromium.org77802e82013-03-26 11:54:42 +00004656 Label good;
4657 __ Branch(&good, eq, entity_name, Operand(tmp));
ulan@chromium.org967e2702012-02-28 09:49:15 +00004658
ulan@chromium.org77802e82013-03-26 11:54:42 +00004659 // Check if the entry name is not a unique name.
4660 __ lw(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
4661 __ lbu(entity_name,
4662 FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004663 __ JumpIfNotUniqueName(entity_name, miss);
ulan@chromium.org77802e82013-03-26 11:54:42 +00004664 __ bind(&good);
ulan@chromium.org967e2702012-02-28 09:49:15 +00004665
ulan@chromium.org77802e82013-03-26 11:54:42 +00004666 // Restore the properties.
4667 __ lw(properties,
4668 FieldMemOperand(receiver, JSObject::kPropertiesOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004669 }
4670
4671 const int spill_mask =
4672 (ra.bit() | t2.bit() | t1.bit() | t0.bit() | a3.bit() |
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004673 a2.bit() | a1.bit() | a0.bit() | v0.bit());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004674
4675 __ MultiPush(spill_mask);
4676 __ lw(a0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004677 __ li(a1, Operand(Handle<Name>(name)));
4678 NameDictionaryLookupStub stub(NEGATIVE_LOOKUP);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004679 __ CallStub(&stub);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004680 __ mov(at, v0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004681 __ MultiPop(spill_mask);
4682
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004683 __ Branch(done, eq, at, Operand(zero_reg));
4684 __ Branch(miss, ne, at, Operand(zero_reg));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004685}
4686
4687
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004688// Probe the name dictionary in the |elements| register. Jump to the
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004689// |done| label if a property with the given name is found. Jump to
4690// the |miss| label otherwise.
4691// If lookup was successful |scratch2| will be equal to elements + 4 * index.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004692void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
4693 Label* miss,
4694 Label* done,
4695 Register elements,
4696 Register name,
4697 Register scratch1,
4698 Register scratch2) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004699 ASSERT(!elements.is(scratch1));
4700 ASSERT(!elements.is(scratch2));
4701 ASSERT(!name.is(scratch1));
4702 ASSERT(!name.is(scratch2));
4703
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004704 __ AssertName(name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004705
4706 // Compute the capacity mask.
4707 __ lw(scratch1, FieldMemOperand(elements, kCapacityOffset));
4708 __ sra(scratch1, scratch1, kSmiTagSize); // convert smi to int
4709 __ Subu(scratch1, scratch1, Operand(1));
4710
4711 // Generate an unrolled loop that performs a few probes before
4712 // giving up. Measurements done on Gmail indicate that 2 probes
4713 // cover ~93% of loads from dictionaries.
4714 for (int i = 0; i < kInlinedProbes; i++) {
4715 // Compute the masked index: (hash + i + i * i) & mask.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004716 __ lw(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004717 if (i > 0) {
4718 // Add the probe offset (i + i * i) left shifted to avoid right shifting
4719 // the hash in a separate instruction. The value hash + i + i * i is right
4720 // shifted in the following and instruction.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004721 ASSERT(NameDictionary::GetProbeOffset(i) <
4722 1 << (32 - Name::kHashFieldOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004723 __ Addu(scratch2, scratch2, Operand(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004724 NameDictionary::GetProbeOffset(i) << Name::kHashShift));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004725 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004726 __ srl(scratch2, scratch2, Name::kHashShift);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004727 __ And(scratch2, scratch1, scratch2);
4728
4729 // Scale the index by multiplying by the element size.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004730 ASSERT(NameDictionary::kEntrySize == 3);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004731 // scratch2 = scratch2 * 3.
4732
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004733 __ sll(at, scratch2, 1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004734 __ Addu(scratch2, scratch2, at);
4735
4736 // Check if the key is identical to the name.
4737 __ sll(at, scratch2, 2);
4738 __ Addu(scratch2, elements, at);
4739 __ lw(at, FieldMemOperand(scratch2, kElementsStartOffset));
4740 __ Branch(done, eq, name, Operand(at));
4741 }
4742
4743 const int spill_mask =
4744 (ra.bit() | t2.bit() | t1.bit() | t0.bit() |
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004745 a3.bit() | a2.bit() | a1.bit() | a0.bit() | v0.bit()) &
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004746 ~(scratch1.bit() | scratch2.bit());
4747
4748 __ MultiPush(spill_mask);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004749 if (name.is(a0)) {
4750 ASSERT(!elements.is(a1));
4751 __ Move(a1, name);
4752 __ Move(a0, elements);
4753 } else {
4754 __ Move(a0, elements);
4755 __ Move(a1, name);
4756 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004757 NameDictionaryLookupStub stub(POSITIVE_LOOKUP);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004758 __ CallStub(&stub);
4759 __ mov(scratch2, a2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004760 __ mov(at, v0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004761 __ MultiPop(spill_mask);
4762
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004763 __ Branch(done, ne, at, Operand(zero_reg));
4764 __ Branch(miss, eq, at, Operand(zero_reg));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004765}
4766
4767
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004768void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004769 // This stub overrides SometimesSetsUpAFrame() to return false. That means
4770 // we cannot call anything that could cause a GC from this stub.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004771 // Registers:
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004772 // result: NameDictionary to probe
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004773 // a1: key
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004774 // dictionary: NameDictionary to probe.
4775 // index: will hold an index of entry if lookup is successful.
4776 // might alias with result_.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004777 // Returns:
4778 // result_ is zero if lookup failed, non zero otherwise.
4779
4780 Register result = v0;
4781 Register dictionary = a0;
4782 Register key = a1;
4783 Register index = a2;
4784 Register mask = a3;
4785 Register hash = t0;
4786 Register undefined = t1;
4787 Register entry_key = t2;
4788
4789 Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
4790
4791 __ lw(mask, FieldMemOperand(dictionary, kCapacityOffset));
4792 __ sra(mask, mask, kSmiTagSize);
4793 __ Subu(mask, mask, Operand(1));
4794
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004795 __ lw(hash, FieldMemOperand(key, Name::kHashFieldOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004796
4797 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
4798
4799 for (int i = kInlinedProbes; i < kTotalProbes; i++) {
4800 // Compute the masked index: (hash + i + i * i) & mask.
4801 // Capacity is smi 2^n.
4802 if (i > 0) {
4803 // Add the probe offset (i + i * i) left shifted to avoid right shifting
4804 // the hash in a separate instruction. The value hash + i + i * i is right
4805 // shifted in the following and instruction.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004806 ASSERT(NameDictionary::GetProbeOffset(i) <
4807 1 << (32 - Name::kHashFieldOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004808 __ Addu(index, hash, Operand(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004809 NameDictionary::GetProbeOffset(i) << Name::kHashShift));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004810 } else {
4811 __ mov(index, hash);
4812 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004813 __ srl(index, index, Name::kHashShift);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004814 __ And(index, mask, index);
4815
4816 // Scale the index by multiplying by the entry size.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004817 ASSERT(NameDictionary::kEntrySize == 3);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004818 // index *= 3.
4819 __ mov(at, index);
4820 __ sll(index, index, 1);
4821 __ Addu(index, index, at);
4822
4823
4824 ASSERT_EQ(kSmiTagSize, 1);
4825 __ sll(index, index, 2);
4826 __ Addu(index, index, dictionary);
4827 __ lw(entry_key, FieldMemOperand(index, kElementsStartOffset));
4828
4829 // Having undefined at this place means the name is not contained.
4830 __ Branch(&not_in_dictionary, eq, entry_key, Operand(undefined));
4831
4832 // Stop if found the property.
4833 __ Branch(&in_dictionary, eq, entry_key, Operand(key));
4834
4835 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004836 // Check if the entry name is not a unique name.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004837 __ lw(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
4838 __ lbu(entry_key,
4839 FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004840 __ JumpIfNotUniqueName(entry_key, &maybe_in_dictionary);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004841 }
4842 }
4843
4844 __ bind(&maybe_in_dictionary);
4845 // If we are doing negative lookup then probing failure should be
4846 // treated as a lookup success. For positive lookup probing failure
4847 // should be treated as lookup failure.
4848 if (mode_ == POSITIVE_LOOKUP) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004849 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004850 __ mov(result, zero_reg);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004851 }
4852
4853 __ bind(&in_dictionary);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004854 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004855 __ li(result, 1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004856
4857 __ bind(&not_in_dictionary);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004858 __ Ret(USE_DELAY_SLOT);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004859 __ mov(result, zero_reg);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004860}
4861
4862
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004863void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
4864 Isolate* isolate) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004865 StoreBufferOverflowStub stub1(kDontSaveFPRegs);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00004866 stub1.GetCode(isolate);
danno@chromium.orgbee51992013-07-10 14:57:15 +00004867 // Hydrogen code stubs need stub2 at snapshot time.
4868 StoreBufferOverflowStub stub2(kSaveFPRegs);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00004869 stub2.GetCode(isolate);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004870}
4871
4872
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004873bool CodeStub::CanUseFPRegisters() {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004874 return true; // FPU is a base requirement for V8.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004875}
4876
4877
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004878// Takes the input in 3 registers: address_ value_ and object_. A pointer to
4879// the value has just been written into the object, now this stub makes sure
4880// we keep the GC informed. The word in the object where the value has been
4881// written is in the address register.
4882void RecordWriteStub::Generate(MacroAssembler* masm) {
4883 Label skip_to_incremental_noncompacting;
4884 Label skip_to_incremental_compacting;
4885
4886 // The first two branch+nop instructions are generated with labels so as to
4887 // get the offset fixed up correctly by the bind(Label*) call. We patch it
4888 // back and forth between a "bne zero_reg, zero_reg, ..." (a nop in this
4889 // position) and the "beq zero_reg, zero_reg, ..." when we start and stop
4890 // incremental heap marking.
4891 // See RecordWriteStub::Patch for details.
4892 __ beq(zero_reg, zero_reg, &skip_to_incremental_noncompacting);
4893 __ nop();
4894 __ beq(zero_reg, zero_reg, &skip_to_incremental_compacting);
4895 __ nop();
4896
4897 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
4898 __ RememberedSetHelper(object_,
4899 address_,
4900 value_,
4901 save_fp_regs_mode_,
4902 MacroAssembler::kReturnAtEnd);
4903 }
4904 __ Ret();
4905
4906 __ bind(&skip_to_incremental_noncompacting);
4907 GenerateIncremental(masm, INCREMENTAL);
4908
4909 __ bind(&skip_to_incremental_compacting);
4910 GenerateIncremental(masm, INCREMENTAL_COMPACTION);
4911
4912 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
4913 // Will be checked in IncrementalMarking::ActivateGeneratedStub.
4914
4915 PatchBranchIntoNop(masm, 0);
4916 PatchBranchIntoNop(masm, 2 * Assembler::kInstrSize);
4917}
4918
4919
4920void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
4921 regs_.Save(masm);
4922
4923 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
4924 Label dont_need_remembered_set;
4925
4926 __ lw(regs_.scratch0(), MemOperand(regs_.address(), 0));
4927 __ JumpIfNotInNewSpace(regs_.scratch0(), // Value.
4928 regs_.scratch0(),
4929 &dont_need_remembered_set);
4930
4931 __ CheckPageFlag(regs_.object(),
4932 regs_.scratch0(),
4933 1 << MemoryChunk::SCAN_ON_SCAVENGE,
4934 ne,
4935 &dont_need_remembered_set);
4936
4937 // First notify the incremental marker if necessary, then update the
4938 // remembered set.
4939 CheckNeedsToInformIncrementalMarker(
4940 masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004941 InformIncrementalMarker(masm);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004942 regs_.Restore(masm);
4943 __ RememberedSetHelper(object_,
4944 address_,
4945 value_,
4946 save_fp_regs_mode_,
4947 MacroAssembler::kReturnAtEnd);
4948
4949 __ bind(&dont_need_remembered_set);
4950 }
4951
4952 CheckNeedsToInformIncrementalMarker(
4953 masm, kReturnOnNoNeedToInformIncrementalMarker, mode);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004954 InformIncrementalMarker(masm);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004955 regs_.Restore(masm);
4956 __ Ret();
4957}
4958
4959
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004960void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004961 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_);
4962 int argument_count = 3;
4963 __ PrepareCallCFunction(argument_count, regs_.scratch0());
4964 Register address =
4965 a0.is(regs_.address()) ? regs_.scratch0() : regs_.address();
4966 ASSERT(!address.is(regs_.object()));
4967 ASSERT(!address.is(a0));
4968 __ Move(address, regs_.address());
4969 __ Move(a0, regs_.object());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004970 __ Move(a1, address);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004971 __ li(a2, Operand(ExternalReference::isolate_address(masm->isolate())));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004972
4973 AllowExternalCallThatCantCauseGC scope(masm);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004974 __ CallCFunction(
4975 ExternalReference::incremental_marking_record_write_function(
4976 masm->isolate()),
4977 argument_count);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004978 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_);
4979}
4980
4981
4982void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
4983 MacroAssembler* masm,
4984 OnNoNeedToInformIncrementalMarker on_no_need,
4985 Mode mode) {
4986 Label on_black;
4987 Label need_incremental;
4988 Label need_incremental_pop_scratch;
4989
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004990 __ And(regs_.scratch0(), regs_.object(), Operand(~Page::kPageAlignmentMask));
4991 __ lw(regs_.scratch1(),
4992 MemOperand(regs_.scratch0(),
4993 MemoryChunk::kWriteBarrierCounterOffset));
4994 __ Subu(regs_.scratch1(), regs_.scratch1(), Operand(1));
4995 __ sw(regs_.scratch1(),
4996 MemOperand(regs_.scratch0(),
4997 MemoryChunk::kWriteBarrierCounterOffset));
4998 __ Branch(&need_incremental, lt, regs_.scratch1(), Operand(zero_reg));
4999
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00005000 // Let's look at the color of the object: If it is not black we don't have
5001 // to inform the incremental marker.
5002 __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black);
5003
5004 regs_.Restore(masm);
5005 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
5006 __ RememberedSetHelper(object_,
5007 address_,
5008 value_,
5009 save_fp_regs_mode_,
5010 MacroAssembler::kReturnAtEnd);
5011 } else {
5012 __ Ret();
5013 }
5014
5015 __ bind(&on_black);
5016
5017 // Get the value from the slot.
5018 __ lw(regs_.scratch0(), MemOperand(regs_.address(), 0));
5019
5020 if (mode == INCREMENTAL_COMPACTION) {
5021 Label ensure_not_white;
5022
5023 __ CheckPageFlag(regs_.scratch0(), // Contains value.
5024 regs_.scratch1(), // Scratch.
5025 MemoryChunk::kEvacuationCandidateMask,
5026 eq,
5027 &ensure_not_white);
5028
5029 __ CheckPageFlag(regs_.object(),
5030 regs_.scratch1(), // Scratch.
5031 MemoryChunk::kSkipEvacuationSlotsRecordingMask,
5032 eq,
5033 &need_incremental);
5034
5035 __ bind(&ensure_not_white);
5036 }
5037
5038 // We need extra registers for this, so we push the object and the address
5039 // register temporarily.
5040 __ Push(regs_.object(), regs_.address());
5041 __ EnsureNotWhite(regs_.scratch0(), // The value.
5042 regs_.scratch1(), // Scratch.
5043 regs_.object(), // Scratch.
5044 regs_.address(), // Scratch.
5045 &need_incremental_pop_scratch);
5046 __ Pop(regs_.object(), regs_.address());
5047
5048 regs_.Restore(masm);
5049 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
5050 __ RememberedSetHelper(object_,
5051 address_,
5052 value_,
5053 save_fp_regs_mode_,
5054 MacroAssembler::kReturnAtEnd);
5055 } else {
5056 __ Ret();
5057 }
5058
5059 __ bind(&need_incremental_pop_scratch);
5060 __ Pop(regs_.object(), regs_.address());
5061
5062 __ bind(&need_incremental);
5063
5064 // Fall through when we need to inform the incremental marker.
5065}
5066
5067
erikcorry0ad885c2011-11-21 13:51:57 +00005068void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
5069 // ----------- S t a t e -------------
5070 // -- a0 : element value to store
erikcorry0ad885c2011-11-21 13:51:57 +00005071 // -- a3 : element index as smi
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005072 // -- sp[0] : array literal index in function as smi
5073 // -- sp[4] : array literal
5074 // clobbers a1, a2, t0
erikcorry0ad885c2011-11-21 13:51:57 +00005075 // -----------------------------------
5076
5077 Label element_done;
5078 Label double_elements;
5079 Label smi_element;
5080 Label slow_elements;
5081 Label fast_elements;
5082
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005083 // Get array literal index, array literal and its map.
5084 __ lw(t0, MemOperand(sp, 0 * kPointerSize));
5085 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
5086 __ lw(a2, FieldMemOperand(a1, JSObject::kMapOffset));
5087
erikcorry0ad885c2011-11-21 13:51:57 +00005088 __ CheckFastElements(a2, t1, &double_elements);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005089 // Check for FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS elements
erikcorry0ad885c2011-11-21 13:51:57 +00005090 __ JumpIfSmi(a0, &smi_element);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005091 __ CheckFastSmiElements(a2, t1, &fast_elements);
erikcorry0ad885c2011-11-21 13:51:57 +00005092
5093 // Store into the array literal requires a elements transition. Call into
5094 // the runtime.
5095 __ bind(&slow_elements);
5096 // call.
5097 __ Push(a1, a3, a0);
5098 __ lw(t1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
5099 __ lw(t1, FieldMemOperand(t1, JSFunction::kLiteralsOffset));
5100 __ Push(t1, t0);
5101 __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
5102
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005103 // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
erikcorry0ad885c2011-11-21 13:51:57 +00005104 __ bind(&fast_elements);
5105 __ lw(t1, FieldMemOperand(a1, JSObject::kElementsOffset));
5106 __ sll(t2, a3, kPointerSizeLog2 - kSmiTagSize);
5107 __ Addu(t2, t1, t2);
5108 __ Addu(t2, t2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
5109 __ sw(a0, MemOperand(t2, 0));
5110 // Update the write barrier for the array store.
5111 __ RecordWrite(t1, t2, a0, kRAHasNotBeenSaved, kDontSaveFPRegs,
5112 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005113 __ Ret(USE_DELAY_SLOT);
5114 __ mov(v0, a0);
erikcorry0ad885c2011-11-21 13:51:57 +00005115
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005116 // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
5117 // and value is Smi.
erikcorry0ad885c2011-11-21 13:51:57 +00005118 __ bind(&smi_element);
5119 __ lw(t1, FieldMemOperand(a1, JSObject::kElementsOffset));
5120 __ sll(t2, a3, kPointerSizeLog2 - kSmiTagSize);
5121 __ Addu(t2, t1, t2);
5122 __ sw(a0, FieldMemOperand(t2, FixedArray::kHeaderSize));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005123 __ Ret(USE_DELAY_SLOT);
5124 __ mov(v0, a0);
erikcorry0ad885c2011-11-21 13:51:57 +00005125
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005126 // Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS.
erikcorry0ad885c2011-11-21 13:51:57 +00005127 __ bind(&double_elements);
5128 __ lw(t1, FieldMemOperand(a1, JSObject::kElementsOffset));
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005129 __ StoreNumberToDoubleElements(a0, a3, t1, t3, t5, a2, &slow_elements);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005130 __ Ret(USE_DELAY_SLOT);
5131 __ mov(v0, a0);
erikcorry0ad885c2011-11-21 13:51:57 +00005132}
5133
5134
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00005135void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005136 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005137 __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005138 int parameter_count_offset =
5139 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
5140 __ lw(a1, MemOperand(fp, parameter_count_offset));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005141 if (function_mode_ == JS_FUNCTION_STUB_MODE) {
5142 __ Addu(a1, a1, Operand(1));
5143 }
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00005144 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005145 __ sll(a1, a1, kPointerSizeLog2);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00005146 __ Ret(USE_DELAY_SLOT);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005147 __ Addu(sp, sp, a1);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00005148}
5149
5150
danno@chromium.org129d3982012-07-25 15:01:47 +00005151void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00005152 if (masm->isolate()->function_entry_hook() != NULL) {
danno@chromium.org129d3982012-07-25 15:01:47 +00005153 ProfileEntryHookStub stub;
5154 __ push(ra);
5155 __ CallStub(&stub);
5156 __ pop(ra);
5157 }
5158}
5159
5160
5161void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
5162 // The entry hook is a "push ra" instruction, followed by a call.
5163 // Note: on MIPS "push" is 2 instruction
5164 const int32_t kReturnAddressDistanceFromFunctionStart =
5165 Assembler::kCallTargetAddressOffset + (2 * Assembler::kInstrSize);
5166
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00005167 // This should contain all kJSCallerSaved registers.
5168 const RegList kSavedRegs =
5169 kJSCallerSaved | // Caller saved registers.
5170 s5.bit(); // Saved stack pointer.
5171
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00005172 // We also save ra, so the count here is one higher than the mask indicates.
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00005173 const int32_t kNumSavedRegs = kNumJSCallerSaved + 2;
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00005174
5175 // Save all caller-save registers as this may be called from anywhere.
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00005176 __ MultiPush(kSavedRegs | ra.bit());
danno@chromium.org129d3982012-07-25 15:01:47 +00005177
5178 // Compute the function's address for the first argument.
5179 __ Subu(a0, ra, Operand(kReturnAddressDistanceFromFunctionStart));
5180
5181 // The caller's return address is above the saved temporaries.
5182 // Grab that for the second argument to the hook.
5183 __ Addu(a1, sp, Operand(kNumSavedRegs * kPointerSize));
5184
5185 // Align the stack if necessary.
5186 int frame_alignment = masm->ActivationFrameAlignment();
5187 if (frame_alignment > kPointerSize) {
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00005188 __ mov(s5, sp);
danno@chromium.org129d3982012-07-25 15:01:47 +00005189 ASSERT(IsPowerOf2(frame_alignment));
5190 __ And(sp, sp, Operand(-frame_alignment));
5191 }
machenbach@chromium.org82975302014-02-06 01:06:18 +00005192 __ Subu(sp, sp, kCArgsSlotsSize);
danno@chromium.org129d3982012-07-25 15:01:47 +00005193#if defined(V8_HOST_ARCH_MIPS)
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00005194 int32_t entry_hook =
5195 reinterpret_cast<int32_t>(masm->isolate()->function_entry_hook());
machenbach@chromium.org82975302014-02-06 01:06:18 +00005196 __ li(t9, Operand(entry_hook));
danno@chromium.org129d3982012-07-25 15:01:47 +00005197#else
5198 // Under the simulator we need to indirect the entry hook through a
5199 // trampoline function at a known address.
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00005200 // It additionally takes an isolate as a third parameter.
5201 __ li(a2, Operand(ExternalReference::isolate_address(masm->isolate())));
5202
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00005203 ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline));
machenbach@chromium.org82975302014-02-06 01:06:18 +00005204 __ li(t9, Operand(ExternalReference(&dispatcher,
danno@chromium.org129d3982012-07-25 15:01:47 +00005205 ExternalReference::BUILTIN_CALL,
5206 masm->isolate())));
5207#endif
machenbach@chromium.org82975302014-02-06 01:06:18 +00005208 // Call C function through t9 to conform ABI for PIC.
5209 __ Call(t9);
danno@chromium.org129d3982012-07-25 15:01:47 +00005210
5211 // Restore the stack pointer if needed.
5212 if (frame_alignment > kPointerSize) {
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00005213 __ mov(sp, s5);
machenbach@chromium.org82975302014-02-06 01:06:18 +00005214 } else {
5215 __ Addu(sp, sp, kCArgsSlotsSize);
danno@chromium.org129d3982012-07-25 15:01:47 +00005216 }
5217
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00005218 // Also pop ra to get Ret(0).
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00005219 __ MultiPop(kSavedRegs | ra.bit());
danno@chromium.org129d3982012-07-25 15:01:47 +00005220 __ Ret();
5221}
5222
5223
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005224template<class T>
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005225static void CreateArrayDispatch(MacroAssembler* masm,
5226 AllocationSiteOverrideMode mode) {
5227 if (mode == DISABLE_ALLOCATION_SITES) {
machenbach@chromium.org03453962014-01-10 14:16:31 +00005228 T stub(GetInitialFastElementsKind(), mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005229 __ TailCallStub(&stub);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005230 } else if (mode == DONT_OVERRIDE) {
5231 int last_index = GetSequenceIndexFromFastElementsKind(
5232 TERMINAL_FAST_ELEMENTS_KIND);
5233 for (int i = 0; i <= last_index; ++i) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005234 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005235 T stub(kind);
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005236 __ TailCallStub(&stub, eq, a3, Operand(kind));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005237 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005238
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005239 // If we reached this point there is a problem.
5240 __ Abort(kUnexpectedElementsKindInArrayConstructor);
5241 } else {
5242 UNREACHABLE();
5243 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005244}
5245
5246
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005247static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
5248 AllocationSiteOverrideMode mode) {
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005249 // a2 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005250 // a3 - kind (if mode != DISABLE_ALLOCATION_SITES)
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005251 // a0 - number of arguments
5252 // a1 - constructor?
5253 // sp[0] - last argument
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005254 Label normal_sequence;
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005255 if (mode == DONT_OVERRIDE) {
5256 ASSERT(FAST_SMI_ELEMENTS == 0);
5257 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
5258 ASSERT(FAST_ELEMENTS == 2);
5259 ASSERT(FAST_HOLEY_ELEMENTS == 3);
5260 ASSERT(FAST_DOUBLE_ELEMENTS == 4);
5261 ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
5262
5263 // is the low bit set? If so, we are holey and that is good.
5264 __ And(at, a3, Operand(1));
5265 __ Branch(&normal_sequence, ne, at, Operand(zero_reg));
5266 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005267
5268 // look at the first argument
5269 __ lw(t1, MemOperand(sp, 0));
5270 __ Branch(&normal_sequence, eq, t1, Operand(zero_reg));
5271
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005272 if (mode == DISABLE_ALLOCATION_SITES) {
5273 ElementsKind initial = GetInitialFastElementsKind();
5274 ElementsKind holey_initial = GetHoleyElementsKind(initial);
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00005275
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005276 ArraySingleArgumentConstructorStub stub_holey(holey_initial,
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005277 DISABLE_ALLOCATION_SITES);
5278 __ TailCallStub(&stub_holey);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005279
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005280 __ bind(&normal_sequence);
5281 ArraySingleArgumentConstructorStub stub(initial,
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005282 DISABLE_ALLOCATION_SITES);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005283 __ TailCallStub(&stub);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005284 } else if (mode == DONT_OVERRIDE) {
5285 // We are going to create a holey array, but our kind is non-holey.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00005286 // Fix kind and retry (only if we have an allocation site in the slot).
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005287 __ Addu(a3, a3, Operand(1));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005288
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005289 if (FLAG_debug_code) {
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005290 __ lw(t1, FieldMemOperand(a2, 0));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005291 __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005292 __ Assert(eq, kExpectedAllocationSite, t1, Operand(at));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005293 }
5294
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005295 // Save the resulting elements kind in type info. We can't just store a3
5296 // in the AllocationSite::transition_info field because elements kind is
5297 // restricted to a portion of the field...upper bits need to be left alone.
5298 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005299 __ lw(t0, FieldMemOperand(a2, AllocationSite::kTransitionInfoOffset));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005300 __ Addu(t0, t0, Operand(Smi::FromInt(kFastElementsKindPackedToHoley)));
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005301 __ sw(t0, FieldMemOperand(a2, AllocationSite::kTransitionInfoOffset));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005302
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005303
5304 __ bind(&normal_sequence);
5305 int last_index = GetSequenceIndexFromFastElementsKind(
5306 TERMINAL_FAST_ELEMENTS_KIND);
5307 for (int i = 0; i <= last_index; ++i) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005308 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005309 ArraySingleArgumentConstructorStub stub(kind);
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005310 __ TailCallStub(&stub, eq, a3, Operand(kind));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005311 }
5312
5313 // If we reached this point there is a problem.
5314 __ Abort(kUnexpectedElementsKindInArrayConstructor);
5315 } else {
5316 UNREACHABLE();
5317 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005318}
5319
5320
5321template<class T>
5322static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
5323 int to_index = GetSequenceIndexFromFastElementsKind(
5324 TERMINAL_FAST_ELEMENTS_KIND);
5325 for (int i = 0; i <= to_index; ++i) {
5326 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
5327 T stub(kind);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00005328 stub.GetCode(isolate);
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00005329 if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
machenbach@chromium.org03453962014-01-10 14:16:31 +00005330 T stub1(kind, DISABLE_ALLOCATION_SITES);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00005331 stub1.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005332 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005333 }
5334}
5335
5336
5337void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) {
5338 ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
5339 isolate);
5340 ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
5341 isolate);
5342 ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
5343 isolate);
5344}
5345
5346
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005347void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(
5348 Isolate* isolate) {
5349 ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS };
5350 for (int i = 0; i < 2; i++) {
5351 // For internal arrays we only need a few things.
5352 InternalArrayNoArgumentConstructorStub stubh1(kinds[i]);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00005353 stubh1.GetCode(isolate);
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005354 InternalArraySingleArgumentConstructorStub stubh2(kinds[i]);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00005355 stubh2.GetCode(isolate);
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005356 InternalArrayNArgumentsConstructorStub stubh3(kinds[i]);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00005357 stubh3.GetCode(isolate);
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005358 }
5359}
5360
5361
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005362void ArrayConstructorStub::GenerateDispatchToArrayStub(
5363 MacroAssembler* masm,
5364 AllocationSiteOverrideMode mode) {
5365 if (argument_count_ == ANY) {
5366 Label not_zero_case, not_one_case;
5367 __ And(at, a0, a0);
5368 __ Branch(&not_zero_case, ne, at, Operand(zero_reg));
5369 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
5370
5371 __ bind(&not_zero_case);
5372 __ Branch(&not_one_case, gt, a0, Operand(1));
5373 CreateArrayDispatchOneArgument(masm, mode);
5374
5375 __ bind(&not_one_case);
5376 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
5377 } else if (argument_count_ == NONE) {
5378 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
5379 } else if (argument_count_ == ONE) {
5380 CreateArrayDispatchOneArgument(masm, mode);
5381 } else if (argument_count_ == MORE_THAN_ONE) {
5382 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
5383 } else {
5384 UNREACHABLE();
5385 }
5386}
5387
5388
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005389void ArrayConstructorStub::Generate(MacroAssembler* masm) {
5390 // ----------- S t a t e -------------
5391 // -- a0 : argc (only if argument_count_ == ANY)
5392 // -- a1 : constructor
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00005393 // -- a2 : AllocationSite or undefined
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005394 // -- sp[0] : return address
5395 // -- sp[4] : last argument
5396 // -----------------------------------
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00005397
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005398 if (FLAG_debug_code) {
5399 // The array construct code is only set for the global and natives
5400 // builtin Array functions which always have maps.
5401
5402 // Initial map for the builtin Array function should be a map.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00005403 __ lw(t0, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005404 // Will both indicate a NULL and a Smi.
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00005405 __ SmiTst(t0, at);
danno@chromium.org59400602013-08-13 17:09:37 +00005406 __ Assert(ne, kUnexpectedInitialMapForArrayFunction,
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005407 at, Operand(zero_reg));
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00005408 __ GetObjectType(t0, t0, t1);
danno@chromium.org59400602013-08-13 17:09:37 +00005409 __ Assert(eq, kUnexpectedInitialMapForArrayFunction,
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00005410 t1, Operand(MAP_TYPE));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005411
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00005412 // We should either have undefined in a2 or a valid AllocationSite
5413 __ AssertUndefinedOrAllocationSite(a2, t0);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005414 }
5415
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005416 Label no_info;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005417 // Get the elements kind and case on that.
machenbach@chromium.org69f64b12014-03-20 01:04:55 +00005418 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
danno@chromium.orgbee51992013-07-10 14:57:15 +00005419 __ Branch(&no_info, eq, a2, Operand(at));
danno@chromium.orgbee51992013-07-10 14:57:15 +00005420
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005421 __ lw(a3, FieldMemOperand(a2, AllocationSite::kTransitionInfoOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005422 __ SmiUntag(a3);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005423 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
5424 __ And(a3, a3, Operand(AllocationSite::ElementsKindBits::kMask));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005425 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
5426
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005427 __ bind(&no_info);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005428 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005429}
5430
5431
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005432void InternalArrayConstructorStub::GenerateCase(
5433 MacroAssembler* masm, ElementsKind kind) {
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005434
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005435 InternalArrayNoArgumentConstructorStub stub0(kind);
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005436 __ TailCallStub(&stub0, lo, a0, Operand(1));
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005437
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005438 InternalArrayNArgumentsConstructorStub stubN(kind);
5439 __ TailCallStub(&stubN, hi, a0, Operand(1));
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005440
5441 if (IsFastPackedElementsKind(kind)) {
5442 // We might need to create a holey array
5443 // look at the first argument.
5444 __ lw(at, MemOperand(sp, 0));
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005445
5446 InternalArraySingleArgumentConstructorStub
5447 stub1_holey(GetHoleyElementsKind(kind));
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005448 __ TailCallStub(&stub1_holey, ne, at, Operand(zero_reg));
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005449 }
5450
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005451 InternalArraySingleArgumentConstructorStub stub1(kind);
5452 __ TailCallStub(&stub1);
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005453}
5454
5455
5456void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
5457 // ----------- S t a t e -------------
5458 // -- a0 : argc
5459 // -- a1 : constructor
5460 // -- sp[0] : return address
5461 // -- sp[4] : last argument
5462 // -----------------------------------
5463
5464 if (FLAG_debug_code) {
5465 // The array construct code is only set for the global and natives
5466 // builtin Array functions which always have maps.
5467
5468 // Initial map for the builtin Array function should be a map.
5469 __ lw(a3, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
5470 // Will both indicate a NULL and a Smi.
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00005471 __ SmiTst(a3, at);
danno@chromium.org59400602013-08-13 17:09:37 +00005472 __ Assert(ne, kUnexpectedInitialMapForArrayFunction,
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005473 at, Operand(zero_reg));
5474 __ GetObjectType(a3, a3, t0);
danno@chromium.org59400602013-08-13 17:09:37 +00005475 __ Assert(eq, kUnexpectedInitialMapForArrayFunction,
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005476 t0, Operand(MAP_TYPE));
5477 }
5478
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005479 // Figure out the right elements kind.
5480 __ lw(a3, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005481
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005482 // Load the map's "bit field 2" into a3. We only need the first byte,
5483 // but the following bit field extraction takes care of that anyway.
5484 __ lbu(a3, FieldMemOperand(a3, Map::kBitField2Offset));
5485 // Retrieve elements_kind from bit field 2.
5486 __ Ext(a3, a3, Map::kElementsKindShift, Map::kElementsKindBitCount);
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005487
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005488 if (FLAG_debug_code) {
5489 Label done;
5490 __ Branch(&done, eq, a3, Operand(FAST_ELEMENTS));
5491 __ Assert(
danno@chromium.org59400602013-08-13 17:09:37 +00005492 eq, kInvalidElementsKindForInternalArrayOrInternalPackedArray,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005493 a3, Operand(FAST_HOLEY_ELEMENTS));
5494 __ bind(&done);
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005495 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005496
5497 Label fast_elements_case;
5498 __ Branch(&fast_elements_case, eq, a3, Operand(FAST_ELEMENTS));
5499 GenerateCase(masm, FAST_HOLEY_ELEMENTS);
5500
5501 __ bind(&fast_elements_case);
5502 GenerateCase(masm, FAST_ELEMENTS);
palfia@homejinni.com46d4fbd2013-06-05 22:27:04 +00005503}
5504
5505
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +00005506void CallApiFunctionStub::Generate(MacroAssembler* masm) {
5507 // ----------- S t a t e -------------
5508 // -- a0 : callee
5509 // -- t0 : call_data
5510 // -- a2 : holder
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00005511 // -- a1 : api_function_address
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +00005512 // -- cp : context
5513 // --
5514 // -- sp[0] : last argument
5515 // -- ...
5516 // -- sp[(argc - 1)* 4] : first argument
5517 // -- sp[argc * 4] : receiver
5518 // -----------------------------------
5519
5520 Register callee = a0;
5521 Register call_data = t0;
5522 Register holder = a2;
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00005523 Register api_function_address = a1;
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +00005524 Register context = cp;
5525
5526 int argc = ArgumentBits::decode(bit_field_);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00005527 bool is_store = IsStoreBits::decode(bit_field_);
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +00005528 bool call_data_undefined = CallDataUndefinedBits::decode(bit_field_);
5529
5530 typedef FunctionCallbackArguments FCA;
5531
5532 STATIC_ASSERT(FCA::kContextSaveIndex == 6);
5533 STATIC_ASSERT(FCA::kCalleeIndex == 5);
5534 STATIC_ASSERT(FCA::kDataIndex == 4);
5535 STATIC_ASSERT(FCA::kReturnValueOffset == 3);
5536 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
5537 STATIC_ASSERT(FCA::kIsolateIndex == 1);
5538 STATIC_ASSERT(FCA::kHolderIndex == 0);
5539 STATIC_ASSERT(FCA::kArgsLength == 7);
5540
5541 Isolate* isolate = masm->isolate();
5542
5543 // Save context, callee and call data.
5544 __ Push(context, callee, call_data);
5545 // Load context from callee.
5546 __ lw(context, FieldMemOperand(callee, JSFunction::kContextOffset));
5547
5548 Register scratch = call_data;
5549 if (!call_data_undefined) {
5550 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
5551 }
5552 // Push return value and default return value.
5553 __ Push(scratch, scratch);
5554 __ li(scratch,
5555 Operand(ExternalReference::isolate_address(isolate)));
5556 // Push isolate and holder.
5557 __ Push(scratch, holder);
5558
5559 // Prepare arguments.
5560 __ mov(scratch, sp);
5561
5562 // Allocate the v8::Arguments structure in the arguments' space since
5563 // it's not controlled by GC.
5564 const int kApiStackSpace = 4;
5565
5566 FrameScope frame_scope(masm, StackFrame::MANUAL);
5567 __ EnterExitFrame(false, kApiStackSpace);
5568
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00005569 ASSERT(!api_function_address.is(a0) && !scratch.is(a0));
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +00005570 // a0 = FunctionCallbackInfo&
5571 // Arguments is after the return address.
5572 __ Addu(a0, sp, Operand(1 * kPointerSize));
5573 // FunctionCallbackInfo::implicit_args_
5574 __ sw(scratch, MemOperand(a0, 0 * kPointerSize));
5575 // FunctionCallbackInfo::values_
5576 __ Addu(at, scratch, Operand((FCA::kArgsLength - 1 + argc) * kPointerSize));
5577 __ sw(at, MemOperand(a0, 1 * kPointerSize));
5578 // FunctionCallbackInfo::length_ = argc
5579 __ li(at, Operand(argc));
5580 __ sw(at, MemOperand(a0, 2 * kPointerSize));
5581 // FunctionCallbackInfo::is_construct_call = 0
5582 __ sw(zero_reg, MemOperand(a0, 3 * kPointerSize));
5583
5584 const int kStackUnwindSpace = argc + FCA::kArgsLength + 1;
5585 Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
5586 ExternalReference::Type thunk_type = ExternalReference::PROFILING_API_CALL;
5587 ApiFunction thunk_fun(thunk_address);
5588 ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
5589 masm->isolate());
5590
5591 AllowExternalCallThatCantCauseGC scope(masm);
5592 MemOperand context_restore_operand(
5593 fp, (2 + FCA::kContextSaveIndex) * kPointerSize);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00005594 // Stores return the first js argument.
5595 int return_value_offset = 0;
5596 if (is_store) {
5597 return_value_offset = 2 + FCA::kArgsLength;
5598 } else {
5599 return_value_offset = 2 + FCA::kReturnValueOffset;
5600 }
5601 MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +00005602
5603 __ CallApiFunctionAndReturn(api_function_address,
5604 thunk_ref,
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +00005605 kStackUnwindSpace,
5606 return_value_operand,
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00005607 &context_restore_operand);
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +00005608}
5609
5610
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00005611void CallApiGetterStub::Generate(MacroAssembler* masm) {
5612 // ----------- S t a t e -------------
5613 // -- sp[0] : name
5614 // -- sp[4 - kArgsLength*4] : PropertyCallbackArguments object
5615 // -- ...
5616 // -- a2 : api_function_address
5617 // -----------------------------------
5618
5619 Register api_function_address = a2;
5620
5621 __ mov(a0, sp); // a0 = Handle<Name>
5622 __ Addu(a1, a0, Operand(1 * kPointerSize)); // a1 = PCA
5623
5624 const int kApiStackSpace = 1;
5625 FrameScope frame_scope(masm, StackFrame::MANUAL);
5626 __ EnterExitFrame(false, kApiStackSpace);
5627
5628 // Create PropertyAccessorInfo instance on the stack above the exit frame with
5629 // a1 (internal::Object** args_) as the data.
5630 __ sw(a1, MemOperand(sp, 1 * kPointerSize));
5631 __ Addu(a1, sp, Operand(1 * kPointerSize)); // a1 = AccessorInfo&
5632
5633 const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
5634
5635 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
5636 ExternalReference::Type thunk_type =
5637 ExternalReference::PROFILING_GETTER_CALL;
5638 ApiFunction thunk_fun(thunk_address);
5639 ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
5640 masm->isolate());
5641 __ CallApiFunctionAndReturn(api_function_address,
5642 thunk_ref,
5643 kStackUnwindSpace,
5644 MemOperand(fp, 6 * kPointerSize),
5645 NULL);
5646}
5647
5648
lrn@chromium.org7516f052011-03-30 08:52:27 +00005649#undef __
5650
5651} } // namespace v8::internal
5652
5653#endif // V8_TARGET_ARCH_MIPS