blob: 8af47b72a9c5914dd6d3077cf9c75a3e3c51d863 [file] [log] [blame]
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ricow@chromium.org65fae842010-08-25 15:26:24 +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_ARM
ricow@chromium.org65fae842010-08-25 15:26:24 +000031
32#include "bootstrapper.h"
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000033#include "code-stubs.h"
ricow@chromium.org65fae842010-08-25 15:26:24 +000034#include "regexp-macro-assembler.h"
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +000035#include "stub-cache.h"
ricow@chromium.org65fae842010-08-25 15:26:24 +000036
37namespace v8 {
38namespace internal {
39
40
verwaest@chromium.org662436e2013-08-28 08:41:27 +000041void FastNewClosureStub::InitializeInterfaceDescriptor(
42 Isolate* isolate,
43 CodeStubInterfaceDescriptor* descriptor) {
44 static Register registers[] = { r2 };
45 descriptor->register_param_count_ = 1;
46 descriptor->register_params_ = registers;
47 descriptor->deoptimization_handler_ =
48 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry;
49}
50
51
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +000052void ToNumberStub::InitializeInterfaceDescriptor(
53 Isolate* isolate,
54 CodeStubInterfaceDescriptor* descriptor) {
55 static Register registers[] = { r0 };
56 descriptor->register_param_count_ = 1;
57 descriptor->register_params_ = registers;
58 descriptor->deoptimization_handler_ = NULL;
59}
60
61
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +000062void NumberToStringStub::InitializeInterfaceDescriptor(
63 Isolate* isolate,
64 CodeStubInterfaceDescriptor* descriptor) {
65 static Register registers[] = { r0 };
66 descriptor->register_param_count_ = 1;
67 descriptor->register_params_ = registers;
bmeurer@chromium.orge7a07452013-10-21 13:27:29 +000068 descriptor->deoptimization_handler_ =
69 Runtime::FunctionForId(Runtime::kNumberToString)->entry;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +000070}
71
72
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000073void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
74 Isolate* isolate,
75 CodeStubInterfaceDescriptor* descriptor) {
76 static Register registers[] = { r3, r2, r1 };
77 descriptor->register_param_count_ = 3;
78 descriptor->register_params_ = registers;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000079 descriptor->deoptimization_handler_ =
machenbach@chromium.org37be4082013-11-26 13:50:38 +000080 Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000081}
82
83
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000084void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
85 Isolate* isolate,
86 CodeStubInterfaceDescriptor* descriptor) {
87 static Register registers[] = { r3, r2, r1, r0 };
88 descriptor->register_param_count_ = 4;
89 descriptor->register_params_ = registers;
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000090 descriptor->deoptimization_handler_ =
machenbach@chromium.org528ce022013-09-23 14:09:36 +000091 Runtime::FunctionForId(Runtime::kCreateObjectLiteral)->entry;
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000092}
93
94
danno@chromium.orgbee51992013-07-10 14:57:15 +000095void CreateAllocationSiteStub::InitializeInterfaceDescriptor(
96 Isolate* isolate,
97 CodeStubInterfaceDescriptor* descriptor) {
98 static Register registers[] = { r2 };
99 descriptor->register_param_count_ = 1;
100 descriptor->register_params_ = registers;
101 descriptor->deoptimization_handler_ = NULL;
102}
103
104
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000105void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
106 Isolate* isolate,
107 CodeStubInterfaceDescriptor* descriptor) {
108 static Register registers[] = { r1, r0 };
109 descriptor->register_param_count_ = 2;
110 descriptor->register_params_ = registers;
111 descriptor->deoptimization_handler_ =
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000112 FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000113}
114
115
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000116void KeyedLoadDictionaryElementStub::InitializeInterfaceDescriptor(
117 Isolate* isolate,
118 CodeStubInterfaceDescriptor* descriptor) {
119 static Register registers[] = { r1, r0 };
120 descriptor->register_param_count_ = 2;
121 descriptor->register_params_ = registers;
122 descriptor->deoptimization_handler_ =
123 FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
124}
125
126
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000127void LoadFieldStub::InitializeInterfaceDescriptor(
128 Isolate* isolate,
129 CodeStubInterfaceDescriptor* descriptor) {
130 static Register registers[] = { r0 };
131 descriptor->register_param_count_ = 1;
132 descriptor->register_params_ = registers;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000133 descriptor->deoptimization_handler_ = NULL;
134}
135
136
137void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
138 Isolate* isolate,
139 CodeStubInterfaceDescriptor* descriptor) {
140 static Register registers[] = { r1 };
141 descriptor->register_param_count_ = 1;
142 descriptor->register_params_ = registers;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000143 descriptor->deoptimization_handler_ = NULL;
144}
145
146
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000147void KeyedArrayCallStub::InitializeInterfaceDescriptor(
148 Isolate* isolate,
149 CodeStubInterfaceDescriptor* descriptor) {
150 static Register registers[] = { r2 };
151 descriptor->register_param_count_ = 1;
152 descriptor->register_params_ = registers;
153 descriptor->continuation_type_ = TAIL_CALL_CONTINUATION;
154 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
155 descriptor->deoptimization_handler_ =
156 FUNCTION_ADDR(KeyedCallIC_MissFromStubFailure);
157}
158
159
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000160void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
161 Isolate* isolate,
162 CodeStubInterfaceDescriptor* descriptor) {
163 static Register registers[] = { r2, r1, r0 };
164 descriptor->register_param_count_ = 3;
165 descriptor->register_params_ = registers;
166 descriptor->deoptimization_handler_ =
167 FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure);
168}
169
170
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000171void TransitionElementsKindStub::InitializeInterfaceDescriptor(
172 Isolate* isolate,
173 CodeStubInterfaceDescriptor* descriptor) {
174 static Register registers[] = { r0, r1 };
175 descriptor->register_param_count_ = 2;
176 descriptor->register_params_ = registers;
177 Address entry =
178 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry;
179 descriptor->deoptimization_handler_ = FUNCTION_ADDR(entry);
180}
181
182
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000183void CompareNilICStub::InitializeInterfaceDescriptor(
184 Isolate* isolate,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000185 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000186 static Register registers[] = { r0 };
187 descriptor->register_param_count_ = 1;
188 descriptor->register_params_ = registers;
189 descriptor->deoptimization_handler_ =
190 FUNCTION_ADDR(CompareNilIC_Miss);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000191 descriptor->SetMissHandler(
192 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate));
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000193}
194
195
196static void InitializeArrayConstructorDescriptor(
197 Isolate* isolate,
198 CodeStubInterfaceDescriptor* descriptor,
199 int constant_stack_parameter_count) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000200 // register state
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000201 // r0 -- number of arguments
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000202 // r1 -- function
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000203 // r2 -- type info cell with elements kind
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000204 static Register registers_variable_args[] = { r1, r2, r0 };
205 static Register registers_no_args[] = { r1, r2 };
206
207 if (constant_stack_parameter_count == 0) {
208 descriptor->register_param_count_ = 2;
209 descriptor->register_params_ = registers_no_args;
210 } else {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000211 // stack param count needs (constructor pointer, and single argument)
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000212 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000213 descriptor->stack_parameter_count_ = r0;
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000214 descriptor->register_param_count_ = 3;
215 descriptor->register_params_ = registers_variable_args;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000216 }
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000217
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000218 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000219 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000220 descriptor->deoptimization_handler_ =
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000221 Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000222}
223
224
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000225static void InitializeInternalArrayConstructorDescriptor(
226 Isolate* isolate,
227 CodeStubInterfaceDescriptor* descriptor,
228 int constant_stack_parameter_count) {
229 // register state
230 // r0 -- number of arguments
231 // r1 -- constructor function
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000232 static Register registers_variable_args[] = { r1, r0 };
233 static Register registers_no_args[] = { r1 };
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000234
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000235 if (constant_stack_parameter_count == 0) {
236 descriptor->register_param_count_ = 1;
237 descriptor->register_params_ = registers_no_args;
238 } else {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000239 // stack param count needs (constructor pointer, and single argument)
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000240 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000241 descriptor->stack_parameter_count_ = r0;
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000242 descriptor->register_param_count_ = 2;
243 descriptor->register_params_ = registers_variable_args;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000244 }
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000245
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000246 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000247 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
248 descriptor->deoptimization_handler_ =
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000249 Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000250}
251
252
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000253void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
254 Isolate* isolate,
255 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000256 InitializeArrayConstructorDescriptor(isolate, descriptor, 0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000257}
258
259
260void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
261 Isolate* isolate,
262 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000263 InitializeArrayConstructorDescriptor(isolate, descriptor, 1);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000264}
265
266
267void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
268 Isolate* isolate,
269 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000270 InitializeArrayConstructorDescriptor(isolate, descriptor, -1);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000271}
272
273
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000274void ToBooleanStub::InitializeInterfaceDescriptor(
275 Isolate* isolate,
276 CodeStubInterfaceDescriptor* descriptor) {
277 static Register registers[] = { r0 };
278 descriptor->register_param_count_ = 1;
279 descriptor->register_params_ = registers;
280 descriptor->deoptimization_handler_ =
281 FUNCTION_ADDR(ToBooleanIC_Miss);
282 descriptor->SetMissHandler(
283 ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate));
284}
285
286
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000287void InternalArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
288 Isolate* isolate,
289 CodeStubInterfaceDescriptor* descriptor) {
290 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 0);
291}
292
293
294void InternalArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
295 Isolate* isolate,
296 CodeStubInterfaceDescriptor* descriptor) {
297 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 1);
298}
299
300
301void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
302 Isolate* isolate,
303 CodeStubInterfaceDescriptor* descriptor) {
304 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1);
305}
306
307
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000308void StoreGlobalStub::InitializeInterfaceDescriptor(
309 Isolate* isolate,
310 CodeStubInterfaceDescriptor* descriptor) {
311 static Register registers[] = { r1, r2, r0 };
312 descriptor->register_param_count_ = 3;
313 descriptor->register_params_ = registers;
314 descriptor->deoptimization_handler_ =
315 FUNCTION_ADDR(StoreIC_MissFromStubFailure);
316}
317
318
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000319void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
320 Isolate* isolate,
321 CodeStubInterfaceDescriptor* descriptor) {
322 static Register registers[] = { r0, r3, r1, r2 };
323 descriptor->register_param_count_ = 4;
324 descriptor->register_params_ = registers;
325 descriptor->deoptimization_handler_ =
326 FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss);
327}
328
329
ulan@chromium.org0f13e742014-01-03 15:51:11 +0000330void BinaryOpICStub::InitializeInterfaceDescriptor(
331 Isolate* isolate,
332 CodeStubInterfaceDescriptor* descriptor) {
333 static Register registers[] = { r1, r0 };
334 descriptor->register_param_count_ = 2;
335 descriptor->register_params_ = registers;
336 descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss);
337 descriptor->SetMissHandler(
338 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
339}
340
341
342void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor(
343 Isolate* isolate,
344 CodeStubInterfaceDescriptor* descriptor) {
345 static Register registers[] = { r2, r1, r0 };
346 descriptor->register_param_count_ = 3;
347 descriptor->register_params_ = registers;
348 descriptor->deoptimization_handler_ =
349 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite);
350}
351
352
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000353void NewStringAddStub::InitializeInterfaceDescriptor(
354 Isolate* isolate,
355 CodeStubInterfaceDescriptor* descriptor) {
356 static Register registers[] = { r1, r0 };
357 descriptor->register_param_count_ = 2;
358 descriptor->register_params_ = registers;
359 descriptor->deoptimization_handler_ =
360 Runtime::FunctionForId(Runtime::kStringAdd)->entry;
361}
362
363
ricow@chromium.org65fae842010-08-25 15:26:24 +0000364#define __ ACCESS_MASM(masm)
365
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000366
ricow@chromium.org65fae842010-08-25 15:26:24 +0000367static void EmitIdenticalObjectComparison(MacroAssembler* masm,
368 Label* slow,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000369 Condition cond);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000370static void EmitSmiNonsmiComparison(MacroAssembler* masm,
371 Register lhs,
372 Register rhs,
373 Label* lhs_not_nan,
374 Label* slow,
375 bool strict);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000376static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
377 Register lhs,
378 Register rhs);
379
380
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000381void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) {
382 // Update the static counter each time a new code stub is generated.
383 Isolate* isolate = masm->isolate();
384 isolate->counters()->code_stubs()->Increment();
385
386 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate);
387 int param_count = descriptor->register_param_count_;
388 {
389 // Call the runtime system in a fresh internal frame.
390 FrameScope scope(masm, StackFrame::INTERNAL);
391 ASSERT(descriptor->register_param_count_ == 0 ||
392 r0.is(descriptor->register_params_[param_count - 1]));
393 // Push arguments
394 for (int i = 0; i < param_count; ++i) {
395 __ push(descriptor->register_params_[i]);
396 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000397 ExternalReference miss = descriptor->miss_handler();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000398 __ CallExternalReference(miss, descriptor->register_param_count_);
399 }
400
401 __ Ret();
402}
403
404
ricow@chromium.org65fae842010-08-25 15:26:24 +0000405void FastNewContextStub::Generate(MacroAssembler* masm) {
406 // Try to allocate the context in new space.
407 Label gc;
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000408 int length = slots_ + Context::MIN_CONTEXT_SLOTS;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000409
410 // Attempt to allocate the context in new space.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000411 __ Allocate(FixedArray::SizeFor(length), r0, r1, r2, &gc, TAG_OBJECT);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000412
413 // Load the function from the stack.
414 __ ldr(r3, MemOperand(sp, 0));
415
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000416 // Set up the object header.
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000417 __ LoadRoot(r1, Heap::kFunctionContextMapRootIndex);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000418 __ mov(r2, Operand(Smi::FromInt(length)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000419 __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000420 __ str(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000421
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000422 // Set up the fixed slots, copy the global object from the previous context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000423 __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000424 __ mov(r1, Operand(Smi::FromInt(0)));
425 __ str(r3, MemOperand(r0, Context::SlotOffset(Context::CLOSURE_INDEX)));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000426 __ str(cp, MemOperand(r0, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000427 __ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX)));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000428 __ str(r2, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000429
430 // Initialize the rest of the slots to undefined.
431 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000432 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000433 __ str(r1, MemOperand(r0, Context::SlotOffset(i)));
434 }
435
436 // Remove the on-stack argument and return.
437 __ mov(cp, r0);
438 __ pop();
439 __ Ret();
440
441 // Need to collect. Call into runtime system.
442 __ bind(&gc);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000443 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000444}
445
446
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000447void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
448 // Stack layout on entry:
449 //
450 // [sp]: function.
451 // [sp + kPointerSize]: serialized scope info
452
453 // Try to allocate the context in new space.
454 Label gc;
455 int length = slots_ + Context::MIN_CONTEXT_SLOTS;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000456 __ Allocate(FixedArray::SizeFor(length), r0, r1, r2, &gc, TAG_OBJECT);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000457
458 // Load the function from the stack.
459 __ ldr(r3, MemOperand(sp, 0));
460
461 // Load the serialized scope info from the stack.
462 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
463
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000464 // Set up the object header.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000465 __ LoadRoot(r2, Heap::kBlockContextMapRootIndex);
466 __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
467 __ mov(r2, Operand(Smi::FromInt(length)));
468 __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset));
469
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000470 // If this block context is nested in the native context we get a smi
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000471 // sentinel instead of a function. The block context should get the
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000472 // canonical empty function of the native context as its closure which
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000473 // we still have to look up.
474 Label after_sentinel;
475 __ JumpIfNotSmi(r3, &after_sentinel);
476 if (FLAG_debug_code) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000477 __ cmp(r3, Operand::Zero());
danno@chromium.org59400602013-08-13 17:09:37 +0000478 __ Assert(eq, kExpected0AsASmiSentinel);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000479 }
480 __ ldr(r3, GlobalObjectOperand());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000481 __ ldr(r3, FieldMemOperand(r3, GlobalObject::kNativeContextOffset));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000482 __ ldr(r3, ContextOperand(r3, Context::CLOSURE_INDEX));
483 __ bind(&after_sentinel);
484
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000485 // Set up the fixed slots, copy the global object from the previous context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000486 __ ldr(r2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000487 __ str(r3, ContextOperand(r0, Context::CLOSURE_INDEX));
488 __ str(cp, ContextOperand(r0, Context::PREVIOUS_INDEX));
489 __ str(r1, ContextOperand(r0, Context::EXTENSION_INDEX));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000490 __ str(r2, ContextOperand(r0, Context::GLOBAL_OBJECT_INDEX));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000491
492 // Initialize the rest of the slots to the hole value.
493 __ LoadRoot(r1, Heap::kTheHoleValueRootIndex);
494 for (int i = 0; i < slots_; i++) {
495 __ str(r1, ContextOperand(r0, i + Context::MIN_CONTEXT_SLOTS));
496 }
497
498 // Remove the on-stack argument and return.
499 __ mov(cp, r0);
500 __ add(sp, sp, Operand(2 * kPointerSize));
501 __ Ret();
502
503 // Need to collect. Call into runtime system.
504 __ bind(&gc);
505 __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1);
506}
507
508
ricow@chromium.org65fae842010-08-25 15:26:24 +0000509// Takes a Smi and converts to an IEEE 64 bit floating point value in two
510// registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and
511// 52 fraction bits (20 in the first word, 32 in the second). Zeros is a
512// scratch register. Destroys the source register. No GC occurs during this
513// stub so you don't have to set up the frame.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000514class ConvertToDoubleStub : public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000515 public:
516 ConvertToDoubleStub(Register result_reg_1,
517 Register result_reg_2,
518 Register source_reg,
519 Register scratch_reg)
520 : result1_(result_reg_1),
521 result2_(result_reg_2),
522 source_(source_reg),
523 zeros_(scratch_reg) { }
524
525 private:
526 Register result1_;
527 Register result2_;
528 Register source_;
529 Register zeros_;
530
531 // Minor key encoding in 16 bits.
532 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
533 class OpBits: public BitField<Token::Value, 2, 14> {};
534
535 Major MajorKey() { return ConvertToDouble; }
536 int MinorKey() {
537 // Encode the parameters in a unique 16 bit value.
538 return result1_.code() +
539 (result2_.code() << 4) +
540 (source_.code() << 8) +
541 (zeros_.code() << 12);
542 }
543
544 void Generate(MacroAssembler* masm);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000545};
546
547
548void ConvertToDoubleStub::Generate(MacroAssembler* masm) {
danno@chromium.org160a7b02011-04-18 15:51:38 +0000549 Register exponent = result1_;
550 Register mantissa = result2_;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000551
ricow@chromium.org65fae842010-08-25 15:26:24 +0000552 Label not_special;
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000553 __ SmiUntag(source_);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000554 // Move sign bit from source to destination. This works because the sign bit
555 // in the exponent word of the double has the same position and polarity as
556 // the 2's complement sign bit in a Smi.
557 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
558 __ and_(exponent, source_, Operand(HeapNumber::kSignMask), SetCC);
559 // Subtract from 0 if source was negative.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000560 __ rsb(source_, source_, Operand::Zero(), LeaveCC, ne);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000561
562 // We have -1, 0 or 1, which we treat specially. Register source_ contains
563 // absolute value: it is either equal to 1 (special case of -1 and 1),
564 // greater than 1 (not a special case) or less than 1 (special case of 0).
565 __ cmp(source_, Operand(1));
566 __ b(gt, &not_special);
567
568 // For 1 or -1 we need to or in the 0 exponent (biased to 1023).
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000569 const uint32_t exponent_word_for_1 =
ricow@chromium.org65fae842010-08-25 15:26:24 +0000570 HeapNumber::kExponentBias << HeapNumber::kExponentShift;
571 __ orr(exponent, exponent, Operand(exponent_word_for_1), LeaveCC, eq);
572 // 1, 0 and -1 all have 0 for the second word.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000573 __ mov(mantissa, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000574 __ Ret();
575
576 __ bind(&not_special);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000577 __ clz(zeros_, source_);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000578 // Compute exponent and or it into the exponent register.
579 // We use mantissa as a scratch register here. Use a fudge factor to
580 // divide the constant 31 + HeapNumber::kExponentBias, 0x41d, into two parts
581 // that fit in the ARM's constant field.
582 int fudge = 0x400;
583 __ rsb(mantissa, zeros_, Operand(31 + HeapNumber::kExponentBias - fudge));
584 __ add(mantissa, mantissa, Operand(fudge));
585 __ orr(exponent,
586 exponent,
587 Operand(mantissa, LSL, HeapNumber::kExponentShift));
588 // Shift up the source chopping the top bit off.
589 __ add(zeros_, zeros_, Operand(1));
590 // This wouldn't work for 1.0 or -1.0 as the shift would be 32 which means 0.
591 __ mov(source_, Operand(source_, LSL, zeros_));
592 // Compute lower part of fraction (last 12 bits).
593 __ mov(mantissa, Operand(source_, LSL, HeapNumber::kMantissaBitsInTopWord));
594 // And the top (top 20 bits).
595 __ orr(exponent,
596 exponent,
597 Operand(source_, LSR, 32 - HeapNumber::kMantissaBitsInTopWord));
598 __ Ret();
599}
600
601
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +0000602void DoubleToIStub::Generate(MacroAssembler* masm) {
603 Label out_of_range, only_low, negate, done;
604 Register input_reg = source();
605 Register result_reg = destination();
606
607 int double_offset = offset();
608 // Account for saved regs if input is sp.
609 if (input_reg.is(sp)) double_offset += 2 * kPointerSize;
610
611 // Immediate values for this stub fit in instructions, so it's safe to use ip.
612 Register scratch = ip;
613 Register scratch_low =
614 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch);
615 Register scratch_high =
616 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch, scratch_low);
617 LowDwVfpRegister double_scratch = kScratchDoubleReg;
618
619 __ Push(scratch_high, scratch_low);
620
621 if (!skip_fastpath()) {
622 // Load double input.
623 __ vldr(double_scratch, MemOperand(input_reg, double_offset));
624 __ vmov(scratch_low, scratch_high, double_scratch);
625
626 // Do fast-path convert from double to int.
627 __ vcvt_s32_f64(double_scratch.low(), double_scratch);
628 __ vmov(result_reg, double_scratch.low());
629
630 // If result is not saturated (0x7fffffff or 0x80000000), we are done.
631 __ sub(scratch, result_reg, Operand(1));
632 __ cmp(scratch, Operand(0x7ffffffe));
633 __ b(lt, &done);
634 } else {
635 // We've already done MacroAssembler::TryFastTruncatedDoubleToILoad, so we
636 // know exponent > 31, so we can skip the vcvt_s32_f64 which will saturate.
637 if (double_offset == 0) {
638 __ ldm(ia, input_reg, scratch_low.bit() | scratch_high.bit());
639 } else {
640 __ ldr(scratch_low, MemOperand(input_reg, double_offset));
641 __ ldr(scratch_high, MemOperand(input_reg, double_offset + kIntSize));
642 }
643 }
644
645 __ Ubfx(scratch, scratch_high,
646 HeapNumber::kExponentShift, HeapNumber::kExponentBits);
647 // Load scratch with exponent - 1. This is faster than loading
648 // with exponent because Bias + 1 = 1024 which is an *ARM* immediate value.
649 STATIC_ASSERT(HeapNumber::kExponentBias + 1 == 1024);
650 __ sub(scratch, scratch, Operand(HeapNumber::kExponentBias + 1));
651 // If exponent is greater than or equal to 84, the 32 less significant
652 // bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits),
653 // the result is 0.
654 // Compare exponent with 84 (compare exponent - 1 with 83).
655 __ cmp(scratch, Operand(83));
656 __ b(ge, &out_of_range);
657
658 // If we reach this code, 31 <= exponent <= 83.
659 // So, we don't have to handle cases where 0 <= exponent <= 20 for
660 // which we would need to shift right the high part of the mantissa.
661 // Scratch contains exponent - 1.
662 // Load scratch with 52 - exponent (load with 51 - (exponent - 1)).
663 __ rsb(scratch, scratch, Operand(51), SetCC);
664 __ b(ls, &only_low);
665 // 21 <= exponent <= 51, shift scratch_low and scratch_high
666 // to generate the result.
667 __ mov(scratch_low, Operand(scratch_low, LSR, scratch));
668 // Scratch contains: 52 - exponent.
669 // We needs: exponent - 20.
670 // So we use: 32 - scratch = 32 - 52 + exponent = exponent - 20.
671 __ rsb(scratch, scratch, Operand(32));
672 __ Ubfx(result_reg, scratch_high,
673 0, HeapNumber::kMantissaBitsInTopWord);
674 // Set the implicit 1 before the mantissa part in scratch_high.
675 __ orr(result_reg, result_reg,
676 Operand(1 << HeapNumber::kMantissaBitsInTopWord));
677 __ orr(result_reg, scratch_low, Operand(result_reg, LSL, scratch));
678 __ b(&negate);
679
680 __ bind(&out_of_range);
681 __ mov(result_reg, Operand::Zero());
682 __ b(&done);
683
684 __ bind(&only_low);
685 // 52 <= exponent <= 83, shift only scratch_low.
686 // On entry, scratch contains: 52 - exponent.
687 __ rsb(scratch, scratch, Operand::Zero());
688 __ mov(result_reg, Operand(scratch_low, LSL, scratch));
689
690 __ bind(&negate);
691 // If input was positive, scratch_high ASR 31 equals 0 and
692 // scratch_high LSR 31 equals zero.
693 // New result = (result eor 0) + 0 = result.
694 // If the input was negative, we have to negate the result.
695 // Input_high ASR 31 equals 0xffffffff and scratch_high LSR 31 equals 1.
696 // New result = (result eor 0xffffffff) + 1 = 0 - result.
697 __ eor(result_reg, result_reg, Operand(scratch_high, ASR, 31));
698 __ add(result_reg, result_reg, Operand(scratch_high, LSR, 31));
699
700 __ bind(&done);
701
702 __ Pop(scratch_high, scratch_low);
703 __ Ret();
704}
705
706
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000707void WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(
708 Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000709 WriteInt32ToHeapNumberStub stub1(r1, r0, r2);
710 WriteInt32ToHeapNumberStub stub2(r2, r0, r3);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +0000711 stub1.GetCode(isolate);
712 stub2.GetCode(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000713}
714
715
ricow@chromium.org65fae842010-08-25 15:26:24 +0000716// See comment for class.
717void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
718 Label max_negative_int;
719 // the_int_ has the answer which is a signed int32 but not a Smi.
720 // We test for the special value that has a different exponent. This test
721 // has the neat side effect of setting the flags according to the sign.
722 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
723 __ cmp(the_int_, Operand(0x80000000u));
724 __ b(eq, &max_negative_int);
725 // Set up the correct exponent in scratch_. All non-Smi int32s have the same.
726 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased).
727 uint32_t non_smi_exponent =
728 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
729 __ mov(scratch_, Operand(non_smi_exponent));
730 // Set the sign bit in scratch_ if the value was negative.
731 __ orr(scratch_, scratch_, Operand(HeapNumber::kSignMask), LeaveCC, cs);
732 // Subtract from 0 if the value was negative.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000733 __ rsb(the_int_, the_int_, Operand::Zero(), LeaveCC, cs);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000734 // We should be masking the implict first digit of the mantissa away here,
735 // but it just ends up combining harmlessly with the last digit of the
736 // exponent that happens to be 1. The sign bit is 0 so we shift 10 to get
737 // the most significant 1 to hit the last bit of the 12 bit sign and exponent.
738 ASSERT(((1 << HeapNumber::kExponentShift) & non_smi_exponent) != 0);
739 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
740 __ orr(scratch_, scratch_, Operand(the_int_, LSR, shift_distance));
741 __ str(scratch_, FieldMemOperand(the_heap_number_,
742 HeapNumber::kExponentOffset));
743 __ mov(scratch_, Operand(the_int_, LSL, 32 - shift_distance));
744 __ str(scratch_, FieldMemOperand(the_heap_number_,
745 HeapNumber::kMantissaOffset));
746 __ Ret();
747
748 __ bind(&max_negative_int);
749 // The max negative int32 is stored as a positive number in the mantissa of
750 // a double because it uses a sign bit instead of using two's complement.
751 // The actual mantissa bits stored are all 0 because the implicit most
752 // significant 1 bit is not stored.
753 non_smi_exponent += 1 << HeapNumber::kExponentShift;
754 __ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent));
755 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000756 __ mov(ip, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000757 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset));
758 __ Ret();
759}
760
761
762// Handle the case where the lhs and rhs are the same object.
763// Equality is almost reflexive (everything but NaN), so this is a test
764// for "identity and not NaN".
765static void EmitIdenticalObjectComparison(MacroAssembler* masm,
766 Label* slow,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000767 Condition cond) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000768 Label not_identical;
769 Label heap_number, return_equal;
770 __ cmp(r0, r1);
771 __ b(ne, &not_identical);
772
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000773 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000774 // so we do the second best thing - test it ourselves.
775 // They are both equal and they are not both Smis so both of them are not
776 // Smis. If it's not a heap number, then return equal.
777 if (cond == lt || cond == gt) {
778 __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE);
779 __ b(ge, slow);
780 } else {
781 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
782 __ b(eq, &heap_number);
783 // Comparing JS objects with <=, >= is complicated.
784 if (cond != eq) {
785 __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000786 __ b(ge, slow);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000787 // Normally here we fall through to return_equal, but undefined is
788 // special: (undefined == undefined) == true, but
789 // (undefined <= undefined) == false! See ECMAScript 11.8.5.
790 if (cond == le || cond == ge) {
791 __ cmp(r4, Operand(ODDBALL_TYPE));
792 __ b(ne, &return_equal);
793 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
794 __ cmp(r0, r2);
795 __ b(ne, &return_equal);
796 if (cond == le) {
797 // undefined <= undefined should fail.
798 __ mov(r0, Operand(GREATER));
799 } else {
800 // undefined >= undefined should fail.
801 __ mov(r0, Operand(LESS));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000802 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000803 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000804 }
805 }
806 }
807
808 __ bind(&return_equal);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000809 if (cond == lt) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000810 __ mov(r0, Operand(GREATER)); // Things aren't less than themselves.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000811 } else if (cond == gt) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000812 __ mov(r0, Operand(LESS)); // Things aren't greater than themselves.
813 } else {
814 __ mov(r0, Operand(EQUAL)); // Things are <=, >=, ==, === themselves.
815 }
816 __ Ret();
817
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000818 // For less and greater we don't have to check for NaN since the result of
819 // x < x is false regardless. For the others here is some code to check
820 // for NaN.
821 if (cond != lt && cond != gt) {
822 __ bind(&heap_number);
823 // It is a heap number, so return non-equal if it's NaN and equal if it's
824 // not NaN.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000825
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000826 // The representation of NaN values has all exponent bits (52..62) set,
827 // and not all mantissa bits (0..51) clear.
828 // Read top bits of double representation (second word of value).
829 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
830 // Test that exponent bits are all set.
831 __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
832 // NaNs have all-one exponents so they sign extend to -1.
833 __ cmp(r3, Operand(-1));
834 __ b(ne, &return_equal);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000835
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000836 // Shift out flag and all exponent bits, retaining only mantissa.
837 __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord));
838 // Or with all low-bits of mantissa.
839 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
840 __ orr(r0, r3, Operand(r2), SetCC);
841 // For equal we already have the right value in r0: Return zero (equal)
842 // if all bits in mantissa are zero (it's an Infinity) and non-zero if
843 // not (it's a NaN). For <= and >= we need to load r0 with the failing
844 // value if it's a NaN.
845 if (cond != eq) {
846 // All-zero means Infinity means equal.
847 __ Ret(eq);
848 if (cond == le) {
849 __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail.
850 } else {
851 __ mov(r0, Operand(LESS)); // NaN >= NaN should fail.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000852 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000853 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000854 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000855 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000856 // No fall through here.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000857
858 __ bind(&not_identical);
859}
860
861
862// See comment at call site.
863static void EmitSmiNonsmiComparison(MacroAssembler* masm,
864 Register lhs,
865 Register rhs,
866 Label* lhs_not_nan,
867 Label* slow,
868 bool strict) {
869 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
870 (lhs.is(r1) && rhs.is(r0)));
871
872 Label rhs_is_smi;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000873 __ JumpIfSmi(rhs, &rhs_is_smi);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000874
875 // Lhs is a Smi. Check whether the rhs is a heap number.
876 __ CompareObjectType(rhs, r4, r4, HEAP_NUMBER_TYPE);
877 if (strict) {
878 // If rhs is not a number and lhs is a Smi then strict equality cannot
879 // succeed. Return non-equal
880 // If rhs is r0 then there is already a non zero value in it.
881 if (!rhs.is(r0)) {
882 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne);
883 }
884 __ Ret(ne);
885 } else {
886 // Smi compared non-strictly with a non-Smi non-heap-number. Call
887 // the runtime.
888 __ b(ne, slow);
889 }
890
891 // Lhs is a smi, rhs is a number.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000892 // Convert lhs to a double in d7.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000893 __ SmiToDouble(d7, lhs);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000894 // Load the double from rhs, tagged HeapNumber r0, to d6.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000895 __ vldr(d6, rhs, HeapNumber::kValueOffset - kHeapObjectTag);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000896
897 // We now have both loaded as doubles but we can skip the lhs nan check
898 // since it's a smi.
899 __ jmp(lhs_not_nan);
900
901 __ bind(&rhs_is_smi);
902 // Rhs is a smi. Check whether the non-smi lhs is a heap number.
903 __ CompareObjectType(lhs, r4, r4, HEAP_NUMBER_TYPE);
904 if (strict) {
905 // If lhs is not a number and rhs is a smi then strict equality cannot
906 // succeed. Return non-equal.
907 // If lhs is r0 then there is already a non zero value in it.
908 if (!lhs.is(r0)) {
909 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne);
910 }
911 __ Ret(ne);
912 } else {
913 // Smi compared non-strictly with a non-smi non-heap-number. Call
914 // the runtime.
915 __ b(ne, slow);
916 }
917
918 // Rhs is a smi, lhs is a heap number.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000919 // Load the double from lhs, tagged HeapNumber r1, to d7.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000920 __ vldr(d7, lhs, HeapNumber::kValueOffset - kHeapObjectTag);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000921 // Convert rhs to a double in d6 .
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000922 __ SmiToDouble(d6, rhs);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000923 // Fall through to both_loaded_as_doubles.
924}
925
926
ricow@chromium.org65fae842010-08-25 15:26:24 +0000927// See comment at call site.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000928static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
929 Register lhs,
930 Register rhs) {
931 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
932 (lhs.is(r1) && rhs.is(r0)));
933
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000934 // If either operand is a JS object or an oddball value, then they are
ricow@chromium.org65fae842010-08-25 15:26:24 +0000935 // not equal since their pointers are different.
936 // There is no test for undetectability in strict equality.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000937 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000938 Label first_non_object;
939 // Get the type of the first operand into r2 and compare it with
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000940 // FIRST_SPEC_OBJECT_TYPE.
941 __ CompareObjectType(rhs, r2, r2, FIRST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000942 __ b(lt, &first_non_object);
943
944 // Return non-zero (r0 is not zero)
945 Label return_not_equal;
946 __ bind(&return_not_equal);
947 __ Ret();
948
949 __ bind(&first_non_object);
950 // Check for oddballs: true, false, null, undefined.
951 __ cmp(r2, Operand(ODDBALL_TYPE));
952 __ b(eq, &return_not_equal);
953
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000954 __ CompareObjectType(lhs, r3, r3, FIRST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000955 __ b(ge, &return_not_equal);
956
957 // Check for oddballs: true, false, null, undefined.
958 __ cmp(r3, Operand(ODDBALL_TYPE));
959 __ b(eq, &return_not_equal);
960
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000961 // Now that we have the types we might as well check for
962 // internalized-internalized.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000963 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
964 __ orr(r2, r2, Operand(r3));
965 __ tst(r2, Operand(kIsNotStringMask | kIsNotInternalizedMask));
966 __ b(eq, &return_not_equal);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000967}
968
969
970// See comment at call site.
971static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
972 Register lhs,
973 Register rhs,
974 Label* both_loaded_as_doubles,
975 Label* not_heap_numbers,
976 Label* slow) {
977 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
978 (lhs.is(r1) && rhs.is(r0)));
979
980 __ CompareObjectType(rhs, r3, r2, HEAP_NUMBER_TYPE);
981 __ b(ne, not_heap_numbers);
982 __ ldr(r2, FieldMemOperand(lhs, HeapObject::kMapOffset));
983 __ cmp(r2, r3);
984 __ b(ne, slow); // First was a heap number, second wasn't. Go slow case.
985
986 // Both are heap numbers. Load them up then jump to the code we have
987 // for that.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000988 __ vldr(d6, rhs, HeapNumber::kValueOffset - kHeapObjectTag);
989 __ vldr(d7, lhs, HeapNumber::kValueOffset - kHeapObjectTag);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000990 __ jmp(both_loaded_as_doubles);
991}
992
993
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000994// Fast negative check for internalized-to-internalized equality.
995static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
996 Register lhs,
997 Register rhs,
998 Label* possible_strings,
999 Label* not_both_strings) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001000 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
1001 (lhs.is(r1) && rhs.is(r0)));
1002
1003 // r2 is object type of rhs.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001004 Label object_test;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001005 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001006 __ tst(r2, Operand(kIsNotStringMask));
1007 __ b(ne, &object_test);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001008 __ tst(r2, Operand(kIsNotInternalizedMask));
1009 __ b(ne, possible_strings);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001010 __ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE);
1011 __ b(ge, not_both_strings);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001012 __ tst(r3, Operand(kIsNotInternalizedMask));
1013 __ b(ne, possible_strings);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001014
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001015 // Both are internalized. We already checked they weren't the same pointer
ricow@chromium.org65fae842010-08-25 15:26:24 +00001016 // so they are not equal.
1017 __ mov(r0, Operand(NOT_EQUAL));
1018 __ Ret();
1019
1020 __ bind(&object_test);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001021 __ cmp(r2, Operand(FIRST_SPEC_OBJECT_TYPE));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001022 __ b(lt, not_both_strings);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001023 __ CompareObjectType(lhs, r2, r3, FIRST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001024 __ b(lt, not_both_strings);
1025 // If both objects are undetectable, they are equal. Otherwise, they
1026 // are not equal, since they are different objects and an object is not
1027 // equal to undefined.
1028 __ ldr(r3, FieldMemOperand(rhs, HeapObject::kMapOffset));
1029 __ ldrb(r2, FieldMemOperand(r2, Map::kBitFieldOffset));
1030 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
1031 __ and_(r0, r2, Operand(r3));
1032 __ and_(r0, r0, Operand(1 << Map::kIsUndetectable));
1033 __ eor(r0, r0, Operand(1 << Map::kIsUndetectable));
1034 __ Ret();
1035}
1036
1037
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001038static void ICCompareStub_CheckInputType(MacroAssembler* masm,
1039 Register input,
1040 Register scratch,
1041 CompareIC::State expected,
1042 Label* fail) {
1043 Label ok;
1044 if (expected == CompareIC::SMI) {
1045 __ JumpIfNotSmi(input, fail);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001046 } else if (expected == CompareIC::NUMBER) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001047 __ JumpIfSmi(input, &ok);
1048 __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail,
1049 DONT_DO_SMI_CHECK);
1050 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001051 // We could be strict about internalized/non-internalized here, but as long as
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001052 // hydrogen doesn't care, the stub doesn't have to care either.
1053 __ bind(&ok);
1054}
1055
1056
1057// On entry r1 and r2 are the values to be compared.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001058// On exit r0 is 0, positive or negative to indicate the result of
1059// the comparison.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001060void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
1061 Register lhs = r1;
1062 Register rhs = r0;
1063 Condition cc = GetCondition();
1064
1065 Label miss;
1066 ICCompareStub_CheckInputType(masm, lhs, r2, left_, &miss);
1067 ICCompareStub_CheckInputType(masm, rhs, r3, right_, &miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001068
1069 Label slow; // Call builtin.
1070 Label not_smis, both_loaded_as_doubles, lhs_not_nan;
1071
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001072 Label not_two_smis, smi_done;
1073 __ orr(r2, r1, r0);
1074 __ JumpIfNotSmi(r2, &not_two_smis);
1075 __ mov(r1, Operand(r1, ASR, 1));
1076 __ sub(r0, r1, Operand(r0, ASR, 1));
1077 __ Ret();
1078 __ bind(&not_two_smis);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001079
ricow@chromium.org65fae842010-08-25 15:26:24 +00001080 // NOTICE! This code is only reached after a smi-fast-case check, so
1081 // it is certain that at least one operand isn't a smi.
1082
1083 // Handle the case where the objects are identical. Either returns the answer
1084 // or goes to slow. Only falls through if the objects were not identical.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001085 EmitIdenticalObjectComparison(masm, &slow, cc);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001086
1087 // If either is a Smi (we know that not both are), then they can only
1088 // be strictly equal if the other is a HeapNumber.
1089 STATIC_ASSERT(kSmiTag == 0);
1090 ASSERT_EQ(0, Smi::FromInt(0));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001091 __ and_(r2, lhs, Operand(rhs));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001092 __ JumpIfNotSmi(r2, &not_smis);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001093 // One operand is a smi. EmitSmiNonsmiComparison generates code that can:
1094 // 1) Return the answer.
1095 // 2) Go to slow.
1096 // 3) Fall through to both_loaded_as_doubles.
1097 // 4) Jump to lhs_not_nan.
1098 // In cases 3 and 4 we have found out we were dealing with a number-number
1099 // comparison. If VFP3 is supported the double values of the numbers have
1100 // been loaded into d7 and d6. Otherwise, the double values have been loaded
1101 // into r0, r1, r2, and r3.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001102 EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001103
1104 __ bind(&both_loaded_as_doubles);
1105 // The arguments have been converted to doubles and stored in d6 and d7, if
1106 // VFP3 is supported, or in r0, r1, r2, and r3.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001107 Isolate* isolate = masm->isolate();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001108 __ bind(&lhs_not_nan);
1109 Label no_nan;
1110 // ARMv7 VFP3 instructions to implement double precision comparison.
1111 __ VFPCompareAndSetFlags(d7, d6);
1112 Label nan;
1113 __ b(vs, &nan);
1114 __ mov(r0, Operand(EQUAL), LeaveCC, eq);
1115 __ mov(r0, Operand(LESS), LeaveCC, lt);
1116 __ mov(r0, Operand(GREATER), LeaveCC, gt);
1117 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001118
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001119 __ bind(&nan);
1120 // If one of the sides was a NaN then the v flag is set. Load r0 with
1121 // whatever it takes to make the comparison fail, since comparisons with NaN
1122 // always fail.
1123 if (cc == lt || cc == le) {
1124 __ mov(r0, Operand(GREATER));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001125 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001126 __ mov(r0, Operand(LESS));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001127 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001128 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001129
1130 __ bind(&not_smis);
1131 // At this point we know we are dealing with two different objects,
1132 // and neither of them is a Smi. The objects are in rhs_ and lhs_.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001133 if (strict()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001134 // This returns non-equal for some object types, or falls through if it
1135 // was not lucky.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001136 EmitStrictTwoHeapObjectCompare(masm, lhs, rhs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001137 }
1138
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001139 Label check_for_internalized_strings;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001140 Label flat_string_check;
1141 // Check for heap-number-heap-number comparison. Can jump to slow case,
1142 // or load both doubles into r0, r1, r2, r3 and jump to the code that handles
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001143 // that case. If the inputs are not doubles then jumps to
1144 // check_for_internalized_strings.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001145 // In this case r2 will contain the type of rhs_. Never falls through.
1146 EmitCheckForTwoHeapNumbers(masm,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001147 lhs,
1148 rhs,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001149 &both_loaded_as_doubles,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001150 &check_for_internalized_strings,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001151 &flat_string_check);
1152
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001153 __ bind(&check_for_internalized_strings);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001154 // In the strict case the EmitStrictTwoHeapObjectCompare already took care of
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001155 // internalized strings.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001156 if (cc == eq && !strict()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001157 // Returns an answer for two internalized strings or two detectable objects.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001158 // Otherwise jumps to string case or not both strings case.
1159 // Assumes that r2 is the type of rhs_ on entry.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001160 EmitCheckForInternalizedStringsOrObjects(
1161 masm, lhs, rhs, &flat_string_check, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001162 }
1163
1164 // Check for both being sequential ASCII strings, and inline if that is the
1165 // case.
1166 __ bind(&flat_string_check);
1167
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001168 __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs, rhs, r2, r3, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001169
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001170 __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001171 if (cc == eq) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001172 StringCompareStub::GenerateFlatAsciiStringEquals(masm,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001173 lhs,
1174 rhs,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001175 r2,
1176 r3,
lrn@chromium.org1c092762011-05-09 09:42:16 +00001177 r4);
1178 } else {
1179 StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001180 lhs,
1181 rhs,
lrn@chromium.org1c092762011-05-09 09:42:16 +00001182 r2,
1183 r3,
1184 r4,
1185 r5);
1186 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001187 // Never falls through to here.
1188
1189 __ bind(&slow);
1190
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001191 __ Push(lhs, rhs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001192 // Figure out which native to call and setup the arguments.
1193 Builtins::JavaScript native;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001194 if (cc == eq) {
1195 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001196 } else {
1197 native = Builtins::COMPARE;
1198 int ncr; // NaN compare result
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001199 if (cc == lt || cc == le) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001200 ncr = GREATER;
1201 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001202 ASSERT(cc == gt || cc == ge); // remaining cases
ricow@chromium.org65fae842010-08-25 15:26:24 +00001203 ncr = LESS;
1204 }
1205 __ mov(r0, Operand(Smi::FromInt(ncr)));
1206 __ push(r0);
1207 }
1208
1209 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
1210 // tagged as a small integer.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001211 __ InvokeBuiltin(native, JUMP_FUNCTION);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001212
1213 __ bind(&miss);
1214 GenerateMiss(masm);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001215}
1216
1217
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001218void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
1219 // We don't allow a GC during a store buffer overflow so there is no need to
1220 // store the registers in any particular way, but we do have to store and
1221 // restore them.
1222 __ stm(db_w, sp, kCallerSaved | lr.bit());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001223
1224 const Register scratch = r1;
1225
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001226 if (save_doubles_ == kSaveFPRegs) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001227 __ SaveFPRegs(sp, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001228 }
1229 const int argument_count = 1;
1230 const int fp_argument_count = 0;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001231
1232 AllowExternalCallThatCantCauseGC scope(masm);
1233 __ PrepareCallCFunction(argument_count, fp_argument_count, scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001234 __ mov(r0, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001235 __ CallCFunction(
1236 ExternalReference::store_buffer_overflow_function(masm->isolate()),
1237 argument_count);
1238 if (save_doubles_ == kSaveFPRegs) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001239 __ RestoreFPRegs(sp, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001240 }
1241 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0).
1242}
1243
1244
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001245void MathPowStub::Generate(MacroAssembler* masm) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001246 const Register base = r1;
1247 const Register exponent = r2;
1248 const Register heapnumbermap = r5;
1249 const Register heapnumber = r0;
machenbach@chromium.org9f18d912013-11-28 13:42:41 +00001250 const DwVfpRegister double_base = d0;
1251 const DwVfpRegister double_exponent = d1;
1252 const DwVfpRegister double_result = d2;
1253 const DwVfpRegister double_scratch = d3;
1254 const SwVfpRegister single_scratch = s6;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001255 const Register scratch = r9;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001256 const Register scratch2 = r4;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001257
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001258 Label call_runtime, done, int_exponent;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001259 if (exponent_type_ == ON_STACK) {
1260 Label base_is_smi, unpack_exponent;
1261 // The exponent and base are supplied as arguments on the stack.
1262 // This can only happen if the stub is called from non-optimized code.
1263 // Load input parameters from stack to double registers.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001264 __ ldr(base, MemOperand(sp, 1 * kPointerSize));
1265 __ ldr(exponent, MemOperand(sp, 0 * kPointerSize));
1266
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001267 __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001268
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001269 __ UntagAndJumpIfSmi(scratch, base, &base_is_smi);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001270 __ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset));
1271 __ cmp(scratch, heapnumbermap);
1272 __ b(ne, &call_runtime);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001273
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001274 __ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
1275 __ jmp(&unpack_exponent);
1276
1277 __ bind(&base_is_smi);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001278 __ vmov(single_scratch, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001279 __ vcvt_f64_s32(double_base, single_scratch);
1280 __ bind(&unpack_exponent);
1281
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001282 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001283
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001284 __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset));
1285 __ cmp(scratch, heapnumbermap);
1286 __ b(ne, &call_runtime);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001287 __ vldr(double_exponent,
1288 FieldMemOperand(exponent, HeapNumber::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001289 } else if (exponent_type_ == TAGGED) {
1290 // Base is already in double_base.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001291 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001292
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001293 __ vldr(double_exponent,
1294 FieldMemOperand(exponent, HeapNumber::kValueOffset));
1295 }
1296
1297 if (exponent_type_ != INTEGER) {
1298 Label int_exponent_convert;
1299 // Detect integer exponents stored as double.
1300 __ vcvt_u32_f64(single_scratch, double_exponent);
1301 // We do not check for NaN or Infinity here because comparing numbers on
1302 // ARM correctly distinguishes NaNs. We end up calling the built-in.
1303 __ vcvt_f64_u32(double_scratch, single_scratch);
1304 __ VFPCompareAndSetFlags(double_scratch, double_exponent);
1305 __ b(eq, &int_exponent_convert);
1306
1307 if (exponent_type_ == ON_STACK) {
1308 // Detect square root case. Crankshaft detects constant +/-0.5 at
1309 // compile time and uses DoMathPowHalf instead. We then skip this check
1310 // for non-constant cases of +/-0.5 as these hardly occur.
1311 Label not_plus_half;
1312
1313 // Test for 0.5.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001314 __ vmov(double_scratch, 0.5, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001315 __ VFPCompareAndSetFlags(double_exponent, double_scratch);
1316 __ b(ne, &not_plus_half);
1317
1318 // Calculates square root of base. Check for the special case of
1319 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001320 __ vmov(double_scratch, -V8_INFINITY, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001321 __ VFPCompareAndSetFlags(double_base, double_scratch);
1322 __ vneg(double_result, double_scratch, eq);
1323 __ b(eq, &done);
1324
1325 // Add +0 to convert -0 to +0.
1326 __ vadd(double_scratch, double_base, kDoubleRegZero);
1327 __ vsqrt(double_result, double_scratch);
1328 __ jmp(&done);
1329
1330 __ bind(&not_plus_half);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001331 __ vmov(double_scratch, -0.5, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001332 __ VFPCompareAndSetFlags(double_exponent, double_scratch);
1333 __ b(ne, &call_runtime);
1334
1335 // Calculates square root of base. Check for the special case of
1336 // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001337 __ vmov(double_scratch, -V8_INFINITY, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001338 __ VFPCompareAndSetFlags(double_base, double_scratch);
1339 __ vmov(double_result, kDoubleRegZero, eq);
1340 __ b(eq, &done);
1341
1342 // Add +0 to convert -0 to +0.
1343 __ vadd(double_scratch, double_base, kDoubleRegZero);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001344 __ vmov(double_result, 1.0, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001345 __ vsqrt(double_scratch, double_scratch);
1346 __ vdiv(double_result, double_result, double_scratch);
1347 __ jmp(&done);
1348 }
1349
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001350 __ push(lr);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001351 {
1352 AllowExternalCallThatCantCauseGC scope(masm);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001353 __ PrepareCallCFunction(0, 2, scratch);
1354 __ SetCallCDoubleArguments(double_base, double_exponent);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001355 __ CallCFunction(
1356 ExternalReference::power_double_double_function(masm->isolate()),
1357 0, 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001358 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001359 __ pop(lr);
1360 __ GetCFunctionDoubleResult(double_result);
1361 __ jmp(&done);
1362
1363 __ bind(&int_exponent_convert);
1364 __ vcvt_u32_f64(single_scratch, double_exponent);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001365 __ vmov(scratch, single_scratch);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001366 }
1367
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001368 // Calculate power with integer exponent.
1369 __ bind(&int_exponent);
1370
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001371 // Get two copies of exponent in the registers scratch and exponent.
1372 if (exponent_type_ == INTEGER) {
1373 __ mov(scratch, exponent);
1374 } else {
1375 // Exponent has previously been stored into scratch as untagged integer.
1376 __ mov(exponent, scratch);
1377 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001378 __ vmov(double_scratch, double_base); // Back up base.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001379 __ vmov(double_result, 1.0, scratch2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001380
1381 // Get absolute value of exponent.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001382 __ cmp(scratch, Operand::Zero());
1383 __ mov(scratch2, Operand::Zero(), LeaveCC, mi);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001384 __ sub(scratch, scratch2, scratch, LeaveCC, mi);
1385
1386 Label while_true;
1387 __ bind(&while_true);
1388 __ mov(scratch, Operand(scratch, ASR, 1), SetCC);
1389 __ vmul(double_result, double_result, double_scratch, cs);
1390 __ vmul(double_scratch, double_scratch, double_scratch, ne);
1391 __ b(ne, &while_true);
1392
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001393 __ cmp(exponent, Operand::Zero());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001394 __ b(ge, &done);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001395 __ vmov(double_scratch, 1.0, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001396 __ vdiv(double_result, double_scratch, double_result);
1397 // Test whether result is zero. Bail out to check for subnormal result.
1398 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
1399 __ VFPCompareAndSetFlags(double_result, 0.0);
1400 __ b(ne, &done);
1401 // double_exponent may not containe the exponent value if the input was a
1402 // smi. We set it with exponent value before bailing out.
1403 __ vmov(single_scratch, exponent);
1404 __ vcvt_f64_s32(double_exponent, single_scratch);
1405
1406 // Returning or bailing out.
1407 Counters* counters = masm->isolate()->counters();
1408 if (exponent_type_ == ON_STACK) {
1409 // The arguments are still on the stack.
1410 __ bind(&call_runtime);
1411 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
1412
1413 // The stub is called from non-optimized code, which expects the result
1414 // as heap number in exponent.
1415 __ bind(&done);
1416 __ AllocateHeapNumber(
1417 heapnumber, scratch, scratch2, heapnumbermap, &call_runtime);
1418 __ vstr(double_result,
1419 FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
1420 ASSERT(heapnumber.is(r0));
1421 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
1422 __ Ret(2);
1423 } else {
1424 __ push(lr);
1425 {
1426 AllowExternalCallThatCantCauseGC scope(masm);
1427 __ PrepareCallCFunction(0, 2, scratch);
1428 __ SetCallCDoubleArguments(double_base, double_exponent);
1429 __ CallCFunction(
1430 ExternalReference::power_double_double_function(masm->isolate()),
1431 0, 2);
1432 }
1433 __ pop(lr);
1434 __ GetCFunctionDoubleResult(double_result);
1435
1436 __ bind(&done);
1437 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
1438 __ Ret();
1439 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001440}
1441
1442
1443bool CEntryStub::NeedsImmovableCode() {
1444 return true;
1445}
1446
1447
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001448void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
1449 CEntryStub::GenerateAheadOfTime(isolate);
1450 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
1451 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001452 StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001453 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001454 CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00001455 BinaryOpICStub::GenerateAheadOfTime(isolate);
ulan@chromium.org0f13e742014-01-03 15:51:11 +00001456 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001457}
1458
1459
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001460void CodeStub::GenerateFPStubs(Isolate* isolate) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001461 SaveFPRegsMode mode = kSaveFPRegs;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001462 CEntryStub save_doubles(1, mode);
1463 StoreBufferOverflowStub stub(mode);
1464 // These stubs might already be in the snapshot, detect that and don't
1465 // regenerate, which would lead to code stub initialization state being messed
1466 // up.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001467 Code* save_doubles_code;
1468 if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) {
1469 save_doubles_code = *save_doubles.GetCode(isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001470 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001471 Code* store_buffer_overflow_code;
1472 if (!stub.FindCodeInCache(&store_buffer_overflow_code, isolate)) {
1473 store_buffer_overflow_code = *stub.GetCode(isolate);
1474 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001475 isolate->set_fp_stubs_generated(true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001476}
1477
1478
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001479void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001480 CEntryStub stub(1, kDontSaveFPRegs);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001481 stub.GetCode(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001482}
1483
1484
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001485static void JumpIfOOM(MacroAssembler* masm,
1486 Register value,
1487 Register scratch,
1488 Label* oom_label) {
1489 STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
1490 STATIC_ASSERT(kFailureTag == 3);
1491 __ and_(scratch, value, Operand(0xf));
1492 __ cmp(scratch, Operand(0xf));
1493 __ b(eq, oom_label);
1494}
1495
1496
ricow@chromium.org65fae842010-08-25 15:26:24 +00001497void CEntryStub::GenerateCore(MacroAssembler* masm,
1498 Label* throw_normal_exception,
1499 Label* throw_termination_exception,
1500 Label* throw_out_of_memory_exception,
1501 bool do_gc,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001502 bool always_allocate) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001503 // r0: result parameter for PerformGC, if any
1504 // r4: number of arguments including receiver (C callee-saved)
1505 // r5: pointer to builtin function (C callee-saved)
1506 // r6: pointer to the first argument (C callee-saved)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001507 Isolate* isolate = masm->isolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001508
1509 if (do_gc) {
1510 // Passing r0.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001511 __ PrepareCallCFunction(2, 0, r1);
1512 __ mov(r1, Operand(ExternalReference::isolate_address(masm->isolate())));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001513 __ CallCFunction(ExternalReference::perform_gc_function(isolate),
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001514 2, 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001515 }
1516
1517 ExternalReference scope_depth =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001518 ExternalReference::heap_always_allocate_scope_depth(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001519 if (always_allocate) {
1520 __ mov(r0, Operand(scope_depth));
1521 __ ldr(r1, MemOperand(r0));
1522 __ add(r1, r1, Operand(1));
1523 __ str(r1, MemOperand(r0));
1524 }
1525
1526 // Call C built-in.
1527 // r0 = argc, r1 = argv
1528 __ mov(r0, Operand(r4));
1529 __ mov(r1, Operand(r6));
1530
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00001531#if V8_HOST_ARCH_ARM
ricow@chromium.org65fae842010-08-25 15:26:24 +00001532 int frame_alignment = MacroAssembler::ActivationFrameAlignment();
1533 int frame_alignment_mask = frame_alignment - 1;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001534 if (FLAG_debug_code) {
1535 if (frame_alignment > kPointerSize) {
1536 Label alignment_as_expected;
1537 ASSERT(IsPowerOf2(frame_alignment));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001538 __ tst(sp, Operand(frame_alignment_mask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001539 __ b(eq, &alignment_as_expected);
1540 // Don't use Check here, as it will call Runtime_Abort re-entering here.
1541 __ stop("Unexpected alignment");
1542 __ bind(&alignment_as_expected);
1543 }
1544 }
1545#endif
1546
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001547 __ mov(r2, Operand(ExternalReference::isolate_address(isolate)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001548
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001549 // To let the GC traverse the return address of the exit frames, we need to
1550 // know where the return address is. The CEntryStub is unmovable, so
1551 // we can store the address on the stack to be able to find it again and
1552 // we never have to restore it, because it will not change.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001553 // Compute the return address in lr to return to after the jump below. Pc is
1554 // already at '+ 8' from the current instruction but return is after three
1555 // instructions so add another 4 to pc to get the return address.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001556 {
1557 // Prevent literal pool emission before return address.
1558 Assembler::BlockConstPoolScope block_const_pool(masm);
1559 masm->add(lr, pc, Operand(4));
1560 __ str(lr, MemOperand(sp, 0));
1561 masm->Jump(r5);
1562 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001563
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001564 __ VFPEnsureFPSCRState(r2);
1565
ricow@chromium.org65fae842010-08-25 15:26:24 +00001566 if (always_allocate) {
1567 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
1568 // though (contain the result).
1569 __ mov(r2, Operand(scope_depth));
1570 __ ldr(r3, MemOperand(r2));
1571 __ sub(r3, r3, Operand(1));
1572 __ str(r3, MemOperand(r2));
1573 }
1574
1575 // check for failure result
1576 Label failure_returned;
1577 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
1578 // Lower 2 bits of r2 are 0 iff r0 has failure tag.
1579 __ add(r2, r0, Operand(1));
1580 __ tst(r2, Operand(kFailureTagMask));
1581 __ b(eq, &failure_returned);
1582
1583 // Exit C frame and return.
1584 // r0:r1: result
1585 // sp: stack pointer
1586 // fp: frame pointer
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001587 // Callee-saved register r4 still holds argc.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001588 __ LeaveExitFrame(save_doubles_, r4, true);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001589 __ mov(pc, lr);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001590
1591 // check if we should retry or throw exception
1592 Label retry;
1593 __ bind(&failure_returned);
1594 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
1595 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
1596 __ b(eq, &retry);
1597
1598 // Special handling of out of memory exceptions.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001599 JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001600
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001601 // Retrieve the pending exception.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001602 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001603 isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001604 __ ldr(r0, MemOperand(ip));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001605
1606 // See if we just retrieved an OOM exception.
1607 JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
1608
1609 // Clear the pending exception.
1610 __ mov(r3, Operand(isolate->factory()->the_hole_value()));
1611 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
1612 isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001613 __ str(r3, MemOperand(ip));
1614
1615 // Special handling of termination exceptions which are uncatchable
1616 // by javascript code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001617 __ cmp(r0, Operand(isolate->factory()->termination_exception()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001618 __ b(eq, throw_termination_exception);
1619
1620 // Handle normal exception.
1621 __ jmp(throw_normal_exception);
1622
1623 __ bind(&retry); // pass last failure (r0) as parameter (r0) when retrying
1624}
1625
1626
1627void CEntryStub::Generate(MacroAssembler* masm) {
1628 // Called from JavaScript; parameters are on stack as if calling JS function
1629 // r0: number of arguments including receiver
1630 // r1: pointer to builtin function
1631 // fp: frame pointer (restored after C call)
1632 // sp: stack pointer (restored as callee's sp after C call)
1633 // cp: current context (C callee-saved)
1634
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001635 ProfileEntryHookStub::MaybeCallEntryHook(masm);
1636
ricow@chromium.org65fae842010-08-25 15:26:24 +00001637 // Result returned in r0 or r0+r1 by default.
1638
1639 // NOTE: Invocations of builtins may return failure objects
1640 // instead of a proper result. The builtin entry handles
1641 // this by performing a garbage collection and retrying the
1642 // builtin once.
1643
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001644 // Compute the argv pointer in a callee-saved register.
1645 __ add(r6, sp, Operand(r0, LSL, kPointerSizeLog2));
1646 __ sub(r6, r6, Operand(kPointerSize));
1647
ricow@chromium.org65fae842010-08-25 15:26:24 +00001648 // Enter the exit frame that transitions from JavaScript to C++.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001649 FrameScope scope(masm, StackFrame::MANUAL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001650 __ EnterExitFrame(save_doubles_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001651
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001652 // Set up argc and the builtin function in callee-saved registers.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001653 __ mov(r4, Operand(r0));
1654 __ mov(r5, Operand(r1));
1655
ricow@chromium.org65fae842010-08-25 15:26:24 +00001656 // r4: number of arguments (C callee-saved)
1657 // r5: pointer to builtin function (C callee-saved)
1658 // r6: pointer to first argument (C callee-saved)
1659
1660 Label throw_normal_exception;
1661 Label throw_termination_exception;
1662 Label throw_out_of_memory_exception;
1663
1664 // Call into the runtime system.
1665 GenerateCore(masm,
1666 &throw_normal_exception,
1667 &throw_termination_exception,
1668 &throw_out_of_memory_exception,
1669 false,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001670 false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001671
1672 // Do space-specific GC and retry runtime call.
1673 GenerateCore(masm,
1674 &throw_normal_exception,
1675 &throw_termination_exception,
1676 &throw_out_of_memory_exception,
1677 true,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001678 false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001679
1680 // Do full GC and retry runtime call one final time.
1681 Failure* failure = Failure::InternalError();
1682 __ mov(r0, Operand(reinterpret_cast<int32_t>(failure)));
1683 GenerateCore(masm,
1684 &throw_normal_exception,
1685 &throw_termination_exception,
1686 &throw_out_of_memory_exception,
1687 true,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001688 true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001689
1690 __ bind(&throw_out_of_memory_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001691 // Set external caught exception to false.
1692 Isolate* isolate = masm->isolate();
1693 ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
1694 isolate);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001695 __ mov(r0, Operand(false, RelocInfo::NONE32));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001696 __ mov(r2, Operand(external_caught));
1697 __ str(r0, MemOperand(r2));
1698
1699 // Set pending exception and r0 to out of memory exception.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001700 Label already_have_failure;
1701 JumpIfOOM(masm, r0, ip, &already_have_failure);
1702 Failure* out_of_memory = Failure::OutOfMemoryException(0x1);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001703 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001704 __ bind(&already_have_failure);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001705 __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
1706 isolate)));
1707 __ str(r0, MemOperand(r2));
1708 // Fall through to the next label.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001709
1710 __ bind(&throw_termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001711 __ ThrowUncatchable(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001712
1713 __ bind(&throw_normal_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001714 __ Throw(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001715}
1716
1717
1718void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
1719 // r0: code entry
1720 // r1: function
1721 // r2: receiver
1722 // r3: argc
1723 // [sp+0]: argv
1724
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001725 Label invoke, handler_entry, exit;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001726
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001727 ProfileEntryHookStub::MaybeCallEntryHook(masm);
1728
ricow@chromium.org65fae842010-08-25 15:26:24 +00001729 // Called from C, so do not pop argc and args on exit (preserve sp)
1730 // No need to save register-passed args
1731 // Save callee-saved registers (incl. cp and fp), sp, and lr
1732 __ stm(db_w, sp, kCalleeSaved | lr.bit());
1733
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001734 // Save callee-saved vfp registers.
1735 __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
1736 // Set up the reserved register for 0.0.
1737 __ vmov(kDoubleRegZero, 0.0);
1738 __ VFPEnsureFPSCRState(r4);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001739
ricow@chromium.org65fae842010-08-25 15:26:24 +00001740 // Get address of argv, see stm above.
1741 // r0: code entry
1742 // r1: function
1743 // r2: receiver
1744 // r3: argc
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001745
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001746 // Set up argv in r4.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001747 int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001748 offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001749 __ ldr(r4, MemOperand(sp, offset_to_argv));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001750
1751 // Push a frame with special values setup to mark it as an entry frame.
1752 // r0: code entry
1753 // r1: function
1754 // r2: receiver
1755 // r3: argc
1756 // r4: argv
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001757 Isolate* isolate = masm->isolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001758 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
ulan@chromium.org9ca30172014-01-02 12:10:54 +00001759 if (FLAG_enable_ool_constant_pool) {
1760 __ mov(r8, Operand(Smi::FromInt(marker)));
1761 }
1762 __ mov(r7, Operand(Smi::FromInt(marker)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001763 __ mov(r6, Operand(Smi::FromInt(marker)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001764 __ mov(r5,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001765 Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001766 __ ldr(r5, MemOperand(r5));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001767 __ mov(ip, Operand(-1)); // Push a bad frame pointer to fail if it is used.
ulan@chromium.org9ca30172014-01-02 12:10:54 +00001768 __ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() |
1769 (FLAG_enable_ool_constant_pool ? r8.bit() : 0) |
1770 ip.bit());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001771
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001772 // Set up frame pointer for the frame to be pushed.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001773 __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
1774
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001775 // If this is the outermost JS call, set js_entry_sp value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001776 Label non_outermost_js;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001777 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001778 __ mov(r5, Operand(ExternalReference(js_entry_sp)));
1779 __ ldr(r6, MemOperand(r5));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001780 __ cmp(r6, Operand::Zero());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001781 __ b(ne, &non_outermost_js);
1782 __ str(fp, MemOperand(r5));
1783 __ mov(ip, Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
1784 Label cont;
1785 __ b(&cont);
1786 __ bind(&non_outermost_js);
1787 __ mov(ip, Operand(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
1788 __ bind(&cont);
1789 __ push(ip);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001790
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001791 // Jump to a faked try block that does the invoke, with a faked catch
1792 // block that sets the pending exception.
1793 __ jmp(&invoke);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001794
1795 // Block literal pool emission whilst taking the position of the handler
1796 // entry. This avoids making the assumption that literal pools are always
1797 // emitted after an instruction is emitted, rather than before.
1798 {
1799 Assembler::BlockConstPoolScope block_const_pool(masm);
1800 __ bind(&handler_entry);
1801 handler_offset_ = handler_entry.pos();
1802 // Caught exception: Store result (exception) in the pending exception
1803 // field in the JSEnv and return a failure sentinel. Coming in here the
1804 // fp will be invalid because the PushTryHandler below sets it to 0 to
1805 // signal the existence of the JSEntry frame.
1806 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
1807 isolate)));
1808 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001809 __ str(r0, MemOperand(ip));
1810 __ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
1811 __ b(&exit);
1812
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001813 // Invoke: Link this frame into the handler chain. There's only one
1814 // handler block in this code object, so its index is 0.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001815 __ bind(&invoke);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001816 // Must preserve r0-r4, r5-r6 are available.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001817 __ PushTryHandler(StackHandler::JS_ENTRY, 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001818 // If an exception not caught by another handler occurs, this handler
1819 // returns control to the code after the bl(&invoke) above, which
1820 // restores all kCalleeSaved registers (including cp and fp) to their
1821 // saved values before returning a failure to C.
1822
1823 // Clear any pending exceptions.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001824 __ mov(r5, Operand(isolate->factory()->the_hole_value()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001825 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001827 __ str(r5, MemOperand(ip));
1828
1829 // Invoke the function by calling through JS entry trampoline builtin.
1830 // Notice that we cannot store a reference to the trampoline code directly in
1831 // this stub, because runtime stubs are not traversed when doing GC.
1832
1833 // Expected registers by Builtins::JSEntryTrampoline
1834 // r0: code entry
1835 // r1: function
1836 // r2: receiver
1837 // r3: argc
1838 // r4: argv
1839 if (is_construct) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001840 ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001841 isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001842 __ mov(ip, Operand(construct_entry));
1843 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001844 ExternalReference entry(Builtins::kJSEntryTrampoline, isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001845 __ mov(ip, Operand(entry));
1846 }
1847 __ ldr(ip, MemOperand(ip)); // deref address
1848
1849 // Branch and link to JSEntryTrampoline. We don't use the double underscore
1850 // macro for the add instruction because we don't want the coverage tool
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001851 // inserting instructions here after we read the pc. We block literal pool
1852 // emission for the same reason.
1853 {
1854 Assembler::BlockConstPoolScope block_const_pool(masm);
1855 __ mov(lr, Operand(pc));
1856 masm->add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
1857 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001858
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001859 // Unlink this frame from the handler chain.
1860 __ PopTryHandler();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001861
1862 __ bind(&exit); // r0 holds result
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001863 // Check if the current stack frame is marked as the outermost JS frame.
1864 Label non_outermost_js_2;
1865 __ pop(r5);
1866 __ cmp(r5, Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
1867 __ b(ne, &non_outermost_js_2);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001868 __ mov(r6, Operand::Zero());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001869 __ mov(r5, Operand(ExternalReference(js_entry_sp)));
1870 __ str(r6, MemOperand(r5));
1871 __ bind(&non_outermost_js_2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001872
ricow@chromium.org65fae842010-08-25 15:26:24 +00001873 // Restore the top frame descriptors from the stack.
1874 __ pop(r3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 __ mov(ip,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001876 Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001877 __ str(r3, MemOperand(ip));
1878
1879 // Reset the stack to the callee saved registers.
1880 __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
1881
1882 // Restore callee-saved registers and return.
1883#ifdef DEBUG
1884 if (FLAG_debug_code) {
1885 __ mov(lr, Operand(pc));
1886 }
1887#endif
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001888
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001889 // Restore callee-saved vfp registers.
1890 __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001891
ricow@chromium.org65fae842010-08-25 15:26:24 +00001892 __ ldm(ia_w, sp, kCalleeSaved | pc.bit());
1893}
1894
1895
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001896// Uses registers r0 to r4.
1897// Expected input (depending on whether args are in registers or on the stack):
1898// * object: r0 or at sp + 1 * kPointerSize.
1899// * function: r1 or at sp.
1900//
1901// An inlined call site may have been generated before calling this stub.
1902// In this case the offset to the inline site to patch is passed on the stack,
1903// in the safepoint slot for register r4.
1904// (See LCodeGen::DoInstanceOfKnownGlobal)
ricow@chromium.org65fae842010-08-25 15:26:24 +00001905void InstanceofStub::Generate(MacroAssembler* masm) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001906 // Call site inlining and patching implies arguments in registers.
1907 ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck());
1908 // ReturnTrueFalse is only implemented for inlined call sites.
1909 ASSERT(!ReturnTrueFalseObject() || HasCallSiteInlineCheck());
1910
whesse@chromium.org023421e2010-12-21 12:19:12 +00001911 // Fixed register usage throughout the stub:
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001912 const Register object = r0; // Object (lhs).
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001913 Register map = r3; // Map of the object.
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001914 const Register function = r1; // Function (rhs).
whesse@chromium.org023421e2010-12-21 12:19:12 +00001915 const Register prototype = r4; // Prototype of the function.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001916 const Register inline_site = r9;
whesse@chromium.org023421e2010-12-21 12:19:12 +00001917 const Register scratch = r2;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001918
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001919 const int32_t kDeltaToLoadBoolResult = 4 * kPointerSize;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001920
whesse@chromium.org023421e2010-12-21 12:19:12 +00001921 Label slow, loop, is_instance, is_not_instance, not_js_object;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001922
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001923 if (!HasArgsInRegisters()) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001924 __ ldr(object, MemOperand(sp, 1 * kPointerSize));
1925 __ ldr(function, MemOperand(sp, 0));
whesse@chromium.org023421e2010-12-21 12:19:12 +00001926 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001927
whesse@chromium.org023421e2010-12-21 12:19:12 +00001928 // Check that the left hand is a JS object and load map.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001929 __ JumpIfSmi(object, &not_js_object);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001930 __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001931
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001932 // If there is a call site cache don't look in the global cache, but do the
1933 // real lookup and update the call site cache.
1934 if (!HasCallSiteInlineCheck()) {
1935 Label miss;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001936 __ CompareRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001937 __ b(ne, &miss);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001938 __ CompareRoot(map, Heap::kInstanceofCacheMapRootIndex);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001939 __ b(ne, &miss);
1940 __ LoadRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
1941 __ Ret(HasArgsInRegisters() ? 0 : 2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001942
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001943 __ bind(&miss);
1944 }
1945
1946 // Get the prototype of the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001947 __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001948
1949 // Check that the function prototype is a JS object.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001950 __ JumpIfSmi(prototype, &slow);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001951 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001952
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001953 // Update the global instanceof or call site inlined cache with the current
1954 // map and function. The cached answer will be set when it is known below.
1955 if (!HasCallSiteInlineCheck()) {
1956 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
1957 __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);
1958 } else {
1959 ASSERT(HasArgsInRegisters());
1960 // Patch the (relocated) inlined map check.
1961
1962 // The offset was stored in r4 safepoint slot.
1963 // (See LCodeGen::DoDeferredLInstanceOfKnownGlobal)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001964 __ LoadFromSafepointRegisterSlot(scratch, r4);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001965 __ sub(inline_site, lr, scratch);
1966 // Get the map location in scratch and patch it.
1967 __ GetRelocatedValueLocation(inline_site, scratch);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001968 __ ldr(scratch, MemOperand(scratch));
danno@chromium.org41728482013-06-12 22:31:22 +00001969 __ str(map, FieldMemOperand(scratch, Cell::kValueOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001970 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001971
1972 // Register mapping: r3 is object map and r4 is function prototype.
1973 // Get prototype of object into r2.
whesse@chromium.org023421e2010-12-21 12:19:12 +00001974 __ ldr(scratch, FieldMemOperand(map, Map::kPrototypeOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001975
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001976 // We don't need map any more. Use it as a scratch register.
1977 Register scratch2 = map;
1978 map = no_reg;
1979
ricow@chromium.org65fae842010-08-25 15:26:24 +00001980 // Loop through the prototype chain looking for the function prototype.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001981 __ LoadRoot(scratch2, Heap::kNullValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001982 __ bind(&loop);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001983 __ cmp(scratch, Operand(prototype));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001984 __ b(eq, &is_instance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001985 __ cmp(scratch, scratch2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001986 __ b(eq, &is_not_instance);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001987 __ ldr(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset));
1988 __ ldr(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001989 __ jmp(&loop);
1990
1991 __ bind(&is_instance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001992 if (!HasCallSiteInlineCheck()) {
1993 __ mov(r0, Operand(Smi::FromInt(0)));
1994 __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
1995 } else {
1996 // Patch the call site to return true.
1997 __ LoadRoot(r0, Heap::kTrueValueRootIndex);
1998 __ add(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
1999 // Get the boolean result location in scratch and patch it.
2000 __ GetRelocatedValueLocation(inline_site, scratch);
2001 __ str(r0, MemOperand(scratch));
2002
2003 if (!ReturnTrueFalseObject()) {
2004 __ mov(r0, Operand(Smi::FromInt(0)));
2005 }
2006 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002007 __ Ret(HasArgsInRegisters() ? 0 : 2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002008
2009 __ bind(&is_not_instance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002010 if (!HasCallSiteInlineCheck()) {
2011 __ mov(r0, Operand(Smi::FromInt(1)));
2012 __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
2013 } else {
2014 // Patch the call site to return false.
2015 __ LoadRoot(r0, Heap::kFalseValueRootIndex);
2016 __ add(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
2017 // Get the boolean result location in scratch and patch it.
2018 __ GetRelocatedValueLocation(inline_site, scratch);
2019 __ str(r0, MemOperand(scratch));
2020
2021 if (!ReturnTrueFalseObject()) {
2022 __ mov(r0, Operand(Smi::FromInt(1)));
2023 }
2024 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002025 __ Ret(HasArgsInRegisters() ? 0 : 2);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002026
2027 Label object_not_null, object_not_null_or_smi;
2028 __ bind(&not_js_object);
2029 // Before null, smi and string value checks, check that the rhs is a function
2030 // as for a non-function rhs an exception needs to be thrown.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002031 __ JumpIfSmi(function, &slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002032 __ CompareObjectType(function, scratch2, scratch, JS_FUNCTION_TYPE);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002033 __ b(ne, &slow);
2034
2035 // Null is not instance of anything.
danno@chromium.org160a7b02011-04-18 15:51:38 +00002036 __ cmp(scratch, Operand(masm->isolate()->factory()->null_value()));
whesse@chromium.org023421e2010-12-21 12:19:12 +00002037 __ b(ne, &object_not_null);
2038 __ mov(r0, Operand(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002039 __ Ret(HasArgsInRegisters() ? 0 : 2);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002040
2041 __ bind(&object_not_null);
2042 // Smi values are not instances of anything.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002043 __ JumpIfNotSmi(object, &object_not_null_or_smi);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002044 __ mov(r0, Operand(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002045 __ Ret(HasArgsInRegisters() ? 0 : 2);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002046
2047 __ bind(&object_not_null_or_smi);
2048 // String values are not instances of anything.
2049 __ IsObjectJSStringType(object, scratch, &slow);
2050 __ mov(r0, Operand(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002051 __ Ret(HasArgsInRegisters() ? 0 : 2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002052
2053 // Slow-case. Tail call builtin.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002054 __ bind(&slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002055 if (!ReturnTrueFalseObject()) {
2056 if (HasArgsInRegisters()) {
2057 __ Push(r0, r1);
2058 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002059 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002060 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002061 {
2062 FrameScope scope(masm, StackFrame::INTERNAL);
2063 __ Push(r0, r1);
2064 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
2065 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002066 __ cmp(r0, Operand::Zero());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002067 __ LoadRoot(r0, Heap::kTrueValueRootIndex, eq);
2068 __ LoadRoot(r0, Heap::kFalseValueRootIndex, ne);
2069 __ Ret(HasArgsInRegisters() ? 0 : 2);
2070 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002071}
2072
2073
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002074void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
2075 Label miss;
2076 Register receiver;
2077 if (kind() == Code::KEYED_LOAD_IC) {
2078 // ----------- S t a t e -------------
2079 // -- lr : return address
2080 // -- r0 : key
2081 // -- r1 : receiver
2082 // -----------------------------------
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002083 __ cmp(r0, Operand(masm->isolate()->factory()->prototype_string()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002084 __ b(ne, &miss);
2085 receiver = r1;
2086 } else {
2087 ASSERT(kind() == Code::LOAD_IC);
2088 // ----------- S t a t e -------------
2089 // -- r2 : name
2090 // -- lr : return address
2091 // -- r0 : receiver
2092 // -- sp[0] : receiver
2093 // -----------------------------------
2094 receiver = r0;
2095 }
2096
2097 StubCompiler::GenerateLoadFunctionPrototype(masm, receiver, r3, r4, &miss);
2098 __ bind(&miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +00002099 StubCompiler::TailCallBuiltin(
2100 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002101}
2102
2103
2104void StringLengthStub::Generate(MacroAssembler* masm) {
2105 Label miss;
2106 Register receiver;
2107 if (kind() == Code::KEYED_LOAD_IC) {
2108 // ----------- S t a t e -------------
2109 // -- lr : return address
2110 // -- r0 : key
2111 // -- r1 : receiver
2112 // -----------------------------------
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002113 __ cmp(r0, Operand(masm->isolate()->factory()->length_string()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002114 __ b(ne, &miss);
2115 receiver = r1;
2116 } else {
2117 ASSERT(kind() == Code::LOAD_IC);
2118 // ----------- S t a t e -------------
2119 // -- r2 : name
2120 // -- lr : return address
2121 // -- r0 : receiver
2122 // -- sp[0] : receiver
2123 // -----------------------------------
2124 receiver = r0;
2125 }
2126
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002127 StubCompiler::GenerateLoadStringLength(masm, receiver, r3, r4, &miss);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002128
2129 __ bind(&miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +00002130 StubCompiler::TailCallBuiltin(
2131 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002132}
2133
2134
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002135void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
2136 // This accepts as a receiver anything JSArray::SetElementsLength accepts
2137 // (currently anything except for external arrays which means anything with
2138 // elements of FixedArray type). Value must be a number, but only smis are
2139 // accepted as the most common case.
2140 Label miss;
2141
2142 Register receiver;
2143 Register value;
2144 if (kind() == Code::KEYED_STORE_IC) {
2145 // ----------- S t a t e -------------
2146 // -- lr : return address
2147 // -- r0 : value
2148 // -- r1 : key
2149 // -- r2 : receiver
2150 // -----------------------------------
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002151 __ cmp(r1, Operand(masm->isolate()->factory()->length_string()));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002152 __ b(ne, &miss);
2153 receiver = r2;
2154 value = r0;
2155 } else {
2156 ASSERT(kind() == Code::STORE_IC);
2157 // ----------- S t a t e -------------
2158 // -- lr : return address
2159 // -- r0 : value
2160 // -- r1 : receiver
2161 // -- r2 : key
2162 // -----------------------------------
2163 receiver = r1;
2164 value = r0;
2165 }
2166 Register scratch = r3;
2167
2168 // Check that the receiver isn't a smi.
2169 __ JumpIfSmi(receiver, &miss);
2170
2171 // Check that the object is a JS array.
2172 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
2173 __ b(ne, &miss);
2174
2175 // Check that elements are FixedArray.
2176 // We rely on StoreIC_ArrayLength below to deal with all types of
2177 // fast elements (including COW).
2178 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
2179 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
2180 __ b(ne, &miss);
2181
2182 // Check that the array has fast properties, otherwise the length
2183 // property might have been redefined.
2184 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset));
2185 __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset));
2186 __ CompareRoot(scratch, Heap::kHashTableMapRootIndex);
2187 __ b(eq, &miss);
2188
2189 // Check that value is a smi.
2190 __ JumpIfNotSmi(value, &miss);
2191
2192 // Prepare tail call to StoreIC_ArrayLength.
2193 __ Push(receiver, value);
2194
2195 ExternalReference ref =
2196 ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength), masm->isolate());
2197 __ TailCallExternalReference(ref, 2, 1);
2198
2199 __ bind(&miss);
2200
danno@chromium.orgbee51992013-07-10 14:57:15 +00002201 StubCompiler::TailCallBuiltin(
2202 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002203}
2204
2205
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002206Register InstanceofStub::left() { return r0; }
2207
2208
2209Register InstanceofStub::right() { return r1; }
2210
2211
ricow@chromium.org65fae842010-08-25 15:26:24 +00002212void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
2213 // The displacement is the offset of the last parameter (if any)
2214 // relative to the frame pointer.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002215 const int kDisplacement =
ricow@chromium.org65fae842010-08-25 15:26:24 +00002216 StandardFrameConstants::kCallerSPOffset - kPointerSize;
2217
2218 // Check that the key is a smi.
2219 Label slow;
ager@chromium.org378b34e2011-01-28 08:04:38 +00002220 __ JumpIfNotSmi(r1, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002221
2222 // Check if the calling frame is an arguments adaptor frame.
2223 Label adaptor;
2224 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2225 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
2226 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2227 __ b(eq, &adaptor);
2228
2229 // Check index against formal parameters count limit passed in
2230 // through register r0. Use unsigned comparison to get negative
2231 // check for free.
2232 __ cmp(r1, r0);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002233 __ b(hs, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002234
2235 // Read the argument from the stack and return it.
2236 __ sub(r3, r0, r1);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002237 __ add(r3, fp, Operand::PointerOffsetFromSmiKey(r3));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002238 __ ldr(r0, MemOperand(r3, kDisplacement));
2239 __ Jump(lr);
2240
2241 // Arguments adaptor case: Check index against actual arguments
2242 // limit found in the arguments adaptor frame. Use unsigned
2243 // comparison to get negative check for free.
2244 __ bind(&adaptor);
2245 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
2246 __ cmp(r1, r0);
2247 __ b(cs, &slow);
2248
2249 // Read the argument from the adaptor frame and return it.
2250 __ sub(r3, r0, r1);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002251 __ add(r3, r2, Operand::PointerOffsetFromSmiKey(r3));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002252 __ ldr(r0, MemOperand(r3, kDisplacement));
2253 __ Jump(lr);
2254
2255 // Slow-case: Handle non-smi or out-of-bounds access to arguments
2256 // by calling the runtime system.
2257 __ bind(&slow);
2258 __ push(r1);
2259 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
2260}
2261
2262
whesse@chromium.org7b260152011-06-20 15:33:18 +00002263void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002264 // sp[0] : number of parameters
2265 // sp[4] : receiver displacement
2266 // sp[8] : function
2267
2268 // Check if the calling frame is an arguments adaptor frame.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002269 Label runtime;
2270 __ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2271 __ ldr(r2, MemOperand(r3, StandardFrameConstants::kContextOffset));
2272 __ cmp(r2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2273 __ b(ne, &runtime);
2274
2275 // Patch the arguments.length and the parameters pointer in the current frame.
2276 __ ldr(r2, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset));
2277 __ str(r2, MemOperand(sp, 0 * kPointerSize));
2278 __ add(r3, r3, Operand(r2, LSL, 1));
2279 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
2280 __ str(r3, MemOperand(sp, 1 * kPointerSize));
2281
2282 __ bind(&runtime);
2283 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
2284}
2285
2286
2287void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
2288 // Stack layout:
2289 // sp[0] : number of parameters (tagged)
2290 // sp[4] : address of receiver argument
2291 // sp[8] : function
2292 // Registers used over whole function:
2293 // r6 : allocated object (tagged)
2294 // r9 : mapped parameter count (tagged)
2295
2296 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
2297 // r1 = parameter count (tagged)
2298
2299 // Check if the calling frame is an arguments adaptor frame.
2300 Label runtime;
2301 Label adaptor_frame, try_allocate;
2302 __ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2303 __ ldr(r2, MemOperand(r3, StandardFrameConstants::kContextOffset));
2304 __ cmp(r2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2305 __ b(eq, &adaptor_frame);
2306
2307 // No adaptor, parameter count = argument count.
2308 __ mov(r2, r1);
2309 __ b(&try_allocate);
2310
2311 // We have an adaptor frame. Patch the parameters pointer.
2312 __ bind(&adaptor_frame);
2313 __ ldr(r2, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset));
2314 __ add(r3, r3, Operand(r2, LSL, 1));
2315 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
2316 __ str(r3, MemOperand(sp, 1 * kPointerSize));
2317
2318 // r1 = parameter count (tagged)
2319 // r2 = argument count (tagged)
2320 // Compute the mapped parameter count = min(r1, r2) in r1.
2321 __ cmp(r1, Operand(r2));
2322 __ mov(r1, Operand(r2), LeaveCC, gt);
2323
2324 __ bind(&try_allocate);
2325
2326 // Compute the sizes of backing store, parameter map, and arguments object.
2327 // 1. Parameter map, has 2 extra words containing context and backing store.
2328 const int kParameterMapHeaderSize =
2329 FixedArray::kHeaderSize + 2 * kPointerSize;
2330 // If there are no mapped parameters, we do not need the parameter_map.
2331 __ cmp(r1, Operand(Smi::FromInt(0)));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002332 __ mov(r9, Operand::Zero(), LeaveCC, eq);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002333 __ mov(r9, Operand(r1, LSL, 1), LeaveCC, ne);
2334 __ add(r9, r9, Operand(kParameterMapHeaderSize), LeaveCC, ne);
2335
2336 // 2. Backing store.
2337 __ add(r9, r9, Operand(r2, LSL, 1));
2338 __ add(r9, r9, Operand(FixedArray::kHeaderSize));
2339
2340 // 3. Arguments object.
2341 __ add(r9, r9, Operand(Heap::kArgumentsObjectSize));
2342
2343 // Do the allocation of all three objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002344 __ Allocate(r9, r0, r3, r4, &runtime, TAG_OBJECT);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002345
2346 // r0 = address of new object(s) (tagged)
2347 // r2 = argument count (tagged)
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002348 // Get the arguments boilerplate from the current native context into r4.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002349 const int kNormalOffset =
2350 Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
2351 const int kAliasedOffset =
2352 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX);
2353
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002354 __ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002355 __ ldr(r4, FieldMemOperand(r4, GlobalObject::kNativeContextOffset));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002356 __ cmp(r1, Operand::Zero());
whesse@chromium.org7b260152011-06-20 15:33:18 +00002357 __ ldr(r4, MemOperand(r4, kNormalOffset), eq);
2358 __ ldr(r4, MemOperand(r4, kAliasedOffset), ne);
2359
2360 // r0 = address of new object (tagged)
2361 // r1 = mapped parameter count (tagged)
2362 // r2 = argument count (tagged)
2363 // r4 = address of boilerplate object (tagged)
2364 // Copy the JS object part.
2365 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
2366 __ ldr(r3, FieldMemOperand(r4, i));
2367 __ str(r3, FieldMemOperand(r0, i));
2368 }
2369
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002370 // Set up the callee in-object property.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002371 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
2372 __ ldr(r3, MemOperand(sp, 2 * kPointerSize));
2373 const int kCalleeOffset = JSObject::kHeaderSize +
2374 Heap::kArgumentsCalleeIndex * kPointerSize;
2375 __ str(r3, FieldMemOperand(r0, kCalleeOffset));
2376
2377 // Use the length (smi tagged) and set that as an in-object property too.
2378 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
2379 const int kLengthOffset = JSObject::kHeaderSize +
2380 Heap::kArgumentsLengthIndex * kPointerSize;
2381 __ str(r2, FieldMemOperand(r0, kLengthOffset));
2382
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002383 // Set up the elements pointer in the allocated arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002384 // If we allocated a parameter map, r4 will point there, otherwise
2385 // it will point to the backing store.
2386 __ add(r4, r0, Operand(Heap::kArgumentsObjectSize));
2387 __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
2388
2389 // r0 = address of new object (tagged)
2390 // r1 = mapped parameter count (tagged)
2391 // r2 = argument count (tagged)
2392 // r4 = address of parameter map or backing store (tagged)
2393 // Initialize parameter map. If there are no mapped arguments, we're done.
2394 Label skip_parameter_map;
2395 __ cmp(r1, Operand(Smi::FromInt(0)));
2396 // Move backing store address to r3, because it is
2397 // expected there when filling in the unmapped arguments.
2398 __ mov(r3, r4, LeaveCC, eq);
2399 __ b(eq, &skip_parameter_map);
2400
2401 __ LoadRoot(r6, Heap::kNonStrictArgumentsElementsMapRootIndex);
2402 __ str(r6, FieldMemOperand(r4, FixedArray::kMapOffset));
2403 __ add(r6, r1, Operand(Smi::FromInt(2)));
2404 __ str(r6, FieldMemOperand(r4, FixedArray::kLengthOffset));
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002405 __ str(cp, FieldMemOperand(r4, FixedArray::kHeaderSize + 0 * kPointerSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002406 __ add(r6, r4, Operand(r1, LSL, 1));
2407 __ add(r6, r6, Operand(kParameterMapHeaderSize));
2408 __ str(r6, FieldMemOperand(r4, FixedArray::kHeaderSize + 1 * kPointerSize));
2409
2410 // Copy the parameter slots and the holes in the arguments.
2411 // We need to fill in mapped_parameter_count slots. They index the context,
2412 // where parameters are stored in reverse order, at
2413 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
2414 // The mapped parameter thus need to get indices
2415 // MIN_CONTEXT_SLOTS+parameter_count-1 ..
2416 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
2417 // We loop from right to left.
2418 Label parameters_loop, parameters_test;
2419 __ mov(r6, r1);
2420 __ ldr(r9, MemOperand(sp, 0 * kPointerSize));
2421 __ add(r9, r9, Operand(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
2422 __ sub(r9, r9, Operand(r1));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002423 __ LoadRoot(r5, Heap::kTheHoleValueRootIndex);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002424 __ add(r3, r4, Operand(r6, LSL, 1));
2425 __ add(r3, r3, Operand(kParameterMapHeaderSize));
2426
2427 // r6 = loop variable (tagged)
2428 // r1 = mapping index (tagged)
2429 // r3 = address of backing store (tagged)
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002430 // r4 = address of parameter map (tagged), which is also the address of new
2431 // object + Heap::kArgumentsObjectSize (tagged)
2432 // r0 = temporary scratch (a.o., for address calculation)
2433 // r5 = the hole value
whesse@chromium.org7b260152011-06-20 15:33:18 +00002434 __ jmp(&parameters_test);
2435
2436 __ bind(&parameters_loop);
2437 __ sub(r6, r6, Operand(Smi::FromInt(1)));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002438 __ mov(r0, Operand(r6, LSL, 1));
2439 __ add(r0, r0, Operand(kParameterMapHeaderSize - kHeapObjectTag));
2440 __ str(r9, MemOperand(r4, r0));
2441 __ sub(r0, r0, Operand(kParameterMapHeaderSize - FixedArray::kHeaderSize));
2442 __ str(r5, MemOperand(r3, r0));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002443 __ add(r9, r9, Operand(Smi::FromInt(1)));
2444 __ bind(&parameters_test);
2445 __ cmp(r6, Operand(Smi::FromInt(0)));
2446 __ b(ne, &parameters_loop);
2447
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002448 // Restore r0 = new object (tagged)
2449 __ sub(r0, r4, Operand(Heap::kArgumentsObjectSize));
2450
whesse@chromium.org7b260152011-06-20 15:33:18 +00002451 __ bind(&skip_parameter_map);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002452 // r0 = address of new object (tagged)
whesse@chromium.org7b260152011-06-20 15:33:18 +00002453 // r2 = argument count (tagged)
2454 // r3 = address of backing store (tagged)
2455 // r5 = scratch
2456 // Copy arguments header and remaining slots (if there are any).
2457 __ LoadRoot(r5, Heap::kFixedArrayMapRootIndex);
2458 __ str(r5, FieldMemOperand(r3, FixedArray::kMapOffset));
2459 __ str(r2, FieldMemOperand(r3, FixedArray::kLengthOffset));
2460
2461 Label arguments_loop, arguments_test;
2462 __ mov(r9, r1);
2463 __ ldr(r4, MemOperand(sp, 1 * kPointerSize));
2464 __ sub(r4, r4, Operand(r9, LSL, 1));
2465 __ jmp(&arguments_test);
2466
2467 __ bind(&arguments_loop);
2468 __ sub(r4, r4, Operand(kPointerSize));
2469 __ ldr(r6, MemOperand(r4, 0));
2470 __ add(r5, r3, Operand(r9, LSL, 1));
2471 __ str(r6, FieldMemOperand(r5, FixedArray::kHeaderSize));
2472 __ add(r9, r9, Operand(Smi::FromInt(1)));
2473
2474 __ bind(&arguments_test);
2475 __ cmp(r9, Operand(r2));
2476 __ b(lt, &arguments_loop);
2477
2478 // Return and remove the on-stack parameters.
2479 __ add(sp, sp, Operand(3 * kPointerSize));
2480 __ Ret();
2481
2482 // Do the runtime call to allocate the arguments object.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002483 // r0 = address of new object (tagged)
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002484 // r2 = argument count (tagged)
whesse@chromium.org7b260152011-06-20 15:33:18 +00002485 __ bind(&runtime);
2486 __ str(r2, MemOperand(sp, 0 * kPointerSize)); // Patch argument count.
2487 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
2488}
2489
2490
2491void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
2492 // sp[0] : number of parameters
2493 // sp[4] : receiver displacement
2494 // sp[8] : function
2495 // Check if the calling frame is an arguments adaptor frame.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002496 Label adaptor_frame, try_allocate, runtime;
2497 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2498 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
2499 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2500 __ b(eq, &adaptor_frame);
2501
2502 // Get the length from the frame.
2503 __ ldr(r1, MemOperand(sp, 0));
2504 __ b(&try_allocate);
2505
2506 // Patch the arguments.length and the parameters pointer.
2507 __ bind(&adaptor_frame);
2508 __ ldr(r1, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
2509 __ str(r1, MemOperand(sp, 0));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002510 __ add(r3, r2, Operand::PointerOffsetFromSmiKey(r1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002511 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
2512 __ str(r3, MemOperand(sp, 1 * kPointerSize));
2513
2514 // Try the new space allocation. Start out with computing the size
2515 // of the arguments object and the elements array in words.
2516 Label add_arguments_object;
2517 __ bind(&try_allocate);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002518 __ SmiUntag(r1, SetCC);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002519 __ b(eq, &add_arguments_object);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002520 __ add(r1, r1, Operand(FixedArray::kHeaderSize / kPointerSize));
2521 __ bind(&add_arguments_object);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002522 __ add(r1, r1, Operand(Heap::kArgumentsObjectSizeStrict / kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002523
2524 // Do the allocation of both objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002525 __ Allocate(r1, r0, r2, r3, &runtime,
2526 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002527
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002528 // Get the arguments boilerplate from the current native context.
2529 __ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2530 __ ldr(r4, FieldMemOperand(r4, GlobalObject::kNativeContextOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002531 __ ldr(r4, MemOperand(r4, Context::SlotOffset(
2532 Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002533
2534 // Copy the JS object part.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002535 __ CopyFields(r0, r4, d0, JSObject::kHeaderSize / kPointerSize);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002536
ricow@chromium.org65fae842010-08-25 15:26:24 +00002537 // Get the length (smi tagged) and set that as an in-object property too.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002538 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002539 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002540 __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize +
whesse@chromium.org7b260152011-06-20 15:33:18 +00002541 Heap::kArgumentsLengthIndex * kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002542
2543 // If there are no actual arguments, we're done.
2544 Label done;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002545 __ cmp(r1, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002546 __ b(eq, &done);
2547
2548 // Get the parameters pointer from the stack.
2549 __ ldr(r2, MemOperand(sp, 1 * kPointerSize));
2550
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002551 // Set up the elements pointer in the allocated arguments object and
ricow@chromium.org65fae842010-08-25 15:26:24 +00002552 // initialize the header in the elements fixed array.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002553 __ add(r4, r0, Operand(Heap::kArgumentsObjectSizeStrict));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002554 __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
2555 __ LoadRoot(r3, Heap::kFixedArrayMapRootIndex);
2556 __ str(r3, FieldMemOperand(r4, FixedArray::kMapOffset));
2557 __ str(r1, FieldMemOperand(r4, FixedArray::kLengthOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002558 __ SmiUntag(r1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002559
2560 // Copy the fixed array slots.
2561 Label loop;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002562 // Set up r4 to point to the first array slot.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002563 __ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
2564 __ bind(&loop);
2565 // Pre-decrement r2 with kPointerSize on each iteration.
2566 // Pre-decrement in order to skip receiver.
2567 __ ldr(r3, MemOperand(r2, kPointerSize, NegPreIndex));
2568 // Post-increment r4 with kPointerSize on each iteration.
2569 __ str(r3, MemOperand(r4, kPointerSize, PostIndex));
2570 __ sub(r1, r1, Operand(1));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002571 __ cmp(r1, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002572 __ b(ne, &loop);
2573
2574 // Return and remove the on-stack parameters.
2575 __ bind(&done);
2576 __ add(sp, sp, Operand(3 * kPointerSize));
2577 __ Ret();
2578
2579 // Do the runtime call to allocate the arguments object.
2580 __ bind(&runtime);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002581 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002582}
2583
2584
2585void RegExpExecStub::Generate(MacroAssembler* masm) {
2586 // Just jump directly to runtime if native RegExp is not selected at compile
2587 // time or if regexp entry in generated code is turned off runtime switch or
2588 // at compilation.
2589#ifdef V8_INTERPRETED_REGEXP
2590 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
2591#else // V8_INTERPRETED_REGEXP
ricow@chromium.org65fae842010-08-25 15:26:24 +00002592
2593 // Stack frame on entry.
2594 // sp[0]: last_match_info (expected JSArray)
2595 // sp[4]: previous index
2596 // sp[8]: subject string
2597 // sp[12]: JSRegExp object
2598
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002599 const int kLastMatchInfoOffset = 0 * kPointerSize;
2600 const int kPreviousIndexOffset = 1 * kPointerSize;
2601 const int kSubjectOffset = 2 * kPointerSize;
2602 const int kJSRegExpOffset = 3 * kPointerSize;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002603
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002604 Label runtime;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002605 // Allocation of registers for this function. These are in callee save
2606 // registers and will be preserved by the call to the native RegExp code, as
2607 // this code is called using the normal C calling convention. When calling
2608 // directly from generated code the native RegExp code will not do a GC and
2609 // therefore the content of these registers are safe to use after the call.
2610 Register subject = r4;
2611 Register regexp_data = r5;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002612 Register last_match_info_elements = no_reg; // will be r6;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002613
2614 // Ensure that a RegExp stack is allocated.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002615 Isolate* isolate = masm->isolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002616 ExternalReference address_of_regexp_stack_memory_address =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002617 ExternalReference::address_of_regexp_stack_memory_address(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002618 ExternalReference address_of_regexp_stack_memory_size =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002619 ExternalReference::address_of_regexp_stack_memory_size(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002620 __ mov(r0, Operand(address_of_regexp_stack_memory_size));
2621 __ ldr(r0, MemOperand(r0, 0));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002622 __ cmp(r0, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002623 __ b(eq, &runtime);
2624
2625 // Check that the first argument is a JSRegExp object.
2626 __ ldr(r0, MemOperand(sp, kJSRegExpOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002627 __ JumpIfSmi(r0, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002628 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
2629 __ b(ne, &runtime);
2630
2631 // Check that the RegExp has been compiled (data contains a fixed array).
2632 __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset));
2633 if (FLAG_debug_code) {
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002634 __ SmiTst(regexp_data);
danno@chromium.org59400602013-08-13 17:09:37 +00002635 __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002636 __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE);
danno@chromium.org59400602013-08-13 17:09:37 +00002637 __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002638 }
2639
2640 // regexp_data: RegExp data (FixedArray)
2641 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
2642 __ ldr(r0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset));
2643 __ cmp(r0, Operand(Smi::FromInt(JSRegExp::IRREGEXP)));
2644 __ b(ne, &runtime);
2645
2646 // regexp_data: RegExp data (FixedArray)
2647 // Check that the number of captures fit in the static offsets vector buffer.
2648 __ ldr(r2,
2649 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002650 // Check (number_of_captures + 1) * 2 <= offsets vector size
2651 // Or number_of_captures * 2 <= offsets vector size - 2
2652 // Multiplying by 2 comes for free since r2 is smi-tagged.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002653 STATIC_ASSERT(kSmiTag == 0);
2654 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002655 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
2656 __ cmp(r2, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize - 2));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002657 __ b(hi, &runtime);
2658
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002659 // Reset offset for possibly sliced string.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002660 __ mov(r9, Operand::Zero());
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002661 __ ldr(subject, MemOperand(sp, kSubjectOffset));
2662 __ JumpIfSmi(subject, &runtime);
2663 __ mov(r3, subject); // Make a copy of the original subject string.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002664 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset));
2665 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002666 // subject: subject string
2667 // r3: subject string
2668 // r0: subject string instance type
2669 // regexp_data: RegExp data (FixedArray)
2670 // Handle subject string according to its encoding and representation:
2671 // (1) Sequential string? If yes, go to (5).
2672 // (2) Anything but sequential or cons? If yes, go to (6).
2673 // (3) Cons string. If the string is flat, replace subject with first string.
2674 // Otherwise bailout.
2675 // (4) Is subject external? If yes, go to (7).
2676 // (5) Sequential string. Load regexp code according to encoding.
2677 // (E) Carry on.
2678 /// [...]
2679
2680 // Deferred code at the end of the stub:
2681 // (6) Not a long external string? If yes, go to (8).
2682 // (7) External string. Make it, offset-wise, look like a sequential string.
2683 // Go to (5).
2684 // (8) Short external string or not a string? If yes, bail out to runtime.
2685 // (9) Sliced string. Replace subject with parent. Go to (4).
2686
2687 Label seq_string /* 5 */, external_string /* 7 */,
2688 check_underlying /* 4 */, not_seq_nor_cons /* 6 */,
2689 not_long_external /* 8 */;
2690
2691 // (1) Sequential string? If yes, go to (5).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002692 __ and_(r1,
2693 r0,
2694 Operand(kIsNotStringMask |
2695 kStringRepresentationMask |
2696 kShortExternalStringMask),
2697 SetCC);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002698 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002699 __ b(eq, &seq_string); // Go to (5).
ricow@chromium.org65fae842010-08-25 15:26:24 +00002700
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002701 // (2) Anything but sequential or cons? If yes, go to (6).
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002702 STATIC_ASSERT(kConsStringTag < kExternalStringTag);
2703 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002704 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
2705 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002706 __ cmp(r1, Operand(kExternalStringTag));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002707 __ b(ge, &not_seq_nor_cons); // Go to (6).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002708
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002709 // (3) Cons string. Check that it's flat.
2710 // Replace subject with first string and reload instance type.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002711 __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002712 __ CompareRoot(r0, Heap::kempty_stringRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002713 __ b(ne, &runtime);
2714 __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002715
2716 // (4) Is subject external? If yes, go to (7).
2717 __ bind(&check_underlying);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002718 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset));
2719 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002720 STATIC_ASSERT(kSeqStringTag == 0);
2721 __ tst(r0, Operand(kStringRepresentationMask));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002722 // The underlying external string is never a short external string.
2723 STATIC_CHECK(ExternalString::kMaxShortLength < ConsString::kMinLength);
2724 STATIC_CHECK(ExternalString::kMaxShortLength < SlicedString::kMinLength);
2725 __ b(ne, &external_string); // Go to (7).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002726
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002727 // (5) Sequential string. Load regexp code according to encoding.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002728 __ bind(&seq_string);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002729 // subject: sequential subject string (or look-alike, external string)
2730 // r3: original subject string
2731 // Load previous index and check range before r3 is overwritten. We have to
2732 // use r3 instead of subject here because subject might have been only made
2733 // to look like a sequential string when it actually is an external string.
2734 __ ldr(r1, MemOperand(sp, kPreviousIndexOffset));
2735 __ JumpIfNotSmi(r1, &runtime);
2736 __ ldr(r3, FieldMemOperand(r3, String::kLengthOffset));
2737 __ cmp(r3, Operand(r1));
2738 __ b(ls, &runtime);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002739 __ SmiUntag(r1);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002740
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002741 STATIC_ASSERT(4 == kOneByteStringTag);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002742 STATIC_ASSERT(kTwoByteStringTag == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002743 __ and_(r0, r0, Operand(kStringEncodingMask));
2744 __ mov(r3, Operand(r0, ASR, 2), SetCC);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002745 __ ldr(r6, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne);
2746 __ ldr(r6, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002747
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002748 // (E) Carry on. String handling is done.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002749 // r6: irregexp code
ricow@chromium.org65fae842010-08-25 15:26:24 +00002750 // Check that the irregexp code has been generated for the actual string
2751 // encoding. If it has, the field contains a code object otherwise it contains
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002752 // a smi (code flushing support).
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002753 __ JumpIfSmi(r6, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002754
ricow@chromium.org65fae842010-08-25 15:26:24 +00002755 // r1: previous index
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002756 // r3: encoding of subject string (1 if ASCII, 0 if two_byte);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002757 // r6: code
ricow@chromium.org65fae842010-08-25 15:26:24 +00002758 // subject: Subject string
2759 // regexp_data: RegExp data (FixedArray)
2760 // All checks done. Now push arguments for native regexp code.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002761 __ IncrementCounter(isolate->counters()->regexp_entry_native(), 1, r0, r2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002763 // Isolates: note we add an additional parameter here (isolate pointer).
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002764 const int kRegExpExecuteArguments = 9;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002765 const int kParameterRegisters = 4;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002766 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002767
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002768 // Stack pointer now points to cell where return address is to be written.
2769 // Arguments are before that on the stack or in registers.
2770
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002771 // Argument 9 (sp[20]): Pass current isolate address.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002772 __ mov(r0, Operand(ExternalReference::isolate_address(isolate)));
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002773 __ str(r0, MemOperand(sp, 5 * kPointerSize));
2774
2775 // Argument 8 (sp[16]): Indicate that this is a direct call from JavaScript.
2776 __ mov(r0, Operand(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002777 __ str(r0, MemOperand(sp, 4 * kPointerSize));
2778
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002779 // Argument 7 (sp[12]): Start (high end) of backtracking stack memory area.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002780 __ mov(r0, Operand(address_of_regexp_stack_memory_address));
2781 __ ldr(r0, MemOperand(r0, 0));
2782 __ mov(r2, Operand(address_of_regexp_stack_memory_size));
2783 __ ldr(r2, MemOperand(r2, 0));
2784 __ add(r0, r0, Operand(r2));
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002785 __ str(r0, MemOperand(sp, 3 * kPointerSize));
2786
2787 // Argument 6: Set the number of capture registers to zero to force global
2788 // regexps to behave as non-global. This does not affect non-global regexps.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002789 __ mov(r0, Operand::Zero());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002790 __ str(r0, MemOperand(sp, 2 * kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002791
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002792 // Argument 5 (sp[4]): static offsets vector buffer.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002793 __ mov(r0,
2794 Operand(ExternalReference::address_of_static_offsets_vector(isolate)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002795 __ str(r0, MemOperand(sp, 1 * kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002796
2797 // For arguments 4 and 3 get string length, calculate start of string data and
2798 // calculate the shift of the index (0 for ASCII and 1 for two byte).
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002799 __ add(r7, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002800 __ eor(r3, r3, Operand(1));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002801 // Load the length from the original subject string from the previous stack
2802 // frame. Therefore we have to use fp, which points exactly to two pointer
2803 // sizes below the previous sp. (Because creating a new stack frame pushes
2804 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.)
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002805 __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002806 // If slice offset is not 0, load the length from the original sliced string.
2807 // Argument 4, r3: End of string data
2808 // Argument 3, r2: Start of string data
2809 // Prepare start and end index of the input.
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002810 __ add(r9, r7, Operand(r9, LSL, r3));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002811 __ add(r2, r9, Operand(r1, LSL, r3));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002812
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002813 __ ldr(r7, FieldMemOperand(subject, String::kLengthOffset));
2814 __ SmiUntag(r7);
2815 __ add(r3, r9, Operand(r7, LSL, r3));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002816
2817 // Argument 2 (r1): Previous index.
2818 // Already there
2819
2820 // Argument 1 (r0): Subject string.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002821 __ mov(r0, subject);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002822
2823 // Locate the code entry and call it.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002824 __ add(r6, r6, Operand(Code::kHeaderSize - kHeapObjectTag));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002825 DirectCEntryStub stub;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002826 stub.GenerateCall(masm, r6);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002827
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002828 __ LeaveExitFrame(false, no_reg, true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002829
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002830 last_match_info_elements = r6;
2831
ricow@chromium.org65fae842010-08-25 15:26:24 +00002832 // r0: result
2833 // subject: subject string (callee saved)
2834 // regexp_data: RegExp data (callee saved)
2835 // last_match_info_elements: Last match info elements (callee saved)
ricow@chromium.org65fae842010-08-25 15:26:24 +00002836 // Check the result.
2837 Label success;
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002838 __ cmp(r0, Operand(1));
2839 // We expect exactly one result since we force the called regexp to behave
2840 // as non-global.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002841 __ b(eq, &success);
2842 Label failure;
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002843 __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002844 __ b(eq, &failure);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002845 __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002846 // If not exception it can only be retry. Handle that in the runtime system.
2847 __ b(ne, &runtime);
2848 // Result must now be exception. If there is no pending exception already a
2849 // stack overflow (on the backtrack stack) was detected in RegExp code but
2850 // haven't created the exception yet. Handle that in the runtime system.
2851 // TODO(592): Rerunning the RegExp to get the stack overflow exception.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002852 __ mov(r1, Operand(isolate->factory()->the_hole_value()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002853 __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002854 isolate)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002855 __ ldr(r0, MemOperand(r2, 0));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002856 __ cmp(r0, r1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002857 __ b(eq, &runtime);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002858
2859 __ str(r1, MemOperand(r2, 0)); // Clear pending exception.
2860
2861 // Check if the exception is a termination. If so, throw as uncatchable.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002862 __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex);
2863
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002864 Label termination_exception;
2865 __ b(eq, &termination_exception);
2866
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002867 __ Throw(r0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002868
2869 __ bind(&termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002870 __ ThrowUncatchable(r0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002871
ricow@chromium.org65fae842010-08-25 15:26:24 +00002872 __ bind(&failure);
2873 // For failure and exception return null.
danno@chromium.org160a7b02011-04-18 15:51:38 +00002874 __ mov(r0, Operand(masm->isolate()->factory()->null_value()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002875 __ add(sp, sp, Operand(4 * kPointerSize));
2876 __ Ret();
2877
2878 // Process the result from the native regexp code.
2879 __ bind(&success);
2880 __ ldr(r1,
2881 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
2882 // Calculate number of capture registers (number_of_captures + 1) * 2.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002883 // Multiplying by 2 comes for free since r1 is smi-tagged.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002884 STATIC_ASSERT(kSmiTag == 0);
2885 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
2886 __ add(r1, r1, Operand(2)); // r1 was a smi.
2887
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002888 __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset));
2889 __ JumpIfSmi(r0, &runtime);
2890 __ CompareObjectType(r0, r2, r2, JS_ARRAY_TYPE);
2891 __ b(ne, &runtime);
2892 // Check that the JSArray is in fast case.
2893 __ ldr(last_match_info_elements,
2894 FieldMemOperand(r0, JSArray::kElementsOffset));
2895 __ ldr(r0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
2896 __ CompareRoot(r0, Heap::kFixedArrayMapRootIndex);
2897 __ b(ne, &runtime);
2898 // Check that the last match info has space for the capture registers and the
2899 // additional information.
2900 __ ldr(r0,
2901 FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset));
2902 __ add(r2, r1, Operand(RegExpImpl::kLastMatchOverhead));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002903 __ cmp(r2, Operand::SmiUntag(r0));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002904 __ b(gt, &runtime);
2905
ricow@chromium.org65fae842010-08-25 15:26:24 +00002906 // r1: number of capture registers
2907 // r4: subject string
2908 // Store the capture count.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002909 __ SmiTag(r2, r1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002910 __ str(r2, FieldMemOperand(last_match_info_elements,
2911 RegExpImpl::kLastCaptureCountOffset));
2912 // Store last subject and last input.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002913 __ str(subject,
2914 FieldMemOperand(last_match_info_elements,
2915 RegExpImpl::kLastSubjectOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002916 __ mov(r2, subject);
2917 __ RecordWriteField(last_match_info_elements,
2918 RegExpImpl::kLastSubjectOffset,
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002919 subject,
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002920 r3,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002921 kLRHasNotBeenSaved,
2922 kDontSaveFPRegs);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002923 __ mov(subject, r2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002924 __ str(subject,
2925 FieldMemOperand(last_match_info_elements,
2926 RegExpImpl::kLastInputOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002927 __ RecordWriteField(last_match_info_elements,
2928 RegExpImpl::kLastInputOffset,
2929 subject,
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002930 r3,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002931 kLRHasNotBeenSaved,
2932 kDontSaveFPRegs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002933
2934 // Get the static offsets vector filled by the native regexp code.
2935 ExternalReference address_of_static_offsets_vector =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002936 ExternalReference::address_of_static_offsets_vector(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002937 __ mov(r2, Operand(address_of_static_offsets_vector));
2938
2939 // r1: number of capture registers
2940 // r2: offsets vector
2941 Label next_capture, done;
2942 // Capture register counter starts from number of capture registers and
2943 // counts down until wraping after zero.
2944 __ add(r0,
2945 last_match_info_elements,
2946 Operand(RegExpImpl::kFirstCaptureOffset - kHeapObjectTag));
2947 __ bind(&next_capture);
2948 __ sub(r1, r1, Operand(1), SetCC);
2949 __ b(mi, &done);
2950 // Read the value from the static offsets vector buffer.
2951 __ ldr(r3, MemOperand(r2, kPointerSize, PostIndex));
2952 // Store the smi value in the last match info.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002953 __ SmiTag(r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002954 __ str(r3, MemOperand(r0, kPointerSize, PostIndex));
2955 __ jmp(&next_capture);
2956 __ bind(&done);
2957
2958 // Return last match info.
2959 __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset));
2960 __ add(sp, sp, Operand(4 * kPointerSize));
2961 __ Ret();
2962
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002963 // Do the runtime call to execute the regexp.
2964 __ bind(&runtime);
2965 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
2966
2967 // Deferred code for string handling.
2968 // (6) Not a long external string? If yes, go to (8).
2969 __ bind(&not_seq_nor_cons);
2970 // Compare flags are still set.
2971 __ b(gt, &not_long_external); // Go to (8).
2972
2973 // (7) External string. Make it, offset-wise, look like a sequential string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002974 __ bind(&external_string);
2975 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset));
2976 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
2977 if (FLAG_debug_code) {
2978 // Assert that we do not have a cons or slice (indirect strings) here.
2979 // Sequential strings have already been ruled out.
2980 __ tst(r0, Operand(kIsIndirectStringMask));
danno@chromium.org59400602013-08-13 17:09:37 +00002981 __ Assert(eq, kExternalStringExpectedButNotFound);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002982 }
2983 __ ldr(subject,
2984 FieldMemOperand(subject, ExternalString::kResourceDataOffset));
2985 // Move the pointer so that offset-wise, it looks like a sequential string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002986 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002987 __ sub(subject,
2988 subject,
2989 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002990 __ jmp(&seq_string); // Go to (5).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002991
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002992 // (8) Short external string or not a string? If yes, bail out to runtime.
2993 __ bind(&not_long_external);
2994 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
2995 __ tst(r1, Operand(kIsNotStringMask | kShortExternalStringMask));
2996 __ b(ne, &runtime);
2997
2998 // (9) Sliced string. Replace subject with parent. Go to (4).
2999 // Load offset into r9 and replace subject string with parent.
3000 __ ldr(r9, FieldMemOperand(subject, SlicedString::kOffsetOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003001 __ SmiUntag(r9);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003002 __ ldr(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
3003 __ jmp(&check_underlying); // Go to (4).
ricow@chromium.org65fae842010-08-25 15:26:24 +00003004#endif // V8_INTERPRETED_REGEXP
3005}
3006
3007
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003008void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
3009 const int kMaxInlineLength = 100;
3010 Label slowcase;
3011 Label done;
danno@chromium.org160a7b02011-04-18 15:51:38 +00003012 Factory* factory = masm->isolate()->factory();
3013
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003014 __ ldr(r1, MemOperand(sp, kPointerSize * 2));
3015 STATIC_ASSERT(kSmiTag == 0);
3016 STATIC_ASSERT(kSmiTagSize == 1);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003017 __ JumpIfNotSmi(r1, &slowcase);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003018 __ cmp(r1, Operand(Smi::FromInt(kMaxInlineLength)));
3019 __ b(hi, &slowcase);
3020 // Smi-tagging is equivalent to multiplying by 2.
3021 // Allocate RegExpResult followed by FixedArray with size in ebx.
3022 // JSArray: [Map][empty properties][Elements][Length-smi][index][input]
3023 // Elements: [Map][Length][..elements..]
3024 // Size of JSArray with two in-object properties and the header of a
3025 // FixedArray.
3026 int objects_size =
3027 (JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize;
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003028 __ SmiUntag(r5, r1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003029 __ add(r2, r5, Operand(objects_size));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003030 __ Allocate(
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003031 r2, // In: Size, in words.
3032 r0, // Out: Start of allocation (tagged).
3033 r3, // Scratch register.
3034 r4, // Scratch register.
3035 &slowcase,
3036 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
3037 // r0: Start of allocated area, object-tagged.
3038 // r1: Number of elements in array, as smi.
3039 // r5: Number of elements, untagged.
3040
3041 // Set JSArray map to global.regexp_result_map().
3042 // Set empty properties FixedArray.
3043 // Set elements to point to FixedArray allocated right after the JSArray.
3044 // Interleave operations for better latency.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003045 __ ldr(r2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003046 __ add(r3, r0, Operand(JSRegExpResult::kSize));
danno@chromium.org160a7b02011-04-18 15:51:38 +00003047 __ mov(r4, Operand(factory->empty_fixed_array()));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003048 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kNativeContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003049 __ str(r3, FieldMemOperand(r0, JSObject::kElementsOffset));
3050 __ ldr(r2, ContextOperand(r2, Context::REGEXP_RESULT_MAP_INDEX));
3051 __ str(r4, FieldMemOperand(r0, JSObject::kPropertiesOffset));
3052 __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
3053
3054 // Set input, index and length fields from arguments.
3055 __ ldr(r1, MemOperand(sp, kPointerSize * 0));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003056 __ ldr(r2, MemOperand(sp, kPointerSize * 1));
3057 __ ldr(r6, MemOperand(sp, kPointerSize * 2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003058 __ str(r1, FieldMemOperand(r0, JSRegExpResult::kInputOffset));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003059 __ str(r2, FieldMemOperand(r0, JSRegExpResult::kIndexOffset));
3060 __ str(r6, FieldMemOperand(r0, JSArray::kLengthOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003061
3062 // Fill out the elements FixedArray.
3063 // r0: JSArray, tagged.
3064 // r3: FixedArray, tagged.
3065 // r5: Number of elements in array, untagged.
3066
3067 // Set map.
danno@chromium.org160a7b02011-04-18 15:51:38 +00003068 __ mov(r2, Operand(factory->fixed_array_map()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003069 __ str(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
3070 // Set FixedArray length.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003071 __ SmiTag(r6, r5);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003072 __ str(r6, FieldMemOperand(r3, FixedArray::kLengthOffset));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003073 // Fill contents of fixed-array with undefined.
3074 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003075 __ add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003076 // Fill fixed array elements with undefined.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003077 // r0: JSArray, tagged.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003078 // r2: undefined.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003079 // r3: Start of elements in FixedArray.
3080 // r5: Number of elements to fill.
3081 Label loop;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003082 __ cmp(r5, Operand::Zero());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003083 __ bind(&loop);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003084 __ b(le, &done); // Jump if r5 is negative or zero.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003085 __ sub(r5, r5, Operand(1), SetCC);
3086 __ str(r2, MemOperand(r3, r5, LSL, kPointerSizeLog2));
3087 __ jmp(&loop);
3088
3089 __ bind(&done);
3090 __ add(sp, sp, Operand(3 * kPointerSize));
3091 __ Ret();
3092
3093 __ bind(&slowcase);
3094 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1);
3095}
3096
3097
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003098static void GenerateRecordCallTarget(MacroAssembler* masm) {
3099 // Cache the called function in a global property cell. Cache states
3100 // are uninitialized, monomorphic (indicated by a JSFunction), and
3101 // megamorphic.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003102 // r0 : number of arguments to the construct function
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003103 // r1 : the function to call
3104 // r2 : cache cell for call target
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003105 Label initialize, done, miss, megamorphic, not_array_function;
3106
3107 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
3108 masm->isolate()->heap()->undefined_value());
3109 ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()),
3110 masm->isolate()->heap()->the_hole_value());
3111
3112 // Load the cache state into r3.
danno@chromium.org41728482013-06-12 22:31:22 +00003113 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003114
3115 // A monomorphic cache hit or an already megamorphic state: invoke the
3116 // function without changing the state.
3117 __ cmp(r3, r1);
3118 __ b(eq, &done);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003119
danno@chromium.orgbee51992013-07-10 14:57:15 +00003120 // If we came here, we need to see if we are the array function.
3121 // If we didn't have a matching function, and we didn't find the megamorph
3122 // sentinel, then we have in the cell either some other function or an
3123 // AllocationSite. Do a map check on the object in ecx.
danno@chromium.orgbee51992013-07-10 14:57:15 +00003124 __ ldr(r5, FieldMemOperand(r3, 0));
3125 __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
3126 __ b(ne, &miss);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003127
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003128 // Make sure the function is the Array() function
3129 __ LoadArrayFunction(r3);
3130 __ cmp(r1, r3);
3131 __ b(ne, &megamorphic);
3132 __ jmp(&done);
3133
3134 __ bind(&miss);
3135
3136 // A monomorphic miss (i.e, here the cache is not uninitialized) goes
3137 // megamorphic.
3138 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
3139 __ b(eq, &initialize);
3140 // MegamorphicSentinel is an immortal immovable object (undefined) so no
3141 // write-barrier is needed.
3142 __ bind(&megamorphic);
3143 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
danno@chromium.org41728482013-06-12 22:31:22 +00003144 __ str(ip, FieldMemOperand(r2, Cell::kValueOffset));
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003145 __ jmp(&done);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003146
3147 // An uninitialized cache is patched with the function or sentinel to
3148 // indicate the ElementsKind if function is the Array constructor.
3149 __ bind(&initialize);
3150 // Make sure the function is the Array() function
3151 __ LoadArrayFunction(r3);
3152 __ cmp(r1, r3);
3153 __ b(ne, &not_array_function);
3154
danno@chromium.orgbee51992013-07-10 14:57:15 +00003155 // The target function is the Array constructor,
3156 // Create an AllocationSite if we don't already have it, store it in the cell
3157 {
3158 FrameScope scope(masm, StackFrame::INTERNAL);
3159
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003160 // Arguments register must be smi-tagged to call out.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00003161 __ SmiTag(r0);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003162 __ Push(r2, r1, r0);
danno@chromium.orgbee51992013-07-10 14:57:15 +00003163
3164 CreateAllocationSiteStub create_stub;
3165 __ CallStub(&create_stub);
3166
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003167 __ Pop(r2, r1, r0);
verwaest@chromium.org662436e2013-08-28 08:41:27 +00003168 __ SmiUntag(r0);
danno@chromium.orgbee51992013-07-10 14:57:15 +00003169 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003170 __ b(&done);
3171
3172 __ bind(&not_array_function);
danno@chromium.org41728482013-06-12 22:31:22 +00003173 __ str(r1, FieldMemOperand(r2, Cell::kValueOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003174 // No need for a write barrier here - cells are rescanned.
3175
3176 __ bind(&done);
3177}
3178
3179
ricow@chromium.org65fae842010-08-25 15:26:24 +00003180void CallFunctionStub::Generate(MacroAssembler* masm) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003181 // r1 : the function to call
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003182 // r2 : cache cell for call target
lrn@chromium.org34e60782011-09-15 07:25:40 +00003183 Label slow, non_function;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003184
ricow@chromium.org65fae842010-08-25 15:26:24 +00003185 // Check that the function is really a JavaScript function.
3186 // r1: pushed function (to be verified)
lrn@chromium.org34e60782011-09-15 07:25:40 +00003187 __ JumpIfSmi(r1, &non_function);
rossberg@chromium.org9ed27462014-01-07 14:16:41 +00003188
3189 // The receiver might implicitly be the global object. This is
3190 // indicated by passing the hole as the receiver to the call
3191 // function stub.
3192 if (ReceiverMightBeImplicit() || ReceiverIsImplicit()) {
3193 Label try_call, call, patch_current_context;
3194 if (ReceiverMightBeImplicit()) {
3195 // Get the receiver from the stack.
3196 // function, receiver [, arguments]
3197 __ ldr(r4, MemOperand(sp, argc_ * kPointerSize));
3198 // Call as function is indicated with the hole.
3199 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
3200 __ b(ne, &try_call);
3201 }
3202 // Patch the receiver on the stack with the global receiver object.
3203 // Goto slow case if we do not have a function.
3204 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
3205 __ b(ne, &patch_current_context);
3206 CallStubCompiler::FetchGlobalProxy(masm, r3, r1);
3207 __ str(r3, MemOperand(sp, argc_ * kPointerSize));
3208 __ jmp(&call);
3209
3210 __ bind(&patch_current_context);
3211 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
3212 __ str(r4, MemOperand(sp, argc_ * kPointerSize));
3213 __ jmp(&slow);
3214
3215 __ bind(&try_call);
3216 // Get the map of the function object.
3217 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
3218 __ b(ne, &slow);
3219
3220 __ bind(&call);
3221 } else {
3222 // Get the map of the function object.
3223 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
3224 __ b(ne, &slow);
3225 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003226
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003227 if (RecordCallTarget()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003228 GenerateRecordCallTarget(masm);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003229 }
3230
ricow@chromium.org65fae842010-08-25 15:26:24 +00003231 // Fast-case: Invoke the function now.
3232 // r1: pushed function
3233 ParameterCount actual(argc_);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003234
3235 if (ReceiverMightBeImplicit()) {
3236 Label call_as_function;
3237 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
3238 __ b(eq, &call_as_function);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003239 __ InvokeFunction(r1,
3240 actual,
3241 JUMP_FUNCTION,
3242 NullCallWrapper(),
3243 CALL_AS_METHOD);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003244 __ bind(&call_as_function);
3245 }
3246 __ InvokeFunction(r1,
3247 actual,
3248 JUMP_FUNCTION,
3249 NullCallWrapper(),
3250 CALL_AS_FUNCTION);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003251
3252 // Slow-case: Non-function called.
3253 __ bind(&slow);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003254 if (RecordCallTarget()) {
3255 // If there is a call target cache, mark it megamorphic in the
3256 // non-function case. MegamorphicSentinel is an immortal immovable
3257 // object (undefined) so no write barrier is needed.
3258 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
3259 masm->isolate()->heap()->undefined_value());
3260 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
danno@chromium.org41728482013-06-12 22:31:22 +00003261 __ str(ip, FieldMemOperand(r2, Cell::kValueOffset));
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003262 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00003263 // Check for function proxy.
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003264 __ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE));
lrn@chromium.org34e60782011-09-15 07:25:40 +00003265 __ b(ne, &non_function);
3266 __ push(r1); // put proxy as additional argument
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003267 __ mov(r0, Operand(argc_ + 1, RelocInfo::NONE32));
3268 __ mov(r2, Operand::Zero());
lrn@chromium.org34e60782011-09-15 07:25:40 +00003269 __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
rossberg@chromium.org9ed27462014-01-07 14:16:41 +00003270 __ SetCallKind(r5, CALL_AS_FUNCTION);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003271 {
3272 Handle<Code> adaptor =
3273 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
3274 __ Jump(adaptor, RelocInfo::CODE_TARGET);
3275 }
3276
ricow@chromium.org65fae842010-08-25 15:26:24 +00003277 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
3278 // of the original receiver from the call site).
lrn@chromium.org34e60782011-09-15 07:25:40 +00003279 __ bind(&non_function);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003280 __ str(r1, MemOperand(sp, argc_ * kPointerSize));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003281 __ mov(r0, Operand(argc_)); // Set up the number of arguments.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003282 __ mov(r2, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003283 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003284 __ SetCallKind(r5, CALL_AS_METHOD);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003285 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
ricow@chromium.org65fae842010-08-25 15:26:24 +00003286 RelocInfo::CODE_TARGET);
3287}
3288
3289
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003290void CallConstructStub::Generate(MacroAssembler* masm) {
3291 // r0 : number of arguments
3292 // r1 : the function to call
3293 // r2 : cache cell for call target
3294 Label slow, non_function_call;
3295
3296 // Check that the function is not a smi.
3297 __ JumpIfSmi(r1, &non_function_call);
3298 // Check that the function is a JSFunction.
3299 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
3300 __ b(ne, &slow);
3301
3302 if (RecordCallTarget()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003303 GenerateRecordCallTarget(masm);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003304 }
3305
3306 // Jump to the function-specific construct stub.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003307 Register jmp_reg = r3;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003308 __ ldr(jmp_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
3309 __ ldr(jmp_reg, FieldMemOperand(jmp_reg,
3310 SharedFunctionInfo::kConstructStubOffset));
3311 __ add(pc, jmp_reg, Operand(Code::kHeaderSize - kHeapObjectTag));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003312
3313 // r0: number of arguments
3314 // r1: called object
3315 // r3: object type
3316 Label do_call;
3317 __ bind(&slow);
3318 __ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE));
3319 __ b(ne, &non_function_call);
3320 __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
3321 __ jmp(&do_call);
3322
3323 __ bind(&non_function_call);
3324 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
3325 __ bind(&do_call);
3326 // Set expected number of arguments to zero (not changing r0).
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003327 __ mov(r2, Operand::Zero());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003328 __ SetCallKind(r5, CALL_AS_METHOD);
3329 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
3330 RelocInfo::CODE_TARGET);
3331}
3332
3333
ricow@chromium.org65fae842010-08-25 15:26:24 +00003334// StringCharCodeAtGenerator
ricow@chromium.org65fae842010-08-25 15:26:24 +00003335void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
3336 Label flat_string;
3337 Label ascii_string;
3338 Label got_char_code;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003339 Label sliced_string;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003340
3341 // If the receiver is a smi trigger the non-string case.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003342 __ JumpIfSmi(object_, receiver_not_string_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003343
3344 // Fetch the instance type of the receiver into result register.
3345 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
3346 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
3347 // If the receiver is not a string trigger the non-string case.
3348 __ tst(result_, Operand(kIsNotStringMask));
3349 __ b(ne, receiver_not_string_);
3350
3351 // If the index is non-smi trigger the non-smi case.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003352 __ JumpIfNotSmi(index_, &index_not_smi_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003353 __ bind(&got_smi_index_);
3354
3355 // Check for index out of range.
3356 __ ldr(ip, FieldMemOperand(object_, String::kLengthOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003357 __ cmp(ip, Operand(index_));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003358 __ b(ls, index_out_of_range_);
3359
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003360 __ SmiUntag(index_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003361
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003362 StringCharLoadGenerator::Generate(masm,
3363 object_,
3364 index_,
3365 result_,
3366 &call_runtime_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003367
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003368 __ SmiTag(result_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003369 __ bind(&exit_);
3370}
3371
3372
3373void StringCharCodeAtGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003374 MacroAssembler* masm,
3375 const RuntimeCallHelper& call_helper) {
danno@chromium.org59400602013-08-13 17:09:37 +00003376 __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003377
3378 // Index is not a smi.
3379 __ bind(&index_not_smi_);
3380 // If index is a heap number, try converting it to an integer.
3381 __ CheckMap(index_,
danno@chromium.orgc612e022011-11-10 11:38:15 +00003382 result_,
ricow@chromium.org65fae842010-08-25 15:26:24 +00003383 Heap::kHeapNumberMapRootIndex,
3384 index_not_number_,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003385 DONT_DO_SMI_CHECK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003386 call_helper.BeforeCall(masm);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003387 __ push(object_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003388 __ push(index_); // Consumed by runtime conversion function.
3389 if (index_flags_ == STRING_INDEX_IS_NUMBER) {
3390 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
3391 } else {
3392 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
3393 // NumberToSmi discards numbers that are not exact integers.
3394 __ CallRuntime(Runtime::kNumberToSmi, 1);
3395 }
3396 // Save the conversion result before the pop instructions below
3397 // have a chance to overwrite it.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003398 __ Move(index_, r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003399 __ pop(object_);
3400 // Reload the instance type.
3401 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
3402 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
3403 call_helper.AfterCall(masm);
3404 // If index is still not a smi, it must be out of range.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003405 __ JumpIfNotSmi(index_, index_out_of_range_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003406 // Otherwise, return to the fast path.
3407 __ jmp(&got_smi_index_);
3408
3409 // Call runtime. We get here when the receiver is a string and the
3410 // index is a number, but the code of getting the actual character
3411 // is too complex (e.g., when the string needs to be flattened).
3412 __ bind(&call_runtime_);
3413 call_helper.BeforeCall(masm);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003414 __ SmiTag(index_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003415 __ Push(object_, index_);
3416 __ CallRuntime(Runtime::kStringCharCodeAt, 2);
3417 __ Move(result_, r0);
3418 call_helper.AfterCall(masm);
3419 __ jmp(&exit_);
3420
danno@chromium.org59400602013-08-13 17:09:37 +00003421 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003422}
3423
3424
3425// -------------------------------------------------------------------------
3426// StringCharFromCodeGenerator
3427
3428void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
3429 // Fast case of Heap::LookupSingleCharacterStringFromCode.
3430 STATIC_ASSERT(kSmiTag == 0);
3431 STATIC_ASSERT(kSmiShiftSize == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003432 ASSERT(IsPowerOf2(String::kMaxOneByteCharCode + 1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003433 __ tst(code_,
3434 Operand(kSmiTagMask |
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003435 ((~String::kMaxOneByteCharCode) << kSmiTagSize)));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003436 __ b(ne, &slow_case_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003437
3438 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003439 // At this point code register contains smi tagged ASCII char code.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003440 __ add(result_, result_, Operand::PointerOffsetFromSmiKey(code_));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003441 __ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003442 __ CompareRoot(result_, Heap::kUndefinedValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003443 __ b(eq, &slow_case_);
3444 __ bind(&exit_);
3445}
3446
3447
3448void StringCharFromCodeGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003449 MacroAssembler* masm,
3450 const RuntimeCallHelper& call_helper) {
danno@chromium.org59400602013-08-13 17:09:37 +00003451 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003452
3453 __ bind(&slow_case_);
3454 call_helper.BeforeCall(masm);
3455 __ push(code_);
3456 __ CallRuntime(Runtime::kCharFromCode, 1);
3457 __ Move(result_, r0);
3458 call_helper.AfterCall(masm);
3459 __ jmp(&exit_);
3460
danno@chromium.org59400602013-08-13 17:09:37 +00003461 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003462}
3463
3464
ricow@chromium.org65fae842010-08-25 15:26:24 +00003465void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
3466 Register dest,
3467 Register src,
3468 Register count,
3469 Register scratch,
3470 bool ascii) {
3471 Label loop;
3472 Label done;
3473 // This loop just copies one character at a time, as it is only used for very
3474 // short strings.
3475 if (!ascii) {
3476 __ add(count, count, Operand(count), SetCC);
3477 } else {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003478 __ cmp(count, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003479 }
3480 __ b(eq, &done);
3481
3482 __ bind(&loop);
3483 __ ldrb(scratch, MemOperand(src, 1, PostIndex));
3484 // Perform sub between load and dependent store to get the load time to
3485 // complete.
3486 __ sub(count, count, Operand(1), SetCC);
3487 __ strb(scratch, MemOperand(dest, 1, PostIndex));
3488 // last iteration.
3489 __ b(gt, &loop);
3490
3491 __ bind(&done);
3492}
3493
3494
3495enum CopyCharactersFlags {
3496 COPY_ASCII = 1,
3497 DEST_ALWAYS_ALIGNED = 2
3498};
3499
3500
3501void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm,
3502 Register dest,
3503 Register src,
3504 Register count,
3505 Register scratch1,
3506 Register scratch2,
3507 Register scratch3,
3508 Register scratch4,
ricow@chromium.org65fae842010-08-25 15:26:24 +00003509 int flags) {
3510 bool ascii = (flags & COPY_ASCII) != 0;
3511 bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0;
3512
3513 if (dest_always_aligned && FLAG_debug_code) {
3514 // Check that destination is actually word aligned if the flag says
3515 // that it is.
3516 __ tst(dest, Operand(kPointerAlignmentMask));
danno@chromium.org59400602013-08-13 17:09:37 +00003517 __ Check(eq, kDestinationOfCopyNotAligned);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003518 }
3519
3520 const int kReadAlignment = 4;
3521 const int kReadAlignmentMask = kReadAlignment - 1;
3522 // Ensure that reading an entire aligned word containing the last character
3523 // of a string will not read outside the allocated area (because we pad up
3524 // to kObjectAlignment).
3525 STATIC_ASSERT(kObjectAlignment >= kReadAlignment);
3526 // Assumes word reads and writes are little endian.
3527 // Nothing to do for zero characters.
3528 Label done;
3529 if (!ascii) {
3530 __ add(count, count, Operand(count), SetCC);
3531 } else {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003532 __ cmp(count, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003533 }
3534 __ b(eq, &done);
3535
3536 // Assume that you cannot read (or write) unaligned.
3537 Label byte_loop;
3538 // Must copy at least eight bytes, otherwise just do it one byte at a time.
3539 __ cmp(count, Operand(8));
3540 __ add(count, dest, Operand(count));
3541 Register limit = count; // Read until src equals this.
3542 __ b(lt, &byte_loop);
3543
3544 if (!dest_always_aligned) {
3545 // Align dest by byte copying. Copies between zero and three bytes.
3546 __ and_(scratch4, dest, Operand(kReadAlignmentMask), SetCC);
3547 Label dest_aligned;
3548 __ b(eq, &dest_aligned);
3549 __ cmp(scratch4, Operand(2));
3550 __ ldrb(scratch1, MemOperand(src, 1, PostIndex));
3551 __ ldrb(scratch2, MemOperand(src, 1, PostIndex), le);
3552 __ ldrb(scratch3, MemOperand(src, 1, PostIndex), lt);
3553 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
3554 __ strb(scratch2, MemOperand(dest, 1, PostIndex), le);
3555 __ strb(scratch3, MemOperand(dest, 1, PostIndex), lt);
3556 __ bind(&dest_aligned);
3557 }
3558
3559 Label simple_loop;
3560
3561 __ sub(scratch4, dest, Operand(src));
3562 __ and_(scratch4, scratch4, Operand(0x03), SetCC);
3563 __ b(eq, &simple_loop);
3564 // Shift register is number of bits in a source word that
3565 // must be combined with bits in the next source word in order
3566 // to create a destination word.
3567
3568 // Complex loop for src/dst that are not aligned the same way.
3569 {
3570 Label loop;
3571 __ mov(scratch4, Operand(scratch4, LSL, 3));
3572 Register left_shift = scratch4;
3573 __ and_(src, src, Operand(~3)); // Round down to load previous word.
3574 __ ldr(scratch1, MemOperand(src, 4, PostIndex));
3575 // Store the "shift" most significant bits of scratch in the least
3576 // signficant bits (i.e., shift down by (32-shift)).
3577 __ rsb(scratch2, left_shift, Operand(32));
3578 Register right_shift = scratch2;
3579 __ mov(scratch1, Operand(scratch1, LSR, right_shift));
3580
3581 __ bind(&loop);
3582 __ ldr(scratch3, MemOperand(src, 4, PostIndex));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003583 __ orr(scratch1, scratch1, Operand(scratch3, LSL, left_shift));
3584 __ str(scratch1, MemOperand(dest, 4, PostIndex));
3585 __ mov(scratch1, Operand(scratch3, LSR, right_shift));
3586 // Loop if four or more bytes left to copy.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003587 __ sub(scratch3, limit, Operand(dest));
3588 __ sub(scratch3, scratch3, Operand(4), SetCC);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003589 __ b(ge, &loop);
3590 }
3591 // There is now between zero and three bytes left to copy (negative that
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003592 // number is in scratch3), and between one and three bytes already read into
ricow@chromium.org65fae842010-08-25 15:26:24 +00003593 // scratch1 (eight times that number in scratch4). We may have read past
3594 // the end of the string, but because objects are aligned, we have not read
3595 // past the end of the object.
3596 // Find the minimum of remaining characters to move and preloaded characters
3597 // and write those as bytes.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003598 __ add(scratch3, scratch3, Operand(4), SetCC);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003599 __ b(eq, &done);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003600 __ cmp(scratch4, Operand(scratch3, LSL, 3), ne);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003601 // Move minimum of bytes read and bytes left to copy to scratch4.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003602 __ mov(scratch3, Operand(scratch4, LSR, 3), LeaveCC, lt);
3603 // Between one and three (value in scratch3) characters already read into
ricow@chromium.org65fae842010-08-25 15:26:24 +00003604 // scratch ready to write.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003605 __ cmp(scratch3, Operand(2));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003606 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
3607 __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, ge);
3608 __ strb(scratch1, MemOperand(dest, 1, PostIndex), ge);
3609 __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, gt);
3610 __ strb(scratch1, MemOperand(dest, 1, PostIndex), gt);
3611 // Copy any remaining bytes.
3612 __ b(&byte_loop);
3613
3614 // Simple loop.
3615 // Copy words from src to dst, until less than four bytes left.
3616 // Both src and dest are word aligned.
3617 __ bind(&simple_loop);
3618 {
3619 Label loop;
3620 __ bind(&loop);
3621 __ ldr(scratch1, MemOperand(src, 4, PostIndex));
3622 __ sub(scratch3, limit, Operand(dest));
3623 __ str(scratch1, MemOperand(dest, 4, PostIndex));
3624 // Compare to 8, not 4, because we do the substraction before increasing
3625 // dest.
3626 __ cmp(scratch3, Operand(8));
3627 __ b(ge, &loop);
3628 }
3629
3630 // Copy bytes from src to dst until dst hits limit.
3631 __ bind(&byte_loop);
3632 __ cmp(dest, Operand(limit));
3633 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt);
3634 __ b(ge, &done);
3635 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
3636 __ b(&byte_loop);
3637
3638 __ bind(&done);
3639}
3640
3641
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003642void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
ricow@chromium.org65fae842010-08-25 15:26:24 +00003643 Register c1,
3644 Register c2,
3645 Register scratch1,
3646 Register scratch2,
3647 Register scratch3,
3648 Register scratch4,
3649 Register scratch5,
3650 Label* not_found) {
3651 // Register scratch3 is the general scratch register in this function.
3652 Register scratch = scratch3;
3653
3654 // Make sure that both characters are not digits as such strings has a
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003655 // different hash algorithm. Don't try to look for these in the string table.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003656 Label not_array_index;
3657 __ sub(scratch, c1, Operand(static_cast<int>('0')));
3658 __ cmp(scratch, Operand(static_cast<int>('9' - '0')));
3659 __ b(hi, &not_array_index);
3660 __ sub(scratch, c2, Operand(static_cast<int>('0')));
3661 __ cmp(scratch, Operand(static_cast<int>('9' - '0')));
3662
3663 // If check failed combine both characters into single halfword.
3664 // This is required by the contract of the method: code at the
3665 // not_found branch expects this combination in c1 register
3666 __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls);
3667 __ b(ls, not_found);
3668
3669 __ bind(&not_array_index);
3670 // Calculate the two character string hash.
3671 Register hash = scratch1;
3672 StringHelper::GenerateHashInit(masm, hash, c1);
3673 StringHelper::GenerateHashAddCharacter(masm, hash, c2);
3674 StringHelper::GenerateHashGetHash(masm, hash);
3675
3676 // Collect the two characters in a register.
3677 Register chars = c1;
3678 __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte));
3679
3680 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
3681 // hash: hash of two character string.
3682
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003683 // Load string table
3684 // Load address of first element of the string table.
3685 Register string_table = c2;
3686 __ LoadRoot(string_table, Heap::kStringTableRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003687
ricow@chromium.org65fae842010-08-25 15:26:24 +00003688 Register undefined = scratch4;
3689 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
3690
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003691 // Calculate capacity mask from the string table capacity.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003692 Register mask = scratch2;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003693 __ ldr(mask, FieldMemOperand(string_table, StringTable::kCapacityOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003694 __ mov(mask, Operand(mask, ASR, 1));
3695 __ sub(mask, mask, Operand(1));
3696
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003697 // Calculate untagged address of the first element of the string table.
3698 Register first_string_table_element = string_table;
3699 __ add(first_string_table_element, string_table,
3700 Operand(StringTable::kElementsStartOffset - kHeapObjectTag));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003701
3702 // Registers
3703 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
3704 // hash: hash of two character string
3705 // mask: capacity mask
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003706 // first_string_table_element: address of the first element of
3707 // the string table
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003708 // undefined: the undefined object
ricow@chromium.org65fae842010-08-25 15:26:24 +00003709 // scratch: -
3710
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003711 // Perform a number of probes in the string table.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00003712 const int kProbes = 4;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003713 Label found_in_string_table;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003714 Label next_probe[kProbes];
danno@chromium.org2c456792011-11-11 12:00:53 +00003715 Register candidate = scratch5; // Scratch register contains candidate.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003716 for (int i = 0; i < kProbes; i++) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003717 // Calculate entry in string table.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003718 if (i > 0) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003719 __ add(candidate, hash, Operand(StringTable::GetProbeOffset(i)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003720 } else {
3721 __ mov(candidate, hash);
3722 }
3723
3724 __ and_(candidate, candidate, Operand(mask));
3725
3726 // Load the entry from the symble table.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003727 STATIC_ASSERT(StringTable::kEntrySize == 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003728 __ ldr(candidate,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003729 MemOperand(first_string_table_element,
ricow@chromium.org65fae842010-08-25 15:26:24 +00003730 candidate,
3731 LSL,
3732 kPointerSizeLog2));
3733
3734 // If entry is undefined no string with this hash can be found.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003735 Label is_string;
3736 __ CompareObjectType(candidate, scratch, scratch, ODDBALL_TYPE);
3737 __ b(ne, &is_string);
3738
3739 __ cmp(undefined, candidate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003740 __ b(eq, not_found);
danno@chromium.org2c456792011-11-11 12:00:53 +00003741 // Must be the hole (deleted entry).
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003742 if (FLAG_debug_code) {
danno@chromium.org2c456792011-11-11 12:00:53 +00003743 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003744 __ cmp(ip, candidate);
danno@chromium.org59400602013-08-13 17:09:37 +00003745 __ Assert(eq, kOddballInStringTableIsNotUndefinedOrTheHole);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003746 }
3747 __ jmp(&next_probe[i]);
3748
3749 __ bind(&is_string);
3750
3751 // Check that the candidate is a non-external ASCII string. The instance
3752 // type is still in the scratch register from the CompareObjectType
3753 // operation.
3754 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &next_probe[i]);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003755
3756 // If length is not 2 the string is not a candidate.
3757 __ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset));
3758 __ cmp(scratch, Operand(Smi::FromInt(2)));
3759 __ b(ne, &next_probe[i]);
3760
ricow@chromium.org65fae842010-08-25 15:26:24 +00003761 // Check if the two characters match.
3762 // Assumes that word load is little endian.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003763 __ ldrh(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003764 __ cmp(chars, scratch);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003765 __ b(eq, &found_in_string_table);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003766 __ bind(&next_probe[i]);
3767 }
3768
3769 // No matching 2 character string found by probing.
3770 __ jmp(not_found);
3771
3772 // Scratch register contains result when we fall through to here.
danno@chromium.org2c456792011-11-11 12:00:53 +00003773 Register result = candidate;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003774 __ bind(&found_in_string_table);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003775 __ Move(r0, result);
3776}
3777
3778
3779void StringHelper::GenerateHashInit(MacroAssembler* masm,
3780 Register hash,
3781 Register character) {
3782 // hash = character + (character << 10);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003783 __ LoadRoot(hash, Heap::kHashSeedRootIndex);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003784 // Untag smi seed and add the character.
3785 __ add(hash, character, Operand(hash, LSR, kSmiTagSize));
3786 // hash += hash << 10;
3787 __ add(hash, hash, Operand(hash, LSL, 10));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003788 // hash ^= hash >> 6;
danno@chromium.org2c456792011-11-11 12:00:53 +00003789 __ eor(hash, hash, Operand(hash, LSR, 6));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003790}
3791
3792
3793void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
3794 Register hash,
3795 Register character) {
3796 // hash += character;
3797 __ add(hash, hash, Operand(character));
3798 // hash += hash << 10;
3799 __ add(hash, hash, Operand(hash, LSL, 10));
3800 // hash ^= hash >> 6;
danno@chromium.org2c456792011-11-11 12:00:53 +00003801 __ eor(hash, hash, Operand(hash, LSR, 6));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003802}
3803
3804
3805void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
3806 Register hash) {
3807 // hash += hash << 3;
3808 __ add(hash, hash, Operand(hash, LSL, 3));
3809 // hash ^= hash >> 11;
danno@chromium.org2c456792011-11-11 12:00:53 +00003810 __ eor(hash, hash, Operand(hash, LSR, 11));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003811 // hash += hash << 15;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003812 __ add(hash, hash, Operand(hash, LSL, 15));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003813
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003814 __ and_(hash, hash, Operand(String::kHashBitMask), SetCC);
danno@chromium.org2c456792011-11-11 12:00:53 +00003815
ricow@chromium.org65fae842010-08-25 15:26:24 +00003816 // if (hash == 0) hash = 27;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003817 __ mov(hash, Operand(StringHasher::kZeroHash), LeaveCC, eq);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003818}
3819
3820
3821void SubStringStub::Generate(MacroAssembler* masm) {
3822 Label runtime;
3823
3824 // Stack frame on entry.
3825 // lr: return address
3826 // sp[0]: to
3827 // sp[4]: from
3828 // sp[8]: string
3829
3830 // This stub is called from the native-call %_SubString(...), so
3831 // nothing can be assumed about the arguments. It is tested that:
3832 // "string" is a sequential string,
3833 // both "from" and "to" are smis, and
3834 // 0 <= from <= to <= string.length.
3835 // If any of these assumptions fail, we call the runtime system.
3836
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00003837 const int kToOffset = 0 * kPointerSize;
3838 const int kFromOffset = 1 * kPointerSize;
3839 const int kStringOffset = 2 * kPointerSize;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003840
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003841 __ Ldrd(r2, r3, MemOperand(sp, kToOffset));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003842 STATIC_ASSERT(kFromOffset == kToOffset + 4);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003843 STATIC_ASSERT(kSmiTag == 0);
3844 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003845
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003846 // Arithmetic shift right by one un-smi-tags. In this case we rotate right
3847 // instead because we bail out on non-smi values: ROR and ASR are equivalent
3848 // for smis but they set the flags in a way that's easier to optimize.
3849 __ mov(r2, Operand(r2, ROR, 1), SetCC);
3850 __ mov(r3, Operand(r3, ROR, 1), SetCC, cc);
3851 // If either to or from had the smi tag bit set, then C is set now, and N
3852 // has the same value: we rotated by 1, so the bottom bit is now the top bit.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003853 // We want to bailout to runtime here if From is negative. In that case, the
3854 // next instruction is not executed and we fall through to bailing out to
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003855 // runtime.
3856 // Executed if both r2 and r3 are untagged integers.
3857 __ sub(r2, r2, Operand(r3), SetCC, cc);
3858 // One of the above un-smis or the above SUB could have set N==1.
3859 __ b(mi, &runtime); // Either "from" or "to" is not an smi, or from > to.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003860
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003861 // Make sure first argument is a string.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003862 __ ldr(r0, MemOperand(sp, kStringOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003863 // Do a JumpIfSmi, but fold its jump into the subsequent string test.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003864 __ SmiTst(r0);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003865 Condition is_string = masm->IsObjectStringType(r0, r1, ne);
3866 ASSERT(is_string == eq);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003867 __ b(NegateCondition(is_string), &runtime);
3868
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003869 Label single_char;
3870 __ cmp(r2, Operand(1));
3871 __ b(eq, &single_char);
3872
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003873 // Short-cut for the case of trivial substring.
3874 Label return_r0;
3875 // r0: original string
3876 // r2: result string length
3877 __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset));
3878 __ cmp(r2, Operand(r4, ASR, 1));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003879 // Return original string.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003880 __ b(eq, &return_r0);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003881 // Longer than original string's length or negative: unsafe arguments.
3882 __ b(hi, &runtime);
3883 // Shorter than original string's length: an actual substring.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003884
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003885 // Deal with different string types: update the index if necessary
3886 // and put the underlying string into r5.
3887 // r0: original string
3888 // r1: instance type
3889 // r2: length
3890 // r3: from index (untagged)
3891 Label underlying_unpacked, sliced_string, seq_or_external_string;
3892 // If the string is not indirect, it can only be sequential or external.
3893 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
3894 STATIC_ASSERT(kIsIndirectStringMask != 0);
3895 __ tst(r1, Operand(kIsIndirectStringMask));
3896 __ b(eq, &seq_or_external_string);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003897
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003898 __ tst(r1, Operand(kSlicedNotConsMask));
3899 __ b(ne, &sliced_string);
3900 // Cons string. Check whether it is flat, then fetch first part.
3901 __ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003902 __ CompareRoot(r5, Heap::kempty_stringRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003903 __ b(ne, &runtime);
3904 __ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset));
3905 // Update instance type.
3906 __ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset));
3907 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
3908 __ jmp(&underlying_unpacked);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003909
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003910 __ bind(&sliced_string);
3911 // Sliced string. Fetch parent and correct start index by offset.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003912 __ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003913 __ ldr(r4, FieldMemOperand(r0, SlicedString::kOffsetOffset));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003914 __ add(r3, r3, Operand(r4, ASR, 1)); // Add offset to index.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003915 // Update instance type.
3916 __ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset));
3917 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
3918 __ jmp(&underlying_unpacked);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003919
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003920 __ bind(&seq_or_external_string);
3921 // Sequential or external string. Just move string to the expected register.
3922 __ mov(r5, r0);
3923
3924 __ bind(&underlying_unpacked);
3925
3926 if (FLAG_string_slices) {
3927 Label copy_routine;
3928 // r5: underlying subject string
3929 // r1: instance type of underlying subject string
3930 // r2: length
3931 // r3: adjusted start index (untagged)
3932 __ cmp(r2, Operand(SlicedString::kMinLength));
3933 // Short slice. Copy instead of slicing.
3934 __ b(lt, &copy_routine);
3935 // Allocate new sliced string. At this point we do not reload the instance
3936 // type including the string encoding because we simply rely on the info
3937 // provided by the original string. It does not matter if the original
3938 // string's encoding is wrong because we always have to recheck encoding of
3939 // the newly created string's parent anyways due to externalized strings.
3940 Label two_byte_slice, set_slice_header;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003941 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003942 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
3943 __ tst(r1, Operand(kStringEncodingMask));
3944 __ b(eq, &two_byte_slice);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003945 __ AllocateAsciiSlicedString(r0, r2, r6, r4, &runtime);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003946 __ jmp(&set_slice_header);
3947 __ bind(&two_byte_slice);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003948 __ AllocateTwoByteSlicedString(r0, r2, r6, r4, &runtime);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003949 __ bind(&set_slice_header);
3950 __ mov(r3, Operand(r3, LSL, 1));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003951 __ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003952 __ str(r3, FieldMemOperand(r0, SlicedString::kOffsetOffset));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003953 __ jmp(&return_r0);
3954
3955 __ bind(&copy_routine);
3956 }
3957
3958 // r5: underlying subject string
3959 // r1: instance type of underlying subject string
3960 // r2: length
3961 // r3: adjusted start index (untagged)
3962 Label two_byte_sequential, sequential_string, allocate_result;
3963 STATIC_ASSERT(kExternalStringTag != 0);
3964 STATIC_ASSERT(kSeqStringTag == 0);
3965 __ tst(r1, Operand(kExternalStringTag));
3966 __ b(eq, &sequential_string);
3967
3968 // Handle external string.
3969 // Rule out short external strings.
3970 STATIC_CHECK(kShortExternalStringTag != 0);
3971 __ tst(r1, Operand(kShortExternalStringTag));
3972 __ b(ne, &runtime);
3973 __ ldr(r5, FieldMemOperand(r5, ExternalString::kResourceDataOffset));
3974 // r5 already points to the first character of underlying string.
3975 __ jmp(&allocate_result);
3976
3977 __ bind(&sequential_string);
3978 // Locate first character of underlying subject string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003979 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
3980 __ add(r5, r5, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003981
3982 __ bind(&allocate_result);
3983 // Sequential acii string. Allocate the result.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003984 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003985 __ tst(r1, Operand(kStringEncodingMask));
3986 __ b(eq, &two_byte_sequential);
3987
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003988 // Allocate and copy the resulting ASCII string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003989 __ AllocateAsciiString(r0, r2, r4, r6, r1, &runtime);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003990
3991 // Locate first character of substring to copy.
3992 __ add(r5, r5, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003993 // Locate first character of result.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003994 __ add(r1, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003995
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003996 // r0: result string
3997 // r1: first character of result string
3998 // r2: result string length
3999 // r5: first character of substring to copy
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004000 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004001 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r9,
ricow@chromium.org65fae842010-08-25 15:26:24 +00004002 COPY_ASCII | DEST_ALWAYS_ALIGNED);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004003 __ jmp(&return_r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004004
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004005 // Allocate and copy the resulting two-byte string.
4006 __ bind(&two_byte_sequential);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004007 __ AllocateTwoByteString(r0, r2, r4, r6, r1, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004008
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004009 // Locate first character of substring to copy.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004010 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004011 __ add(r5, r5, Operand(r3, LSL, 1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004012 // Locate first character of result.
4013 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004014
ricow@chromium.org65fae842010-08-25 15:26:24 +00004015 // r0: result string.
4016 // r1: first character of result.
4017 // r2: result length.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004018 // r5: first character of substring to copy.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004019 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004020 StringHelper::GenerateCopyCharactersLong(
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004021 masm, r1, r5, r2, r3, r4, r6, r9, DEST_ALWAYS_ALIGNED);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004022
4023 __ bind(&return_r0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004024 Counters* counters = masm->isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004025 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00004026 __ Drop(3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004027 __ Ret();
4028
4029 // Just jump to runtime to create the sub string.
4030 __ bind(&runtime);
4031 __ TailCallRuntime(Runtime::kSubString, 3, 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00004032
4033 __ bind(&single_char);
4034 // r0: original string
4035 // r1: instance type
4036 // r2: length
4037 // r3: from index (untagged)
4038 __ SmiTag(r3, r3);
4039 StringCharAtGenerator generator(
4040 r0, r3, r2, r0, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
4041 generator.GenerateFast(masm);
4042 __ Drop(3);
4043 __ Ret();
4044 generator.SkipSlow(masm, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004045}
4046
4047
lrn@chromium.org1c092762011-05-09 09:42:16 +00004048void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
4049 Register left,
4050 Register right,
4051 Register scratch1,
4052 Register scratch2,
4053 Register scratch3) {
4054 Register length = scratch1;
4055
4056 // Compare lengths.
4057 Label strings_not_equal, check_zero_length;
4058 __ ldr(length, FieldMemOperand(left, String::kLengthOffset));
4059 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset));
4060 __ cmp(length, scratch2);
4061 __ b(eq, &check_zero_length);
4062 __ bind(&strings_not_equal);
4063 __ mov(r0, Operand(Smi::FromInt(NOT_EQUAL)));
4064 __ Ret();
4065
4066 // Check if the length is zero.
4067 Label compare_chars;
4068 __ bind(&check_zero_length);
4069 STATIC_ASSERT(kSmiTag == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004070 __ cmp(length, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00004071 __ b(ne, &compare_chars);
4072 __ mov(r0, Operand(Smi::FromInt(EQUAL)));
4073 __ Ret();
4074
4075 // Compare characters.
4076 __ bind(&compare_chars);
4077 GenerateAsciiCharsCompareLoop(masm,
4078 left, right, length, scratch2, scratch3,
4079 &strings_not_equal);
4080
4081 // Characters are equal.
4082 __ mov(r0, Operand(Smi::FromInt(EQUAL)));
4083 __ Ret();
4084}
4085
4086
ricow@chromium.org65fae842010-08-25 15:26:24 +00004087void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
4088 Register left,
4089 Register right,
4090 Register scratch1,
4091 Register scratch2,
4092 Register scratch3,
4093 Register scratch4) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00004094 Label result_not_equal, compare_lengths;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004095 // Find minimum length and length difference.
4096 __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset));
4097 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset));
4098 __ sub(scratch3, scratch1, Operand(scratch2), SetCC);
4099 Register length_delta = scratch3;
4100 __ mov(scratch1, scratch2, LeaveCC, gt);
4101 Register min_length = scratch1;
4102 STATIC_ASSERT(kSmiTag == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004103 __ cmp(min_length, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004104 __ b(eq, &compare_lengths);
4105
lrn@chromium.org1c092762011-05-09 09:42:16 +00004106 // Compare loop.
4107 GenerateAsciiCharsCompareLoop(masm,
4108 left, right, min_length, scratch2, scratch4,
4109 &result_not_equal);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004110
lrn@chromium.org1c092762011-05-09 09:42:16 +00004111 // Compare lengths - strings up to min-length are equal.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004112 __ bind(&compare_lengths);
4113 ASSERT(Smi::FromInt(EQUAL) == static_cast<Smi*>(0));
lrn@chromium.org1c092762011-05-09 09:42:16 +00004114 // Use length_delta as result if it's zero.
4115 __ mov(r0, Operand(length_delta), SetCC);
4116 __ bind(&result_not_equal);
4117 // Conditionally update the result based either on length_delta or
4118 // the last comparion performed in the loop above.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004119 __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt);
4120 __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt);
4121 __ Ret();
4122}
4123
4124
lrn@chromium.org1c092762011-05-09 09:42:16 +00004125void StringCompareStub::GenerateAsciiCharsCompareLoop(
4126 MacroAssembler* masm,
4127 Register left,
4128 Register right,
4129 Register length,
4130 Register scratch1,
4131 Register scratch2,
4132 Label* chars_not_equal) {
4133 // Change index to run from -length to -1 by adding length to string
4134 // start. This means that loop ends when index reaches zero, which
4135 // doesn't need an additional compare.
4136 __ SmiUntag(length);
4137 __ add(scratch1, length,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004138 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
lrn@chromium.org1c092762011-05-09 09:42:16 +00004139 __ add(left, left, Operand(scratch1));
4140 __ add(right, right, Operand(scratch1));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004141 __ rsb(length, length, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00004142 Register index = length; // index = -length;
4143
4144 // Compare loop.
4145 Label loop;
4146 __ bind(&loop);
4147 __ ldrb(scratch1, MemOperand(left, index));
4148 __ ldrb(scratch2, MemOperand(right, index));
4149 __ cmp(scratch1, scratch2);
4150 __ b(ne, chars_not_equal);
4151 __ add(index, index, Operand(1), SetCC);
4152 __ b(ne, &loop);
4153}
4154
4155
ricow@chromium.org65fae842010-08-25 15:26:24 +00004156void StringCompareStub::Generate(MacroAssembler* masm) {
4157 Label runtime;
4158
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004159 Counters* counters = masm->isolate()->counters();
4160
ricow@chromium.org65fae842010-08-25 15:26:24 +00004161 // Stack frame on entry.
4162 // sp[0]: right string
4163 // sp[4]: left string
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004164 __ Ldrd(r0 , r1, MemOperand(sp)); // Load right in r0, left in r1.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004165
4166 Label not_same;
4167 __ cmp(r0, r1);
4168 __ b(ne, &not_same);
4169 STATIC_ASSERT(EQUAL == 0);
4170 STATIC_ASSERT(kSmiTag == 0);
4171 __ mov(r0, Operand(Smi::FromInt(EQUAL)));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004172 __ IncrementCounter(counters->string_compare_native(), 1, r1, r2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004173 __ add(sp, sp, Operand(2 * kPointerSize));
4174 __ Ret();
4175
4176 __ bind(&not_same);
4177
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004178 // Check that both objects are sequential ASCII strings.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004179 __ JumpIfNotBothSequentialAsciiStrings(r1, r0, r2, r3, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004180
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004181 // Compare flat ASCII strings natively. Remove arguments from stack first.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004182 __ IncrementCounter(counters->string_compare_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004183 __ add(sp, sp, Operand(2 * kPointerSize));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004184 GenerateCompareFlatAsciiStrings(masm, r1, r0, r2, r3, r4, r5);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004185
4186 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
4187 // tagged as a small integer.
4188 __ bind(&runtime);
4189 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
4190}
4191
4192
ulan@chromium.org0f13e742014-01-03 15:51:11 +00004193void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
4194 // ----------- S t a t e -------------
4195 // -- r1 : left
4196 // -- r0 : right
4197 // -- lr : return address
4198 // -----------------------------------
4199 Isolate* isolate = masm->isolate();
4200
4201 // Load r2 with the allocation site. We stick an undefined dummy value here
4202 // and replace it with the real allocation site later when we instantiate this
4203 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
4204 __ Move(r2, handle(isolate->heap()->undefined_value()));
4205
4206 // Make sure that we actually patched the allocation site.
4207 if (FLAG_debug_code) {
4208 __ tst(r2, Operand(kSmiTagMask));
4209 __ Assert(ne, kExpectedAllocationSite);
4210 __ push(r2);
4211 __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset));
4212 __ LoadRoot(ip, Heap::kAllocationSiteMapRootIndex);
4213 __ cmp(r2, ip);
4214 __ pop(r2);
4215 __ Assert(eq, kExpectedAllocationSite);
4216 }
4217
4218 // Tail call into the stub that handles binary operations with allocation
4219 // sites.
4220 BinaryOpWithAllocationSiteStub stub(state_);
4221 __ TailCallStub(&stub);
4222}
4223
4224
ricow@chromium.org65fae842010-08-25 15:26:24 +00004225void StringAddStub::Generate(MacroAssembler* masm) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004226 Label call_runtime, call_builtin;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004227 Builtins::JavaScript builtin_id = Builtins::ADD;
4228
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004229 Counters* counters = masm->isolate()->counters();
4230
ricow@chromium.org65fae842010-08-25 15:26:24 +00004231 // Stack on entry:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004232 // sp[0]: second argument (right).
4233 // sp[4]: first argument (left).
ricow@chromium.org65fae842010-08-25 15:26:24 +00004234
4235 // Load the two arguments.
4236 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument.
4237 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument.
4238
4239 // Make sure that both arguments are strings if not known in advance.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004240 // Otherwise, at least one of the arguments is definitely a string,
4241 // and we convert the one that is not known to be a string.
4242 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
4243 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT);
4244 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004245 __ JumpIfEitherSmi(r0, r1, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004246 // Load instance types.
4247 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4248 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4249 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4250 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4251 STATIC_ASSERT(kStringTag == 0);
4252 // If either is not a string, go to runtime.
4253 __ tst(r4, Operand(kIsNotStringMask));
4254 __ tst(r5, Operand(kIsNotStringMask), eq);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004255 __ b(ne, &call_runtime);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004256 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
4257 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0);
4258 GenerateConvertArgument(
4259 masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &call_builtin);
4260 builtin_id = Builtins::STRING_ADD_RIGHT;
4261 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
4262 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0);
4263 GenerateConvertArgument(
4264 masm, 0 * kPointerSize, r1, r2, r3, r4, r5, &call_builtin);
4265 builtin_id = Builtins::STRING_ADD_LEFT;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004266 }
4267
4268 // Both arguments are strings.
4269 // r0: first string
4270 // r1: second string
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004271 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4272 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
ricow@chromium.org65fae842010-08-25 15:26:24 +00004273 {
4274 Label strings_not_empty;
4275 // Check if either of the strings are empty. In that case return the other.
4276 __ ldr(r2, FieldMemOperand(r0, String::kLengthOffset));
4277 __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset));
4278 STATIC_ASSERT(kSmiTag == 0);
4279 __ cmp(r2, Operand(Smi::FromInt(0))); // Test if first string is empty.
4280 __ mov(r0, Operand(r1), LeaveCC, eq); // If first is empty, return second.
4281 STATIC_ASSERT(kSmiTag == 0);
4282 // Else test if second string is empty.
4283 __ cmp(r3, Operand(Smi::FromInt(0)), ne);
4284 __ b(ne, &strings_not_empty); // If either string was empty, return r0.
4285
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004286 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004287 __ add(sp, sp, Operand(2 * kPointerSize));
4288 __ Ret();
4289
4290 __ bind(&strings_not_empty);
4291 }
4292
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004293 __ SmiUntag(r2);
4294 __ SmiUntag(r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004295 // Both strings are non-empty.
4296 // r0: first string
4297 // r1: second string
4298 // r2: length of first string
4299 // r3: length of second string
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004300 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4301 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
ricow@chromium.org65fae842010-08-25 15:26:24 +00004302 // Look at the length of the result of adding the two strings.
4303 Label string_add_flat_result, longer_than_two;
4304 // Adding two lengths can't overflow.
4305 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2);
4306 __ add(r6, r2, Operand(r3));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004307 // Use the string table when adding two one character strings, as it
4308 // helps later optimizations to return a string here.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004309 __ cmp(r6, Operand(2));
4310 __ b(ne, &longer_than_two);
4311
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004312 // Check that both strings are non-external ASCII strings.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004313 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004314 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4315 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4316 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4317 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4318 }
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004319 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r3,
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004320 &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004321
4322 // Get the two characters forming the sub string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004323 __ ldrb(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize));
4324 __ ldrb(r3, FieldMemOperand(r1, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004325
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004326 // Try to lookup two character string in string table. If it is not found
ricow@chromium.org65fae842010-08-25 15:26:24 +00004327 // just allocate a new one.
4328 Label make_two_character_string;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004329 StringHelper::GenerateTwoCharacterStringTableProbe(
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004330 masm, r2, r3, r6, r0, r4, r5, r9, &make_two_character_string);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004331 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004332 __ add(sp, sp, Operand(2 * kPointerSize));
4333 __ Ret();
4334
4335 __ bind(&make_two_character_string);
4336 // Resulting string has length 2 and first chars of two strings
4337 // are combined into single halfword in r2 register.
4338 // So we can fill resulting string without two loops by a single
4339 // halfword store instruction (which assumes that processor is
4340 // in a little endian mode)
4341 __ mov(r6, Operand(2));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004342 __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004343 __ strh(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004344 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004345 __ add(sp, sp, Operand(2 * kPointerSize));
4346 __ Ret();
4347
4348 __ bind(&longer_than_two);
4349 // Check if resulting string will be flat.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004350 __ cmp(r6, Operand(ConsString::kMinLength));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004351 __ b(lt, &string_add_flat_result);
4352 // Handle exceptionally long strings in the runtime system.
4353 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
4354 ASSERT(IsPowerOf2(String::kMaxLength + 1));
4355 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not.
4356 __ cmp(r6, Operand(String::kMaxLength + 1));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004357 __ b(hs, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004358
4359 // If result is not supposed to be flat, allocate a cons string object.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004360 // If both strings are ASCII the result is an ASCII cons string.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004361 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004362 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4363 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4364 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4365 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4366 }
4367 Label non_ascii, allocated, ascii_data;
4368 STATIC_ASSERT(kTwoByteStringTag == 0);
4369 __ tst(r4, Operand(kStringEncodingMask));
4370 __ tst(r5, Operand(kStringEncodingMask), ne);
4371 __ b(eq, &non_ascii);
4372
4373 // Allocate an ASCII cons string.
4374 __ bind(&ascii_data);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004375 __ AllocateAsciiConsString(r3, r6, r4, r5, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004376 __ bind(&allocated);
4377 // Fill the fields of the cons string.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004378 Label skip_write_barrier, after_writing;
4379 ExternalReference high_promotion_mode = ExternalReference::
4380 new_space_high_promotion_mode_active_address(masm->isolate());
4381 __ mov(r4, Operand(high_promotion_mode));
4382 __ ldr(r4, MemOperand(r4, 0));
4383 __ cmp(r4, Operand::Zero());
4384 __ b(eq, &skip_write_barrier);
4385
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004386 __ str(r0, FieldMemOperand(r3, ConsString::kFirstOffset));
4387 __ RecordWriteField(r3,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004388 ConsString::kFirstOffset,
4389 r0,
4390 r4,
4391 kLRHasNotBeenSaved,
4392 kDontSaveFPRegs);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004393 __ str(r1, FieldMemOperand(r3, ConsString::kSecondOffset));
4394 __ RecordWriteField(r3,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004395 ConsString::kSecondOffset,
4396 r1,
4397 r4,
4398 kLRHasNotBeenSaved,
4399 kDontSaveFPRegs);
4400 __ jmp(&after_writing);
4401
4402 __ bind(&skip_write_barrier);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004403 __ str(r0, FieldMemOperand(r3, ConsString::kFirstOffset));
4404 __ str(r1, FieldMemOperand(r3, ConsString::kSecondOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004405
4406 __ bind(&after_writing);
4407
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004408 __ mov(r0, Operand(r3));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004409 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004410 __ add(sp, sp, Operand(2 * kPointerSize));
4411 __ Ret();
4412
4413 __ bind(&non_ascii);
4414 // At least one of the strings is two-byte. Check whether it happens
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004415 // to contain only one byte characters.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004416 // r4: first instance type.
4417 // r5: second instance type.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004418 __ tst(r4, Operand(kOneByteDataHintMask));
4419 __ tst(r5, Operand(kOneByteDataHintMask), ne);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004420 __ b(ne, &ascii_data);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00004421 __ eor(r4, r4, Operand(r5));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004422 STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0);
4423 __ and_(r4, r4, Operand(kOneByteStringTag | kOneByteDataHintTag));
4424 __ cmp(r4, Operand(kOneByteStringTag | kOneByteDataHintTag));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00004425 __ b(eq, &ascii_data);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004426
4427 // Allocate a two byte cons string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004428 __ AllocateTwoByteConsString(r3, r6, r4, r5, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004429 __ jmp(&allocated);
4430
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004431 // We cannot encounter sliced strings or cons strings here since:
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004432 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004433 // Handle creating a flat result from either external or sequential strings.
4434 // Locate the first characters' locations.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004435 // r0: first string
4436 // r1: second string
4437 // r2: length of first string
4438 // r3: length of second string
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004439 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4440 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
ricow@chromium.org65fae842010-08-25 15:26:24 +00004441 // r6: sum of lengths.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004442 Label first_prepared, second_prepared;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004443 __ bind(&string_add_flat_result);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004444 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004445 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4446 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4447 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4448 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4449 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004450
4451 // Check whether both strings have same encoding
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004452 __ eor(ip, r4, Operand(r5));
4453 ASSERT(__ ImmediateFitsAddrMode1Instruction(kStringEncodingMask));
4454 __ tst(ip, Operand(kStringEncodingMask));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004455 __ b(ne, &call_runtime);
4456
4457 STATIC_ASSERT(kSeqStringTag == 0);
4458 __ tst(r4, Operand(kStringRepresentationMask));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004459 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004460 __ add(r6,
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004461 r0,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004462 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag),
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004463 LeaveCC,
4464 eq);
4465 __ b(eq, &first_prepared);
4466 // External string: rule out short external string and load string resource.
4467 STATIC_ASSERT(kShortExternalStringTag != 0);
4468 __ tst(r4, Operand(kShortExternalStringMask));
4469 __ b(ne, &call_runtime);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004470 __ ldr(r6, FieldMemOperand(r0, ExternalString::kResourceDataOffset));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004471 __ bind(&first_prepared);
4472
4473 STATIC_ASSERT(kSeqStringTag == 0);
4474 __ tst(r5, Operand(kStringRepresentationMask));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004475 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004476 __ add(r1,
4477 r1,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004478 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag),
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004479 LeaveCC,
4480 eq);
4481 __ b(eq, &second_prepared);
4482 // External string: rule out short external string and load string resource.
4483 STATIC_ASSERT(kShortExternalStringTag != 0);
4484 __ tst(r5, Operand(kShortExternalStringMask));
4485 __ b(ne, &call_runtime);
4486 __ ldr(r1, FieldMemOperand(r1, ExternalString::kResourceDataOffset));
4487 __ bind(&second_prepared);
4488
4489 Label non_ascii_string_add_flat_result;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004490 // r6: first character of first string
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004491 // r1: first character of second string
4492 // r2: length of first string.
4493 // r3: length of second string.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004494 // Both strings have the same encoding.
4495 STATIC_ASSERT(kTwoByteStringTag == 0);
4496 __ tst(r5, Operand(kStringEncodingMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004497 __ b(eq, &non_ascii_string_add_flat_result);
4498
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004499 __ add(r2, r2, Operand(r3));
4500 __ AllocateAsciiString(r0, r2, r4, r5, r9, &call_runtime);
4501 __ sub(r2, r2, Operand(r3));
4502 __ add(r5, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004503 // r0: result string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004504 // r6: first character of first string.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004505 // r1: first character of second string.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004506 // r2: length of first string.
4507 // r3: length of second string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004508 // r5: first character of result.
4509 StringHelper::GenerateCopyCharacters(masm, r5, r6, r2, r4, true);
4510 // r5: next character of result.
4511 StringHelper::GenerateCopyCharacters(masm, r5, r1, r3, r4, true);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004512 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004513 __ add(sp, sp, Operand(2 * kPointerSize));
4514 __ Ret();
4515
4516 __ bind(&non_ascii_string_add_flat_result);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004517 __ add(r2, r2, Operand(r3));
4518 __ AllocateTwoByteString(r0, r2, r4, r5, r9, &call_runtime);
4519 __ sub(r2, r2, Operand(r3));
4520 __ add(r5, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004521 // r0: result string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004522 // r6: first character of first string.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004523 // r1: first character of second string.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004524 // r2: length of first string.
4525 // r3: length of second string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004526 // r5: first character of result.
4527 StringHelper::GenerateCopyCharacters(masm, r5, r6, r2, r4, false);
4528 // r5: next character of result.
4529 StringHelper::GenerateCopyCharacters(masm, r5, r1, r3, r4, false);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004530 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004531 __ add(sp, sp, Operand(2 * kPointerSize));
4532 __ Ret();
4533
4534 // Just jump to runtime to add the two strings.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004535 __ bind(&call_runtime);
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +00004536 __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004537
4538 if (call_builtin.is_linked()) {
4539 __ bind(&call_builtin);
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +00004540 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004541 }
4542}
4543
4544
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00004545void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
4546 __ push(r0);
4547 __ push(r1);
4548}
4549
4550
4551void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm) {
4552 __ pop(r1);
4553 __ pop(r0);
4554}
4555
4556
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004557void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
4558 int stack_offset,
4559 Register arg,
4560 Register scratch1,
4561 Register scratch2,
4562 Register scratch3,
4563 Register scratch4,
4564 Label* slow) {
4565 // First check if the argument is already a string.
4566 Label not_string, done;
4567 __ JumpIfSmi(arg, &not_string);
4568 __ CompareObjectType(arg, scratch1, scratch1, FIRST_NONSTRING_TYPE);
4569 __ b(lt, &done);
4570
4571 // Check the number to string cache.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004572 __ bind(&not_string);
4573 // Puts the cached result into scratch1.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004574 __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, scratch4, slow);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004575 __ mov(arg, scratch1);
4576 __ str(arg, MemOperand(sp, stack_offset));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004577 __ bind(&done);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004578}
4579
4580
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004581void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004582 ASSERT(state_ == CompareIC::SMI);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004583 Label miss;
4584 __ orr(r2, r1, r0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004585 __ JumpIfNotSmi(r2, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004586
4587 if (GetCondition() == eq) {
4588 // For equality we do not care about the sign of the result.
4589 __ sub(r0, r0, r1, SetCC);
4590 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004591 // Untag before subtracting to avoid handling overflow.
4592 __ SmiUntag(r1);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004593 __ sub(r0, r1, Operand::SmiUntag(r0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004594 }
4595 __ Ret();
4596
4597 __ bind(&miss);
4598 GenerateMiss(masm);
4599}
4600
4601
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004602void ICCompareStub::GenerateNumbers(MacroAssembler* masm) {
4603 ASSERT(state_ == CompareIC::NUMBER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004604
4605 Label generic_stub;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004606 Label unordered, maybe_undefined1, maybe_undefined2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004607 Label miss;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004608
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004609 if (left_ == CompareIC::SMI) {
4610 __ JumpIfNotSmi(r1, &miss);
4611 }
4612 if (right_ == CompareIC::SMI) {
4613 __ JumpIfNotSmi(r0, &miss);
4614 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004615
4616 // Inlining the double comparison and falling back to the general compare
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004617 // stub if NaN is involved.
4618 // Load left and right operand.
4619 Label done, left, left_smi, right_smi;
4620 __ JumpIfSmi(r0, &right_smi);
4621 __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
4622 DONT_DO_SMI_CHECK);
4623 __ sub(r2, r0, Operand(kHeapObjectTag));
4624 __ vldr(d1, r2, HeapNumber::kValueOffset);
4625 __ b(&left);
4626 __ bind(&right_smi);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004627 __ SmiToDouble(d1, r0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004628
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004629 __ bind(&left);
4630 __ JumpIfSmi(r1, &left_smi);
4631 __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
4632 DONT_DO_SMI_CHECK);
4633 __ sub(r2, r1, Operand(kHeapObjectTag));
4634 __ vldr(d0, r2, HeapNumber::kValueOffset);
4635 __ b(&done);
4636 __ bind(&left_smi);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004637 __ SmiToDouble(d0, r1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004638
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004639 __ bind(&done);
4640 // Compare operands.
4641 __ VFPCompareAndSetFlags(d0, d1);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004642
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004643 // Don't base result on status bits when a NaN is involved.
4644 __ b(vs, &unordered);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004645
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004646 // Return a result of -1, 0, or 1, based on status bits.
4647 __ mov(r0, Operand(EQUAL), LeaveCC, eq);
4648 __ mov(r0, Operand(LESS), LeaveCC, lt);
4649 __ mov(r0, Operand(GREATER), LeaveCC, gt);
4650 __ Ret();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004651
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004652 __ bind(&unordered);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004653 __ bind(&generic_stub);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004654 ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
4655 CompareIC::GENERIC);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004656 __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004657
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004658 __ bind(&maybe_undefined1);
4659 if (Token::IsOrderedRelationalCompareOp(op_)) {
4660 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
4661 __ b(ne, &miss);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004662 __ JumpIfSmi(r1, &unordered);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004663 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
4664 __ b(ne, &maybe_undefined2);
4665 __ jmp(&unordered);
4666 }
4667
4668 __ bind(&maybe_undefined2);
4669 if (Token::IsOrderedRelationalCompareOp(op_)) {
4670 __ CompareRoot(r1, Heap::kUndefinedValueRootIndex);
4671 __ b(eq, &unordered);
4672 }
4673
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004674 __ bind(&miss);
4675 GenerateMiss(masm);
4676}
4677
4678
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004679void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) {
4680 ASSERT(state_ == CompareIC::INTERNALIZED_STRING);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004681 Label miss;
4682
4683 // Registers containing left and right operands respectively.
4684 Register left = r1;
4685 Register right = r0;
4686 Register tmp1 = r2;
4687 Register tmp2 = r3;
4688
4689 // Check that both operands are heap objects.
4690 __ JumpIfEitherSmi(left, right, &miss);
4691
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004692 // Check that both operands are internalized strings.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004693 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
4694 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
4695 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
4696 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004697 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
4698 __ orr(tmp1, tmp1, Operand(tmp2));
4699 __ tst(tmp1, Operand(kIsNotStringMask | kIsNotInternalizedMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004700 __ b(ne, &miss);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004701
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004702 // Internalized strings are compared by identity.
4703 __ cmp(left, right);
4704 // Make sure r0 is non-zero. At this point input operands are
4705 // guaranteed to be non-zero.
4706 ASSERT(right.is(r0));
4707 STATIC_ASSERT(EQUAL == 0);
4708 STATIC_ASSERT(kSmiTag == 0);
4709 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
4710 __ Ret();
4711
4712 __ bind(&miss);
4713 GenerateMiss(masm);
4714}
4715
4716
4717void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) {
4718 ASSERT(state_ == CompareIC::UNIQUE_NAME);
4719 ASSERT(GetCondition() == eq);
4720 Label miss;
4721
4722 // Registers containing left and right operands respectively.
4723 Register left = r1;
4724 Register right = r0;
4725 Register tmp1 = r2;
4726 Register tmp2 = r3;
4727
4728 // Check that both operands are heap objects.
4729 __ JumpIfEitherSmi(left, right, &miss);
4730
4731 // Check that both operands are unique names. This leaves the instance
4732 // types loaded in tmp1 and tmp2.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004733 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
4734 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
4735 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
4736 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
4737
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004738 __ JumpIfNotUniqueName(tmp1, &miss);
4739 __ JumpIfNotUniqueName(tmp2, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004740
4741 // Unique names are compared by identity.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004742 __ cmp(left, right);
4743 // Make sure r0 is non-zero. At this point input operands are
4744 // guaranteed to be non-zero.
4745 ASSERT(right.is(r0));
4746 STATIC_ASSERT(EQUAL == 0);
4747 STATIC_ASSERT(kSmiTag == 0);
4748 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
4749 __ Ret();
4750
4751 __ bind(&miss);
4752 GenerateMiss(masm);
4753}
4754
4755
lrn@chromium.org1c092762011-05-09 09:42:16 +00004756void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004757 ASSERT(state_ == CompareIC::STRING);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004758 Label miss;
4759
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004760 bool equality = Token::IsEqualityOp(op_);
4761
lrn@chromium.org1c092762011-05-09 09:42:16 +00004762 // Registers containing left and right operands respectively.
4763 Register left = r1;
4764 Register right = r0;
4765 Register tmp1 = r2;
4766 Register tmp2 = r3;
4767 Register tmp3 = r4;
4768 Register tmp4 = r5;
4769
4770 // Check that both operands are heap objects.
4771 __ JumpIfEitherSmi(left, right, &miss);
4772
4773 // Check that both operands are strings. This leaves the instance
4774 // types loaded in tmp1 and tmp2.
4775 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
4776 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
4777 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
4778 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
4779 STATIC_ASSERT(kNotStringTag != 0);
4780 __ orr(tmp3, tmp1, tmp2);
4781 __ tst(tmp3, Operand(kIsNotStringMask));
4782 __ b(ne, &miss);
4783
4784 // Fast check for identical strings.
4785 __ cmp(left, right);
4786 STATIC_ASSERT(EQUAL == 0);
4787 STATIC_ASSERT(kSmiTag == 0);
4788 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
4789 __ Ret(eq);
4790
4791 // Handle not identical strings.
4792
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004793 // Check that both strings are internalized strings. If they are, we're done
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004794 // because we already know they are not identical. We know they are both
4795 // strings.
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004796 if (equality) {
4797 ASSERT(GetCondition() == eq);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004798 STATIC_ASSERT(kInternalizedTag == 0);
4799 __ orr(tmp3, tmp1, Operand(tmp2));
4800 __ tst(tmp3, Operand(kIsNotInternalizedMask));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004801 // Make sure r0 is non-zero. At this point input operands are
4802 // guaranteed to be non-zero.
4803 ASSERT(right.is(r0));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004804 __ Ret(eq);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004805 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004806
4807 // Check that both strings are sequential ASCII.
4808 Label runtime;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004809 __ JumpIfBothInstanceTypesAreNotSequentialAscii(
4810 tmp1, tmp2, tmp3, tmp4, &runtime);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004811
4812 // Compare flat ASCII strings. Returns when done.
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004813 if (equality) {
4814 StringCompareStub::GenerateFlatAsciiStringEquals(
4815 masm, left, right, tmp1, tmp2, tmp3);
4816 } else {
4817 StringCompareStub::GenerateCompareFlatAsciiStrings(
4818 masm, left, right, tmp1, tmp2, tmp3, tmp4);
4819 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004820
4821 // Handle more complex cases in runtime.
4822 __ bind(&runtime);
4823 __ Push(left, right);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004824 if (equality) {
4825 __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
4826 } else {
4827 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
4828 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004829
4830 __ bind(&miss);
4831 GenerateMiss(masm);
4832}
4833
4834
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004835void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004836 ASSERT(state_ == CompareIC::OBJECT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004837 Label miss;
4838 __ and_(r2, r1, Operand(r0));
whesse@chromium.org7b260152011-06-20 15:33:18 +00004839 __ JumpIfSmi(r2, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004840
4841 __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE);
4842 __ b(ne, &miss);
4843 __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE);
4844 __ b(ne, &miss);
4845
4846 ASSERT(GetCondition() == eq);
4847 __ sub(r0, r0, Operand(r1));
4848 __ Ret();
4849
4850 __ bind(&miss);
4851 GenerateMiss(masm);
4852}
4853
4854
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004855void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
4856 Label miss;
4857 __ and_(r2, r1, Operand(r0));
4858 __ JumpIfSmi(r2, &miss);
4859 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
4860 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
4861 __ cmp(r2, Operand(known_map_));
4862 __ b(ne, &miss);
4863 __ cmp(r3, Operand(known_map_));
4864 __ b(ne, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004865
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004866 __ sub(r0, r0, Operand(r1));
4867 __ Ret();
4868
4869 __ bind(&miss);
4870 GenerateMiss(masm);
4871}
4872
4873
4874
4875void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004876 {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004877 // Call the runtime system in a fresh internal frame.
4878 ExternalReference miss =
4879 ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
4880
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004881 FrameScope scope(masm, StackFrame::INTERNAL);
4882 __ Push(r1, r0);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004883 __ Push(lr, r1, r0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004884 __ mov(ip, Operand(Smi::FromInt(op_)));
4885 __ push(ip);
4886 __ CallExternalReference(miss, 3);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004887 // Compute the entry point of the rewritten stub.
4888 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
4889 // Restore registers.
4890 __ pop(lr);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004891 __ Pop(r1, r0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004892 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004893
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004894 __ Jump(r2);
4895}
4896
4897
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004898void DirectCEntryStub::Generate(MacroAssembler* masm) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004899 // Place the return address on the stack, making the call
4900 // GC safe. The RegExp backend also relies on this.
4901 __ str(lr, MemOperand(sp, 0));
4902 __ blx(ip); // Call the C++ function.
4903 __ VFPEnsureFPSCRState(r2);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004904 __ ldr(pc, MemOperand(sp, 0));
4905}
4906
4907
4908void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004909 Register target) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004910 intptr_t code =
4911 reinterpret_cast<intptr_t>(GetCode(masm->isolate()).location());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004912 __ Move(ip, target);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004913 __ mov(lr, Operand(code, RelocInfo::CODE_TARGET));
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004914 __ blx(lr); // Call the stub.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004915}
4916
4917
ulan@chromium.org750145a2013-03-07 15:14:13 +00004918void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
4919 Label* miss,
4920 Label* done,
4921 Register receiver,
4922 Register properties,
4923 Handle<Name> name,
4924 Register scratch0) {
4925 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004926 // If names of slots in range from 1 to kProbes - 1 for the hash value are
4927 // not equal to the name and kProbes-th slot is not used (its name is the
4928 // undefined value), it guarantees the hash table doesn't contain the
4929 // property. It's true even if some slots represent deleted properties
ulan@chromium.org967e2702012-02-28 09:49:15 +00004930 // (their names are the hole value).
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004931 for (int i = 0; i < kInlinedProbes; i++) {
4932 // scratch0 points to properties hash.
4933 // Compute the masked index: (hash + i + i * i) & mask.
4934 Register index = scratch0;
4935 // Capacity is smi 2^n.
4936 __ ldr(index, FieldMemOperand(properties, kCapacityOffset));
4937 __ sub(index, index, Operand(1));
4938 __ and_(index, index, Operand(
ulan@chromium.org750145a2013-03-07 15:14:13 +00004939 Smi::FromInt(name->Hash() + NameDictionary::GetProbeOffset(i))));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004940
4941 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004942 ASSERT(NameDictionary::kEntrySize == 3);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004943 __ add(index, index, Operand(index, LSL, 1)); // index *= 3.
4944
4945 Register entity_name = scratch0;
4946 // Having undefined at this place means the name is not contained.
4947 ASSERT_EQ(kSmiTagSize, 1);
4948 Register tmp = properties;
4949 __ add(tmp, properties, Operand(index, LSL, 1));
4950 __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
4951
4952 ASSERT(!tmp.is(entity_name));
4953 __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
4954 __ cmp(entity_name, tmp);
4955 __ b(eq, done);
4956
ulan@chromium.org77802e82013-03-26 11:54:42 +00004957 // Load the hole ready for use below:
4958 __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex);
ulan@chromium.org967e2702012-02-28 09:49:15 +00004959
ulan@chromium.org77802e82013-03-26 11:54:42 +00004960 // Stop if found the property.
4961 __ cmp(entity_name, Operand(Handle<Name>(name)));
4962 __ b(eq, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004963
ulan@chromium.org77802e82013-03-26 11:54:42 +00004964 Label good;
4965 __ cmp(entity_name, tmp);
4966 __ b(eq, &good);
ulan@chromium.org967e2702012-02-28 09:49:15 +00004967
ulan@chromium.org77802e82013-03-26 11:54:42 +00004968 // Check if the entry name is not a unique name.
4969 __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
4970 __ ldrb(entity_name,
4971 FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004972 __ JumpIfNotUniqueName(entity_name, miss);
ulan@chromium.org77802e82013-03-26 11:54:42 +00004973 __ bind(&good);
ulan@chromium.org967e2702012-02-28 09:49:15 +00004974
ulan@chromium.org77802e82013-03-26 11:54:42 +00004975 // Restore the properties.
4976 __ ldr(properties,
4977 FieldMemOperand(receiver, JSObject::kPropertiesOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004978 }
4979
4980 const int spill_mask =
4981 (lr.bit() | r6.bit() | r5.bit() | r4.bit() | r3.bit() |
4982 r2.bit() | r1.bit() | r0.bit());
4983
4984 __ stm(db_w, sp, spill_mask);
4985 __ ldr(r0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +00004986 __ mov(r1, Operand(Handle<Name>(name)));
4987 NameDictionaryLookupStub stub(NEGATIVE_LOOKUP);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004988 __ CallStub(&stub);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004989 __ cmp(r0, Operand::Zero());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004990 __ ldm(ia_w, sp, spill_mask);
4991
4992 __ b(eq, done);
4993 __ b(ne, miss);
4994}
4995
4996
ulan@chromium.org750145a2013-03-07 15:14:13 +00004997// Probe the name dictionary in the |elements| register. Jump to the
lrn@chromium.org1c092762011-05-09 09:42:16 +00004998// |done| label if a property with the given name is found. Jump to
4999// the |miss| label otherwise.
5000// If lookup was successful |scratch2| will be equal to elements + 4 * index.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005001void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
5002 Label* miss,
5003 Label* done,
5004 Register elements,
5005 Register name,
5006 Register scratch1,
5007 Register scratch2) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00005008 ASSERT(!elements.is(scratch1));
5009 ASSERT(!elements.is(scratch2));
5010 ASSERT(!name.is(scratch1));
5011 ASSERT(!name.is(scratch2));
5012
ulan@chromium.org750145a2013-03-07 15:14:13 +00005013 __ AssertName(name);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005014
5015 // Compute the capacity mask.
5016 __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00005017 __ SmiUntag(scratch1);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005018 __ sub(scratch1, scratch1, Operand(1));
5019
5020 // Generate an unrolled loop that performs a few probes before
5021 // giving up. Measurements done on Gmail indicate that 2 probes
5022 // cover ~93% of loads from dictionaries.
5023 for (int i = 0; i < kInlinedProbes; i++) {
5024 // Compute the masked index: (hash + i + i * i) & mask.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005025 __ ldr(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005026 if (i > 0) {
5027 // Add the probe offset (i + i * i) left shifted to avoid right shifting
5028 // the hash in a separate instruction. The value hash + i + i * i is right
5029 // shifted in the following and instruction.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005030 ASSERT(NameDictionary::GetProbeOffset(i) <
5031 1 << (32 - Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005032 __ add(scratch2, scratch2, Operand(
ulan@chromium.org750145a2013-03-07 15:14:13 +00005033 NameDictionary::GetProbeOffset(i) << Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005034 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00005035 __ and_(scratch2, scratch1, Operand(scratch2, LSR, Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005036
5037 // Scale the index by multiplying by the element size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005038 ASSERT(NameDictionary::kEntrySize == 3);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005039 // scratch2 = scratch2 * 3.
5040 __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
5041
5042 // Check if the key is identical to the name.
5043 __ add(scratch2, elements, Operand(scratch2, LSL, 2));
5044 __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
5045 __ cmp(name, Operand(ip));
5046 __ b(eq, done);
5047 }
5048
5049 const int spill_mask =
5050 (lr.bit() | r6.bit() | r5.bit() | r4.bit() |
5051 r3.bit() | r2.bit() | r1.bit() | r0.bit()) &
5052 ~(scratch1.bit() | scratch2.bit());
5053
5054 __ stm(db_w, sp, spill_mask);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00005055 if (name.is(r0)) {
5056 ASSERT(!elements.is(r1));
5057 __ Move(r1, name);
5058 __ Move(r0, elements);
5059 } else {
5060 __ Move(r0, elements);
5061 __ Move(r1, name);
5062 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00005063 NameDictionaryLookupStub stub(POSITIVE_LOOKUP);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005064 __ CallStub(&stub);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005065 __ cmp(r0, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00005066 __ mov(scratch2, Operand(r2));
5067 __ ldm(ia_w, sp, spill_mask);
5068
5069 __ b(ne, done);
5070 __ b(eq, miss);
5071}
5072
5073
ulan@chromium.org750145a2013-03-07 15:14:13 +00005074void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005075 // This stub overrides SometimesSetsUpAFrame() to return false. That means
5076 // we cannot call anything that could cause a GC from this stub.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005077 // Registers:
ulan@chromium.org750145a2013-03-07 15:14:13 +00005078 // result: NameDictionary to probe
lrn@chromium.org1c092762011-05-09 09:42:16 +00005079 // r1: key
ulan@chromium.org750145a2013-03-07 15:14:13 +00005080 // dictionary: NameDictionary to probe.
5081 // index: will hold an index of entry if lookup is successful.
5082 // might alias with result_.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005083 // Returns:
5084 // result_ is zero if lookup failed, non zero otherwise.
5085
5086 Register result = r0;
5087 Register dictionary = r0;
5088 Register key = r1;
5089 Register index = r2;
5090 Register mask = r3;
5091 Register hash = r4;
5092 Register undefined = r5;
5093 Register entry_key = r6;
5094
5095 Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
5096
5097 __ ldr(mask, FieldMemOperand(dictionary, kCapacityOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00005098 __ SmiUntag(mask);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005099 __ sub(mask, mask, Operand(1));
5100
ulan@chromium.org750145a2013-03-07 15:14:13 +00005101 __ ldr(hash, FieldMemOperand(key, Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005102
5103 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
5104
5105 for (int i = kInlinedProbes; i < kTotalProbes; i++) {
5106 // Compute the masked index: (hash + i + i * i) & mask.
5107 // Capacity is smi 2^n.
5108 if (i > 0) {
5109 // Add the probe offset (i + i * i) left shifted to avoid right shifting
5110 // the hash in a separate instruction. The value hash + i + i * i is right
5111 // shifted in the following and instruction.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005112 ASSERT(NameDictionary::GetProbeOffset(i) <
5113 1 << (32 - Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005114 __ add(index, hash, Operand(
ulan@chromium.org750145a2013-03-07 15:14:13 +00005115 NameDictionary::GetProbeOffset(i) << Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005116 } else {
5117 __ mov(index, Operand(hash));
5118 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00005119 __ and_(index, mask, Operand(index, LSR, Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005120
5121 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005122 ASSERT(NameDictionary::kEntrySize == 3);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005123 __ add(index, index, Operand(index, LSL, 1)); // index *= 3.
5124
5125 ASSERT_EQ(kSmiTagSize, 1);
5126 __ add(index, dictionary, Operand(index, LSL, 2));
5127 __ ldr(entry_key, FieldMemOperand(index, kElementsStartOffset));
5128
5129 // Having undefined at this place means the name is not contained.
5130 __ cmp(entry_key, Operand(undefined));
5131 __ b(eq, &not_in_dictionary);
5132
5133 // Stop if found the property.
5134 __ cmp(entry_key, Operand(key));
5135 __ b(eq, &in_dictionary);
5136
5137 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005138 // Check if the entry name is not a unique name.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005139 __ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
5140 __ ldrb(entry_key,
5141 FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005142 __ JumpIfNotUniqueName(entry_key, &maybe_in_dictionary);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005143 }
5144 }
5145
5146 __ bind(&maybe_in_dictionary);
5147 // If we are doing negative lookup then probing failure should be
5148 // treated as a lookup success. For positive lookup probing failure
5149 // should be treated as lookup failure.
5150 if (mode_ == POSITIVE_LOOKUP) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005151 __ mov(result, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00005152 __ Ret();
5153 }
5154
5155 __ bind(&in_dictionary);
5156 __ mov(result, Operand(1));
5157 __ Ret();
5158
5159 __ bind(&not_in_dictionary);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005160 __ mov(result, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00005161 __ Ret();
5162}
5163
5164
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005165void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
5166 Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005167 StoreBufferOverflowStub stub1(kDontSaveFPRegs);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005168 stub1.GetCode(isolate);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00005169 // Hydrogen code stubs need stub2 at snapshot time.
5170 StoreBufferOverflowStub stub2(kSaveFPRegs);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005171 stub2.GetCode(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005172}
5173
5174
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005175bool CodeStub::CanUseFPRegisters() {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005176 return true; // VFP2 is a base requirement for V8
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005177}
5178
5179
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005180// Takes the input in 3 registers: address_ value_ and object_. A pointer to
5181// the value has just been written into the object, now this stub makes sure
5182// we keep the GC informed. The word in the object where the value has been
5183// written is in the address register.
5184void RecordWriteStub::Generate(MacroAssembler* masm) {
5185 Label skip_to_incremental_noncompacting;
5186 Label skip_to_incremental_compacting;
5187
5188 // The first two instructions are generated with labels so as to get the
5189 // offset fixed up correctly by the bind(Label*) call. We patch it back and
5190 // forth between a compare instructions (a nop in this position) and the
5191 // real branch when we start and stop incremental heap marking.
5192 // See RecordWriteStub::Patch for details.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005193 {
5194 // Block literal pool emission, as the position of these two instructions
5195 // is assumed by the patching code.
5196 Assembler::BlockConstPoolScope block_const_pool(masm);
5197 __ b(&skip_to_incremental_noncompacting);
5198 __ b(&skip_to_incremental_compacting);
5199 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005200
5201 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
5202 __ RememberedSetHelper(object_,
5203 address_,
5204 value_,
5205 save_fp_regs_mode_,
5206 MacroAssembler::kReturnAtEnd);
5207 }
5208 __ Ret();
5209
5210 __ bind(&skip_to_incremental_noncompacting);
5211 GenerateIncremental(masm, INCREMENTAL);
5212
5213 __ bind(&skip_to_incremental_compacting);
5214 GenerateIncremental(masm, INCREMENTAL_COMPACTION);
5215
5216 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
5217 // Will be checked in IncrementalMarking::ActivateGeneratedStub.
5218 ASSERT(Assembler::GetBranchOffset(masm->instr_at(0)) < (1 << 12));
5219 ASSERT(Assembler::GetBranchOffset(masm->instr_at(4)) < (1 << 12));
5220 PatchBranchIntoNop(masm, 0);
5221 PatchBranchIntoNop(masm, Assembler::kInstrSize);
5222}
5223
5224
5225void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
5226 regs_.Save(masm);
5227
5228 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
5229 Label dont_need_remembered_set;
5230
5231 __ ldr(regs_.scratch0(), MemOperand(regs_.address(), 0));
5232 __ JumpIfNotInNewSpace(regs_.scratch0(), // Value.
5233 regs_.scratch0(),
5234 &dont_need_remembered_set);
5235
5236 __ CheckPageFlag(regs_.object(),
5237 regs_.scratch0(),
5238 1 << MemoryChunk::SCAN_ON_SCAVENGE,
5239 ne,
5240 &dont_need_remembered_set);
5241
5242 // First notify the incremental marker if necessary, then update the
5243 // remembered set.
5244 CheckNeedsToInformIncrementalMarker(
5245 masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
5246 InformIncrementalMarker(masm, mode);
5247 regs_.Restore(masm);
5248 __ RememberedSetHelper(object_,
5249 address_,
5250 value_,
5251 save_fp_regs_mode_,
5252 MacroAssembler::kReturnAtEnd);
5253
5254 __ bind(&dont_need_remembered_set);
5255 }
5256
5257 CheckNeedsToInformIncrementalMarker(
5258 masm, kReturnOnNoNeedToInformIncrementalMarker, mode);
5259 InformIncrementalMarker(masm, mode);
5260 regs_.Restore(masm);
5261 __ Ret();
5262}
5263
5264
5265void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) {
5266 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_);
5267 int argument_count = 3;
5268 __ PrepareCallCFunction(argument_count, regs_.scratch0());
5269 Register address =
5270 r0.is(regs_.address()) ? regs_.scratch0() : regs_.address();
5271 ASSERT(!address.is(regs_.object()));
5272 ASSERT(!address.is(r0));
5273 __ Move(address, regs_.address());
5274 __ Move(r0, regs_.object());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005275 __ Move(r1, address);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005276 __ mov(r2, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005277
5278 AllowExternalCallThatCantCauseGC scope(masm);
5279 if (mode == INCREMENTAL_COMPACTION) {
5280 __ CallCFunction(
5281 ExternalReference::incremental_evacuation_record_write_function(
5282 masm->isolate()),
5283 argument_count);
5284 } else {
5285 ASSERT(mode == INCREMENTAL);
5286 __ CallCFunction(
5287 ExternalReference::incremental_marking_record_write_function(
5288 masm->isolate()),
5289 argument_count);
5290 }
5291 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_);
5292}
5293
5294
5295void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
5296 MacroAssembler* masm,
5297 OnNoNeedToInformIncrementalMarker on_no_need,
5298 Mode mode) {
5299 Label on_black;
5300 Label need_incremental;
5301 Label need_incremental_pop_scratch;
5302
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005303 __ and_(regs_.scratch0(), regs_.object(), Operand(~Page::kPageAlignmentMask));
5304 __ ldr(regs_.scratch1(),
5305 MemOperand(regs_.scratch0(),
5306 MemoryChunk::kWriteBarrierCounterOffset));
5307 __ sub(regs_.scratch1(), regs_.scratch1(), Operand(1), SetCC);
5308 __ str(regs_.scratch1(),
5309 MemOperand(regs_.scratch0(),
5310 MemoryChunk::kWriteBarrierCounterOffset));
5311 __ b(mi, &need_incremental);
5312
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005313 // Let's look at the color of the object: If it is not black we don't have
5314 // to inform the incremental marker.
5315 __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black);
5316
5317 regs_.Restore(masm);
5318 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
5319 __ RememberedSetHelper(object_,
5320 address_,
5321 value_,
5322 save_fp_regs_mode_,
5323 MacroAssembler::kReturnAtEnd);
5324 } else {
5325 __ Ret();
5326 }
5327
5328 __ bind(&on_black);
5329
5330 // Get the value from the slot.
5331 __ ldr(regs_.scratch0(), MemOperand(regs_.address(), 0));
5332
5333 if (mode == INCREMENTAL_COMPACTION) {
5334 Label ensure_not_white;
5335
5336 __ CheckPageFlag(regs_.scratch0(), // Contains value.
5337 regs_.scratch1(), // Scratch.
5338 MemoryChunk::kEvacuationCandidateMask,
5339 eq,
5340 &ensure_not_white);
5341
5342 __ CheckPageFlag(regs_.object(),
5343 regs_.scratch1(), // Scratch.
5344 MemoryChunk::kSkipEvacuationSlotsRecordingMask,
5345 eq,
5346 &need_incremental);
5347
5348 __ bind(&ensure_not_white);
5349 }
5350
5351 // We need extra registers for this, so we push the object and the address
5352 // register temporarily.
5353 __ Push(regs_.object(), regs_.address());
5354 __ EnsureNotWhite(regs_.scratch0(), // The value.
5355 regs_.scratch1(), // Scratch.
5356 regs_.object(), // Scratch.
5357 regs_.address(), // Scratch.
5358 &need_incremental_pop_scratch);
5359 __ Pop(regs_.object(), regs_.address());
5360
5361 regs_.Restore(masm);
5362 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
5363 __ RememberedSetHelper(object_,
5364 address_,
5365 value_,
5366 save_fp_regs_mode_,
5367 MacroAssembler::kReturnAtEnd);
5368 } else {
5369 __ Ret();
5370 }
5371
5372 __ bind(&need_incremental_pop_scratch);
5373 __ Pop(regs_.object(), regs_.address());
5374
5375 __ bind(&need_incremental);
5376
5377 // Fall through when we need to inform the incremental marker.
5378}
5379
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005380
5381void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
5382 // ----------- S t a t e -------------
5383 // -- r0 : element value to store
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005384 // -- r3 : element index as smi
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005385 // -- sp[0] : array literal index in function as smi
5386 // -- sp[4] : array literal
5387 // clobbers r1, r2, r4
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005388 // -----------------------------------
5389
5390 Label element_done;
5391 Label double_elements;
5392 Label smi_element;
5393 Label slow_elements;
5394 Label fast_elements;
5395
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005396 // Get array literal index, array literal and its map.
5397 __ ldr(r4, MemOperand(sp, 0 * kPointerSize));
5398 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
5399 __ ldr(r2, FieldMemOperand(r1, JSObject::kMapOffset));
5400
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005401 __ CheckFastElements(r2, r5, &double_elements);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005402 // FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005403 __ JumpIfSmi(r0, &smi_element);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005404 __ CheckFastSmiElements(r2, r5, &fast_elements);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005405
5406 // Store into the array literal requires a elements transition. Call into
5407 // the runtime.
5408 __ bind(&slow_elements);
5409 // call.
5410 __ Push(r1, r3, r0);
5411 __ ldr(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
5412 __ ldr(r5, FieldMemOperand(r5, JSFunction::kLiteralsOffset));
5413 __ Push(r5, r4);
5414 __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
5415
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005416 // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005417 __ bind(&fast_elements);
5418 __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00005419 __ add(r6, r5, Operand::PointerOffsetFromSmiKey(r3));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005420 __ add(r6, r6, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
5421 __ str(r0, MemOperand(r6, 0));
5422 // Update the write barrier for the array store.
5423 __ RecordWrite(r5, r6, r0, kLRHasNotBeenSaved, kDontSaveFPRegs,
5424 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
5425 __ Ret();
5426
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005427 // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
5428 // and value is Smi.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005429 __ bind(&smi_element);
5430 __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00005431 __ add(r6, r5, Operand::PointerOffsetFromSmiKey(r3));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005432 __ str(r0, FieldMemOperand(r6, FixedArray::kHeaderSize));
5433 __ Ret();
5434
5435 // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
5436 __ bind(&double_elements);
5437 __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00005438 __ StoreNumberToDoubleElements(r0, r3, r5, r6, d0, &slow_elements);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005439 __ Ret();
5440}
5441
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005442
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00005443void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005444 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005445 __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00005446 int parameter_count_offset =
5447 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
5448 __ ldr(r1, MemOperand(fp, parameter_count_offset));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005449 if (function_mode_ == JS_FUNCTION_STUB_MODE) {
5450 __ add(r1, r1, Operand(1));
5451 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00005452 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00005453 __ mov(r1, Operand(r1, LSL, kPointerSizeLog2));
5454 __ add(sp, sp, r1);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00005455 __ Ret();
5456}
5457
5458
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005459void StubFailureTailCallTrampolineStub::Generate(MacroAssembler* masm) {
5460 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
5461 __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
5462 __ mov(r1, r0);
5463 int parameter_count_offset =
5464 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
5465 __ ldr(r0, MemOperand(fp, parameter_count_offset));
5466 // The parameter count above includes the receiver for the arguments passed to
5467 // the deoptimization handler. Subtract the receiver for the parameter count
5468 // for the call.
5469 __ sub(r0, r0, Operand(1));
5470 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
5471 ParameterCount argument_count(r0);
5472 __ InvokeFunction(
5473 r1, argument_count, JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
5474}
5475
5476
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005477void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005478 if (masm->isolate()->function_entry_hook() != NULL) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005479 PredictableCodeSizeScope predictable(masm, 4 * Assembler::kInstrSize);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005480 ProfileEntryHookStub stub;
5481 __ push(lr);
5482 __ CallStub(&stub);
5483 __ pop(lr);
5484 }
5485}
5486
5487
5488void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
5489 // The entry hook is a "push lr" instruction, followed by a call.
5490 const int32_t kReturnAddressDistanceFromFunctionStart =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005491 3 * Assembler::kInstrSize;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005492
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005493 // This should contain all kCallerSaved registers.
5494 const RegList kSavedRegs =
5495 1 << 0 | // r0
5496 1 << 1 | // r1
5497 1 << 2 | // r2
5498 1 << 3 | // r3
5499 1 << 5 | // r5
5500 1 << 9; // r9
5501 // We also save lr, so the count here is one higher than the mask indicates.
5502 const int32_t kNumSavedRegs = 7;
5503
5504 ASSERT((kCallerSaved & kSavedRegs) == kCallerSaved);
5505
5506 // Save all caller-save registers as this may be called from anywhere.
5507 __ stm(db_w, sp, kSavedRegs | lr.bit());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005508
5509 // Compute the function's address for the first argument.
5510 __ sub(r0, lr, Operand(kReturnAddressDistanceFromFunctionStart));
5511
5512 // The caller's return address is above the saved temporaries.
5513 // Grab that for the second argument to the hook.
5514 __ add(r1, sp, Operand(kNumSavedRegs * kPointerSize));
5515
5516 // Align the stack if necessary.
5517 int frame_alignment = masm->ActivationFrameAlignment();
5518 if (frame_alignment > kPointerSize) {
5519 __ mov(r5, sp);
5520 ASSERT(IsPowerOf2(frame_alignment));
5521 __ and_(sp, sp, Operand(-frame_alignment));
5522 }
5523
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00005524#if V8_HOST_ARCH_ARM
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005525 int32_t entry_hook =
5526 reinterpret_cast<int32_t>(masm->isolate()->function_entry_hook());
5527 __ mov(ip, Operand(entry_hook));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005528#else
5529 // Under the simulator we need to indirect the entry hook through a
5530 // trampoline function at a known address.
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00005531 // It additionally takes an isolate as a third parameter
5532 __ mov(r2, Operand(ExternalReference::isolate_address(masm->isolate())));
5533
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005534 ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005535 __ mov(ip, Operand(ExternalReference(&dispatcher,
5536 ExternalReference::BUILTIN_CALL,
5537 masm->isolate())));
5538#endif
5539 __ Call(ip);
5540
5541 // Restore the stack pointer if needed.
5542 if (frame_alignment > kPointerSize) {
5543 __ mov(sp, r5);
5544 }
5545
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005546 // Also pop pc to get Ret(0).
5547 __ ldm(ia_w, sp, kSavedRegs | pc.bit());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005548}
5549
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005550
5551template<class T>
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005552static void CreateArrayDispatch(MacroAssembler* masm,
5553 AllocationSiteOverrideMode mode) {
5554 if (mode == DISABLE_ALLOCATION_SITES) {
5555 T stub(GetInitialFastElementsKind(),
5556 CONTEXT_CHECK_REQUIRED,
5557 mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005558 __ TailCallStub(&stub);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005559 } else if (mode == DONT_OVERRIDE) {
5560 int last_index = GetSequenceIndexFromFastElementsKind(
5561 TERMINAL_FAST_ELEMENTS_KIND);
5562 for (int i = 0; i <= last_index; ++i) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005563 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
5564 __ cmp(r3, Operand(kind));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005565 T stub(kind);
ulan@chromium.org9ca30172014-01-02 12:10:54 +00005566 __ TailCallStub(&stub, eq);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005567 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005568
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005569 // If we reached this point there is a problem.
5570 __ Abort(kUnexpectedElementsKindInArrayConstructor);
5571 } else {
5572 UNREACHABLE();
5573 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005574}
5575
5576
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005577static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
5578 AllocationSiteOverrideMode mode) {
5579 // r2 - type info cell (if mode != DISABLE_ALLOCATION_SITES)
5580 // r3 - kind (if mode != DISABLE_ALLOCATION_SITES)
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005581 // r0 - number of arguments
5582 // r1 - constructor?
5583 // sp[0] - last argument
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005584 Label normal_sequence;
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005585 if (mode == DONT_OVERRIDE) {
5586 ASSERT(FAST_SMI_ELEMENTS == 0);
5587 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
5588 ASSERT(FAST_ELEMENTS == 2);
5589 ASSERT(FAST_HOLEY_ELEMENTS == 3);
5590 ASSERT(FAST_DOUBLE_ELEMENTS == 4);
5591 ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
5592
5593 // is the low bit set? If so, we are holey and that is good.
5594 __ tst(r3, Operand(1));
5595 __ b(ne, &normal_sequence);
5596 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005597
5598 // look at the first argument
5599 __ ldr(r5, MemOperand(sp, 0));
5600 __ cmp(r5, Operand::Zero());
5601 __ b(eq, &normal_sequence);
5602
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005603 if (mode == DISABLE_ALLOCATION_SITES) {
5604 ElementsKind initial = GetInitialFastElementsKind();
5605 ElementsKind holey_initial = GetHoleyElementsKind(initial);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005606
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005607 ArraySingleArgumentConstructorStub stub_holey(holey_initial,
5608 CONTEXT_CHECK_REQUIRED,
5609 DISABLE_ALLOCATION_SITES);
5610 __ TailCallStub(&stub_holey);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005611
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005612 __ bind(&normal_sequence);
5613 ArraySingleArgumentConstructorStub stub(initial,
5614 CONTEXT_CHECK_REQUIRED,
5615 DISABLE_ALLOCATION_SITES);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005616 __ TailCallStub(&stub);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005617 } else if (mode == DONT_OVERRIDE) {
5618 // We are going to create a holey array, but our kind is non-holey.
5619 // Fix kind and retry (only if we have an allocation site in the cell).
5620 __ add(r3, r3, Operand(1));
5621 __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005622
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005623 if (FLAG_debug_code) {
5624 __ ldr(r5, FieldMemOperand(r5, 0));
5625 __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
5626 __ Assert(eq, kExpectedAllocationSiteInCell);
5627 __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
5628 }
5629
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005630 // Save the resulting elements kind in type info. We can't just store r3
5631 // in the AllocationSite::transition_info field because elements kind is
5632 // restricted to a portion of the field...upper bits need to be left alone.
5633 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
5634 __ ldr(r4, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset));
5635 __ add(r4, r4, Operand(Smi::FromInt(kFastElementsKindPackedToHoley)));
5636 __ str(r4, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005637
5638 __ bind(&normal_sequence);
5639 int last_index = GetSequenceIndexFromFastElementsKind(
5640 TERMINAL_FAST_ELEMENTS_KIND);
5641 for (int i = 0; i <= last_index; ++i) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005642 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
5643 __ cmp(r3, Operand(kind));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005644 ArraySingleArgumentConstructorStub stub(kind);
ulan@chromium.org9ca30172014-01-02 12:10:54 +00005645 __ TailCallStub(&stub, eq);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005646 }
5647
5648 // If we reached this point there is a problem.
5649 __ Abort(kUnexpectedElementsKindInArrayConstructor);
5650 } else {
5651 UNREACHABLE();
5652 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005653}
5654
5655
5656template<class T>
5657static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005658 ElementsKind initial_kind = GetInitialFastElementsKind();
5659 ElementsKind initial_holey_kind = GetHoleyElementsKind(initial_kind);
5660
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005661 int to_index = GetSequenceIndexFromFastElementsKind(
5662 TERMINAL_FAST_ELEMENTS_KIND);
5663 for (int i = 0; i <= to_index; ++i) {
5664 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
5665 T stub(kind);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005666 stub.GetCode(isolate);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005667 if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE ||
5668 (!FLAG_track_allocation_sites &&
5669 (kind == initial_kind || kind == initial_holey_kind))) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005670 T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005671 stub1.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005672 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005673 }
5674}
5675
5676
5677void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) {
5678 ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
5679 isolate);
5680 ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
5681 isolate);
5682 ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
5683 isolate);
5684}
5685
5686
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005687void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(
5688 Isolate* isolate) {
5689 ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS };
5690 for (int i = 0; i < 2; i++) {
5691 // For internal arrays we only need a few things
5692 InternalArrayNoArgumentConstructorStub stubh1(kinds[i]);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005693 stubh1.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005694 InternalArraySingleArgumentConstructorStub stubh2(kinds[i]);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005695 stubh2.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005696 InternalArrayNArgumentsConstructorStub stubh3(kinds[i]);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005697 stubh3.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005698 }
5699}
5700
5701
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005702void ArrayConstructorStub::GenerateDispatchToArrayStub(
5703 MacroAssembler* masm,
5704 AllocationSiteOverrideMode mode) {
5705 if (argument_count_ == ANY) {
5706 Label not_zero_case, not_one_case;
5707 __ tst(r0, r0);
5708 __ b(ne, &not_zero_case);
5709 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
5710
5711 __ bind(&not_zero_case);
5712 __ cmp(r0, Operand(1));
5713 __ b(gt, &not_one_case);
5714 CreateArrayDispatchOneArgument(masm, mode);
5715
5716 __ bind(&not_one_case);
5717 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
5718 } else if (argument_count_ == NONE) {
5719 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
5720 } else if (argument_count_ == ONE) {
5721 CreateArrayDispatchOneArgument(masm, mode);
5722 } else if (argument_count_ == MORE_THAN_ONE) {
5723 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
5724 } else {
5725 UNREACHABLE();
5726 }
5727}
5728
5729
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005730void ArrayConstructorStub::Generate(MacroAssembler* masm) {
5731 // ----------- S t a t e -------------
5732 // -- r0 : argc (only if argument_count_ == ANY)
5733 // -- r1 : constructor
5734 // -- r2 : type info cell
5735 // -- sp[0] : return address
5736 // -- sp[4] : last argument
5737 // -----------------------------------
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005738 if (FLAG_debug_code) {
5739 // The array construct code is only set for the global and natives
5740 // builtin Array functions which always have maps.
5741
5742 // Initial map for the builtin Array function should be a map.
5743 __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
5744 // Will both indicate a NULL and a Smi.
5745 __ tst(r3, Operand(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00005746 __ Assert(ne, kUnexpectedInitialMapForArrayFunction);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005747 __ CompareObjectType(r3, r3, r4, MAP_TYPE);
danno@chromium.org59400602013-08-13 17:09:37 +00005748 __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005749
danno@chromium.org41728482013-06-12 22:31:22 +00005750 // We should either have undefined in ebx or a valid cell
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005751 Label okay_here;
danno@chromium.org41728482013-06-12 22:31:22 +00005752 Handle<Map> cell_map = masm->isolate()->factory()->cell_map();
danno@chromium.orgbee51992013-07-10 14:57:15 +00005753 __ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005754 __ b(eq, &okay_here);
5755 __ ldr(r3, FieldMemOperand(r2, 0));
danno@chromium.org41728482013-06-12 22:31:22 +00005756 __ cmp(r3, Operand(cell_map));
danno@chromium.org59400602013-08-13 17:09:37 +00005757 __ Assert(eq, kExpectedPropertyCellInRegisterEbx);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005758 __ bind(&okay_here);
5759 }
5760
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005761 Label no_info;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005762 // Get the elements kind and case on that.
danno@chromium.orgbee51992013-07-10 14:57:15 +00005763 __ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005764 __ b(eq, &no_info);
5765 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset));
danno@chromium.orgbee51992013-07-10 14:57:15 +00005766
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005767 // If the type cell is undefined, or contains anything other than an
5768 // AllocationSite, call an array constructor that doesn't use AllocationSites.
danno@chromium.orgbee51992013-07-10 14:57:15 +00005769 __ ldr(r4, FieldMemOperand(r3, 0));
5770 __ CompareRoot(r4, Heap::kAllocationSiteMapRootIndex);
5771 __ b(ne, &no_info);
5772
5773 __ ldr(r3, FieldMemOperand(r3, AllocationSite::kTransitionInfoOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005774 __ SmiUntag(r3);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005775 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
5776 __ and_(r3, r3, Operand(AllocationSite::ElementsKindBits::kMask));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005777 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
5778
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005779 __ bind(&no_info);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005780 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005781}
5782
5783
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005784void InternalArrayConstructorStub::GenerateCase(
5785 MacroAssembler* masm, ElementsKind kind) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005786 __ cmp(r0, Operand(1));
ulan@chromium.org9ca30172014-01-02 12:10:54 +00005787
5788 InternalArrayNoArgumentConstructorStub stub0(kind);
5789 __ TailCallStub(&stub0, lo);
5790
5791 InternalArrayNArgumentsConstructorStub stubN(kind);
5792 __ TailCallStub(&stubN, hi);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005793
5794 if (IsFastPackedElementsKind(kind)) {
5795 // We might need to create a holey array
5796 // look at the first argument
5797 __ ldr(r3, MemOperand(sp, 0));
5798 __ cmp(r3, Operand::Zero());
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005799
5800 InternalArraySingleArgumentConstructorStub
5801 stub1_holey(GetHoleyElementsKind(kind));
ulan@chromium.org9ca30172014-01-02 12:10:54 +00005802 __ TailCallStub(&stub1_holey, ne);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005803 }
5804
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005805 InternalArraySingleArgumentConstructorStub stub1(kind);
5806 __ TailCallStub(&stub1);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005807}
5808
5809
5810void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
5811 // ----------- S t a t e -------------
5812 // -- r0 : argc
5813 // -- r1 : constructor
5814 // -- sp[0] : return address
5815 // -- sp[4] : last argument
5816 // -----------------------------------
5817
5818 if (FLAG_debug_code) {
5819 // The array construct code is only set for the global and natives
5820 // builtin Array functions which always have maps.
5821
5822 // Initial map for the builtin Array function should be a map.
5823 __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
5824 // Will both indicate a NULL and a Smi.
5825 __ tst(r3, Operand(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00005826 __ Assert(ne, kUnexpectedInitialMapForArrayFunction);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005827 __ CompareObjectType(r3, r3, r4, MAP_TYPE);
danno@chromium.org59400602013-08-13 17:09:37 +00005828 __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005829 }
5830
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005831 // Figure out the right elements kind
5832 __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
5833 // Load the map's "bit field 2" into |result|. We only need the first byte,
5834 // but the following bit field extraction takes care of that anyway.
5835 __ ldr(r3, FieldMemOperand(r3, Map::kBitField2Offset));
5836 // Retrieve elements_kind from bit field 2.
5837 __ Ubfx(r3, r3, Map::kElementsKindShift, Map::kElementsKindBitCount);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005838
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005839 if (FLAG_debug_code) {
5840 Label done;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005841 __ cmp(r3, Operand(FAST_ELEMENTS));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005842 __ b(eq, &done);
5843 __ cmp(r3, Operand(FAST_HOLEY_ELEMENTS));
5844 __ Assert(eq,
danno@chromium.org59400602013-08-13 17:09:37 +00005845 kInvalidElementsKindForInternalArrayOrInternalPackedArray);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005846 __ bind(&done);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005847 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005848
5849 Label fast_elements_case;
5850 __ cmp(r3, Operand(FAST_ELEMENTS));
5851 __ b(eq, &fast_elements_case);
5852 GenerateCase(masm, FAST_HOLEY_ELEMENTS);
5853
5854 __ bind(&fast_elements_case);
5855 GenerateCase(masm, FAST_ELEMENTS);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005856}
5857
5858
ricow@chromium.org65fae842010-08-25 15:26:24 +00005859#undef __
5860
5861} } // namespace v8::internal
5862
5863#endif // V8_TARGET_ARCH_ARM