blob: 5c5231bb8861f2c5be13e52e4c8b54cac5ebefa8 [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;
68 descriptor->deoptimization_handler_ = NULL;
69}
70
71
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000072void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
73 Isolate* isolate,
74 CodeStubInterfaceDescriptor* descriptor) {
75 static Register registers[] = { r3, r2, r1 };
76 descriptor->register_param_count_ = 3;
77 descriptor->register_params_ = registers;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000078 descriptor->deoptimization_handler_ =
79 Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
80}
81
82
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000083void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
84 Isolate* isolate,
85 CodeStubInterfaceDescriptor* descriptor) {
86 static Register registers[] = { r3, r2, r1, r0 };
87 descriptor->register_param_count_ = 4;
88 descriptor->register_params_ = registers;
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000089 descriptor->deoptimization_handler_ =
machenbach@chromium.org528ce022013-09-23 14:09:36 +000090 Runtime::FunctionForId(Runtime::kCreateObjectLiteral)->entry;
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000091}
92
93
danno@chromium.orgbee51992013-07-10 14:57:15 +000094void CreateAllocationSiteStub::InitializeInterfaceDescriptor(
95 Isolate* isolate,
96 CodeStubInterfaceDescriptor* descriptor) {
97 static Register registers[] = { r2 };
98 descriptor->register_param_count_ = 1;
99 descriptor->register_params_ = registers;
100 descriptor->deoptimization_handler_ = NULL;
101}
102
103
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000104void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
105 Isolate* isolate,
106 CodeStubInterfaceDescriptor* descriptor) {
107 static Register registers[] = { r1, r0 };
108 descriptor->register_param_count_ = 2;
109 descriptor->register_params_ = registers;
110 descriptor->deoptimization_handler_ =
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000111 FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000112}
113
114
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000115void LoadFieldStub::InitializeInterfaceDescriptor(
116 Isolate* isolate,
117 CodeStubInterfaceDescriptor* descriptor) {
118 static Register registers[] = { r0 };
119 descriptor->register_param_count_ = 1;
120 descriptor->register_params_ = registers;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000121 descriptor->deoptimization_handler_ = NULL;
122}
123
124
125void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
126 Isolate* isolate,
127 CodeStubInterfaceDescriptor* descriptor) {
128 static Register registers[] = { r1 };
129 descriptor->register_param_count_ = 1;
130 descriptor->register_params_ = registers;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000131 descriptor->deoptimization_handler_ = NULL;
132}
133
134
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000135void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
136 Isolate* isolate,
137 CodeStubInterfaceDescriptor* descriptor) {
138 static Register registers[] = { r2, r1, r0 };
139 descriptor->register_param_count_ = 3;
140 descriptor->register_params_ = registers;
141 descriptor->deoptimization_handler_ =
142 FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure);
143}
144
145
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000146void TransitionElementsKindStub::InitializeInterfaceDescriptor(
147 Isolate* isolate,
148 CodeStubInterfaceDescriptor* descriptor) {
149 static Register registers[] = { r0, r1 };
150 descriptor->register_param_count_ = 2;
151 descriptor->register_params_ = registers;
152 Address entry =
153 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry;
154 descriptor->deoptimization_handler_ = FUNCTION_ADDR(entry);
155}
156
157
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000158void CompareNilICStub::InitializeInterfaceDescriptor(
159 Isolate* isolate,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000160 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000161 static Register registers[] = { r0 };
162 descriptor->register_param_count_ = 1;
163 descriptor->register_params_ = registers;
164 descriptor->deoptimization_handler_ =
165 FUNCTION_ADDR(CompareNilIC_Miss);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000166 descriptor->SetMissHandler(
167 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate));
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000168}
169
170
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000171void BinaryOpStub::InitializeInterfaceDescriptor(
172 Isolate* isolate,
173 CodeStubInterfaceDescriptor* descriptor) {
174 static Register registers[] = { r1, r0 };
175 descriptor->register_param_count_ = 2;
176 descriptor->register_params_ = registers;
177 descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss);
178 descriptor->SetMissHandler(
179 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
180}
181
182
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000183static void InitializeArrayConstructorDescriptor(
184 Isolate* isolate,
185 CodeStubInterfaceDescriptor* descriptor,
186 int constant_stack_parameter_count) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000187 // register state
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000188 // r0 -- number of arguments
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000189 // r1 -- function
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000190 // r2 -- type info cell with elements kind
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000191 static Register registers[] = { r1, r2 };
192 descriptor->register_param_count_ = 2;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000193 if (constant_stack_parameter_count != 0) {
194 // stack param count needs (constructor pointer, and single argument)
195 descriptor->stack_parameter_count_ = &r0;
196 }
197 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000198 descriptor->register_params_ = registers;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000199 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000200 descriptor->deoptimization_handler_ =
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000201 Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000202}
203
204
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000205static void InitializeInternalArrayConstructorDescriptor(
206 Isolate* isolate,
207 CodeStubInterfaceDescriptor* descriptor,
208 int constant_stack_parameter_count) {
209 // register state
210 // r0 -- number of arguments
211 // r1 -- constructor function
212 static Register registers[] = { r1 };
213 descriptor->register_param_count_ = 1;
214
215 if (constant_stack_parameter_count != 0) {
216 // stack param count needs (constructor pointer, and single argument)
217 descriptor->stack_parameter_count_ = &r0;
218 }
219 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
220 descriptor->register_params_ = registers;
221 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
222 descriptor->deoptimization_handler_ =
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000223 Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000224}
225
226
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000227void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
228 Isolate* isolate,
229 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000230 InitializeArrayConstructorDescriptor(isolate, descriptor, 0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000231}
232
233
234void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
235 Isolate* isolate,
236 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000237 InitializeArrayConstructorDescriptor(isolate, descriptor, 1);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000238}
239
240
241void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
242 Isolate* isolate,
243 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000244 InitializeArrayConstructorDescriptor(isolate, descriptor, -1);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000245}
246
247
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000248void ToBooleanStub::InitializeInterfaceDescriptor(
249 Isolate* isolate,
250 CodeStubInterfaceDescriptor* descriptor) {
251 static Register registers[] = { r0 };
252 descriptor->register_param_count_ = 1;
253 descriptor->register_params_ = registers;
254 descriptor->deoptimization_handler_ =
255 FUNCTION_ADDR(ToBooleanIC_Miss);
256 descriptor->SetMissHandler(
257 ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate));
258}
259
260
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000261void InternalArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
262 Isolate* isolate,
263 CodeStubInterfaceDescriptor* descriptor) {
264 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 0);
265}
266
267
268void InternalArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
269 Isolate* isolate,
270 CodeStubInterfaceDescriptor* descriptor) {
271 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 1);
272}
273
274
275void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
276 Isolate* isolate,
277 CodeStubInterfaceDescriptor* descriptor) {
278 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1);
279}
280
281
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000282void StoreGlobalStub::InitializeInterfaceDescriptor(
283 Isolate* isolate,
284 CodeStubInterfaceDescriptor* descriptor) {
285 static Register registers[] = { r1, r2, r0 };
286 descriptor->register_param_count_ = 3;
287 descriptor->register_params_ = registers;
288 descriptor->deoptimization_handler_ =
289 FUNCTION_ADDR(StoreIC_MissFromStubFailure);
290}
291
292
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000293void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
294 Isolate* isolate,
295 CodeStubInterfaceDescriptor* descriptor) {
296 static Register registers[] = { r0, r3, r1, r2 };
297 descriptor->register_param_count_ = 4;
298 descriptor->register_params_ = registers;
299 descriptor->deoptimization_handler_ =
300 FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss);
301}
302
303
ricow@chromium.org65fae842010-08-25 15:26:24 +0000304#define __ ACCESS_MASM(masm)
305
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000306
ricow@chromium.org65fae842010-08-25 15:26:24 +0000307static void EmitIdenticalObjectComparison(MacroAssembler* masm,
308 Label* slow,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000309 Condition cond);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000310static void EmitSmiNonsmiComparison(MacroAssembler* masm,
311 Register lhs,
312 Register rhs,
313 Label* lhs_not_nan,
314 Label* slow,
315 bool strict);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000316static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
317 Register lhs,
318 Register rhs);
319
320
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000321void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) {
322 // Update the static counter each time a new code stub is generated.
323 Isolate* isolate = masm->isolate();
324 isolate->counters()->code_stubs()->Increment();
325
326 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate);
327 int param_count = descriptor->register_param_count_;
328 {
329 // Call the runtime system in a fresh internal frame.
330 FrameScope scope(masm, StackFrame::INTERNAL);
331 ASSERT(descriptor->register_param_count_ == 0 ||
332 r0.is(descriptor->register_params_[param_count - 1]));
333 // Push arguments
334 for (int i = 0; i < param_count; ++i) {
335 __ push(descriptor->register_params_[i]);
336 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000337 ExternalReference miss = descriptor->miss_handler();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000338 __ CallExternalReference(miss, descriptor->register_param_count_);
339 }
340
341 __ Ret();
342}
343
344
ricow@chromium.org65fae842010-08-25 15:26:24 +0000345void FastNewContextStub::Generate(MacroAssembler* masm) {
346 // Try to allocate the context in new space.
347 Label gc;
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000348 int length = slots_ + Context::MIN_CONTEXT_SLOTS;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000349
350 // Attempt to allocate the context in new space.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000351 __ Allocate(FixedArray::SizeFor(length), r0, r1, r2, &gc, TAG_OBJECT);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000352
353 // Load the function from the stack.
354 __ ldr(r3, MemOperand(sp, 0));
355
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000356 // Set up the object header.
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000357 __ LoadRoot(r1, Heap::kFunctionContextMapRootIndex);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000358 __ mov(r2, Operand(Smi::FromInt(length)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000359 __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000360 __ str(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000361
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000362 // Set up the fixed slots, copy the global object from the previous context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000363 __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000364 __ mov(r1, Operand(Smi::FromInt(0)));
365 __ str(r3, MemOperand(r0, Context::SlotOffset(Context::CLOSURE_INDEX)));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000366 __ str(cp, MemOperand(r0, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000367 __ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX)));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000368 __ str(r2, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000369
370 // Initialize the rest of the slots to undefined.
371 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000372 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000373 __ str(r1, MemOperand(r0, Context::SlotOffset(i)));
374 }
375
376 // Remove the on-stack argument and return.
377 __ mov(cp, r0);
378 __ pop();
379 __ Ret();
380
381 // Need to collect. Call into runtime system.
382 __ bind(&gc);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000383 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000384}
385
386
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000387void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
388 // Stack layout on entry:
389 //
390 // [sp]: function.
391 // [sp + kPointerSize]: serialized scope info
392
393 // Try to allocate the context in new space.
394 Label gc;
395 int length = slots_ + Context::MIN_CONTEXT_SLOTS;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000396 __ Allocate(FixedArray::SizeFor(length), r0, r1, r2, &gc, TAG_OBJECT);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000397
398 // Load the function from the stack.
399 __ ldr(r3, MemOperand(sp, 0));
400
401 // Load the serialized scope info from the stack.
402 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
403
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000404 // Set up the object header.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000405 __ LoadRoot(r2, Heap::kBlockContextMapRootIndex);
406 __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
407 __ mov(r2, Operand(Smi::FromInt(length)));
408 __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset));
409
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000410 // If this block context is nested in the native context we get a smi
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000411 // sentinel instead of a function. The block context should get the
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000412 // canonical empty function of the native context as its closure which
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000413 // we still have to look up.
414 Label after_sentinel;
415 __ JumpIfNotSmi(r3, &after_sentinel);
416 if (FLAG_debug_code) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000417 __ cmp(r3, Operand::Zero());
danno@chromium.org59400602013-08-13 17:09:37 +0000418 __ Assert(eq, kExpected0AsASmiSentinel);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000419 }
420 __ ldr(r3, GlobalObjectOperand());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000421 __ ldr(r3, FieldMemOperand(r3, GlobalObject::kNativeContextOffset));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000422 __ ldr(r3, ContextOperand(r3, Context::CLOSURE_INDEX));
423 __ bind(&after_sentinel);
424
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000425 // Set up the fixed slots, copy the global object from the previous context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000426 __ ldr(r2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000427 __ str(r3, ContextOperand(r0, Context::CLOSURE_INDEX));
428 __ str(cp, ContextOperand(r0, Context::PREVIOUS_INDEX));
429 __ str(r1, ContextOperand(r0, Context::EXTENSION_INDEX));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000430 __ str(r2, ContextOperand(r0, Context::GLOBAL_OBJECT_INDEX));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000431
432 // Initialize the rest of the slots to the hole value.
433 __ LoadRoot(r1, Heap::kTheHoleValueRootIndex);
434 for (int i = 0; i < slots_; i++) {
435 __ str(r1, ContextOperand(r0, i + Context::MIN_CONTEXT_SLOTS));
436 }
437
438 // Remove the on-stack argument and return.
439 __ mov(cp, r0);
440 __ add(sp, sp, Operand(2 * kPointerSize));
441 __ Ret();
442
443 // Need to collect. Call into runtime system.
444 __ bind(&gc);
445 __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1);
446}
447
448
ricow@chromium.org65fae842010-08-25 15:26:24 +0000449// Takes a Smi and converts to an IEEE 64 bit floating point value in two
450// registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and
451// 52 fraction bits (20 in the first word, 32 in the second). Zeros is a
452// scratch register. Destroys the source register. No GC occurs during this
453// stub so you don't have to set up the frame.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000454class ConvertToDoubleStub : public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000455 public:
456 ConvertToDoubleStub(Register result_reg_1,
457 Register result_reg_2,
458 Register source_reg,
459 Register scratch_reg)
460 : result1_(result_reg_1),
461 result2_(result_reg_2),
462 source_(source_reg),
463 zeros_(scratch_reg) { }
464
465 private:
466 Register result1_;
467 Register result2_;
468 Register source_;
469 Register zeros_;
470
471 // Minor key encoding in 16 bits.
472 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
473 class OpBits: public BitField<Token::Value, 2, 14> {};
474
475 Major MajorKey() { return ConvertToDouble; }
476 int MinorKey() {
477 // Encode the parameters in a unique 16 bit value.
478 return result1_.code() +
479 (result2_.code() << 4) +
480 (source_.code() << 8) +
481 (zeros_.code() << 12);
482 }
483
484 void Generate(MacroAssembler* masm);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000485};
486
487
488void ConvertToDoubleStub::Generate(MacroAssembler* masm) {
danno@chromium.org160a7b02011-04-18 15:51:38 +0000489 Register exponent = result1_;
490 Register mantissa = result2_;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000491
ricow@chromium.org65fae842010-08-25 15:26:24 +0000492 Label not_special;
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000493 __ SmiUntag(source_);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000494 // Move sign bit from source to destination. This works because the sign bit
495 // in the exponent word of the double has the same position and polarity as
496 // the 2's complement sign bit in a Smi.
497 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
498 __ and_(exponent, source_, Operand(HeapNumber::kSignMask), SetCC);
499 // Subtract from 0 if source was negative.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000500 __ rsb(source_, source_, Operand::Zero(), LeaveCC, ne);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000501
502 // We have -1, 0 or 1, which we treat specially. Register source_ contains
503 // absolute value: it is either equal to 1 (special case of -1 and 1),
504 // greater than 1 (not a special case) or less than 1 (special case of 0).
505 __ cmp(source_, Operand(1));
506 __ b(gt, &not_special);
507
508 // For 1 or -1 we need to or in the 0 exponent (biased to 1023).
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000509 const uint32_t exponent_word_for_1 =
ricow@chromium.org65fae842010-08-25 15:26:24 +0000510 HeapNumber::kExponentBias << HeapNumber::kExponentShift;
511 __ orr(exponent, exponent, Operand(exponent_word_for_1), LeaveCC, eq);
512 // 1, 0 and -1 all have 0 for the second word.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000513 __ mov(mantissa, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000514 __ Ret();
515
516 __ bind(&not_special);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000517 __ clz(zeros_, source_);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000518 // Compute exponent and or it into the exponent register.
519 // We use mantissa as a scratch register here. Use a fudge factor to
520 // divide the constant 31 + HeapNumber::kExponentBias, 0x41d, into two parts
521 // that fit in the ARM's constant field.
522 int fudge = 0x400;
523 __ rsb(mantissa, zeros_, Operand(31 + HeapNumber::kExponentBias - fudge));
524 __ add(mantissa, mantissa, Operand(fudge));
525 __ orr(exponent,
526 exponent,
527 Operand(mantissa, LSL, HeapNumber::kExponentShift));
528 // Shift up the source chopping the top bit off.
529 __ add(zeros_, zeros_, Operand(1));
530 // This wouldn't work for 1.0 or -1.0 as the shift would be 32 which means 0.
531 __ mov(source_, Operand(source_, LSL, zeros_));
532 // Compute lower part of fraction (last 12 bits).
533 __ mov(mantissa, Operand(source_, LSL, HeapNumber::kMantissaBitsInTopWord));
534 // And the top (top 20 bits).
535 __ orr(exponent,
536 exponent,
537 Operand(source_, LSR, 32 - HeapNumber::kMantissaBitsInTopWord));
538 __ Ret();
539}
540
541
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +0000542void DoubleToIStub::Generate(MacroAssembler* masm) {
543 Label out_of_range, only_low, negate, done;
544 Register input_reg = source();
545 Register result_reg = destination();
546
547 int double_offset = offset();
548 // Account for saved regs if input is sp.
549 if (input_reg.is(sp)) double_offset += 2 * kPointerSize;
550
551 // Immediate values for this stub fit in instructions, so it's safe to use ip.
552 Register scratch = ip;
553 Register scratch_low =
554 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch);
555 Register scratch_high =
556 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch, scratch_low);
557 LowDwVfpRegister double_scratch = kScratchDoubleReg;
558
559 __ Push(scratch_high, scratch_low);
560
561 if (!skip_fastpath()) {
562 // Load double input.
563 __ vldr(double_scratch, MemOperand(input_reg, double_offset));
564 __ vmov(scratch_low, scratch_high, double_scratch);
565
566 // Do fast-path convert from double to int.
567 __ vcvt_s32_f64(double_scratch.low(), double_scratch);
568 __ vmov(result_reg, double_scratch.low());
569
570 // If result is not saturated (0x7fffffff or 0x80000000), we are done.
571 __ sub(scratch, result_reg, Operand(1));
572 __ cmp(scratch, Operand(0x7ffffffe));
573 __ b(lt, &done);
574 } else {
575 // We've already done MacroAssembler::TryFastTruncatedDoubleToILoad, so we
576 // know exponent > 31, so we can skip the vcvt_s32_f64 which will saturate.
577 if (double_offset == 0) {
578 __ ldm(ia, input_reg, scratch_low.bit() | scratch_high.bit());
579 } else {
580 __ ldr(scratch_low, MemOperand(input_reg, double_offset));
581 __ ldr(scratch_high, MemOperand(input_reg, double_offset + kIntSize));
582 }
583 }
584
585 __ Ubfx(scratch, scratch_high,
586 HeapNumber::kExponentShift, HeapNumber::kExponentBits);
587 // Load scratch with exponent - 1. This is faster than loading
588 // with exponent because Bias + 1 = 1024 which is an *ARM* immediate value.
589 STATIC_ASSERT(HeapNumber::kExponentBias + 1 == 1024);
590 __ sub(scratch, scratch, Operand(HeapNumber::kExponentBias + 1));
591 // If exponent is greater than or equal to 84, the 32 less significant
592 // bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits),
593 // the result is 0.
594 // Compare exponent with 84 (compare exponent - 1 with 83).
595 __ cmp(scratch, Operand(83));
596 __ b(ge, &out_of_range);
597
598 // If we reach this code, 31 <= exponent <= 83.
599 // So, we don't have to handle cases where 0 <= exponent <= 20 for
600 // which we would need to shift right the high part of the mantissa.
601 // Scratch contains exponent - 1.
602 // Load scratch with 52 - exponent (load with 51 - (exponent - 1)).
603 __ rsb(scratch, scratch, Operand(51), SetCC);
604 __ b(ls, &only_low);
605 // 21 <= exponent <= 51, shift scratch_low and scratch_high
606 // to generate the result.
607 __ mov(scratch_low, Operand(scratch_low, LSR, scratch));
608 // Scratch contains: 52 - exponent.
609 // We needs: exponent - 20.
610 // So we use: 32 - scratch = 32 - 52 + exponent = exponent - 20.
611 __ rsb(scratch, scratch, Operand(32));
612 __ Ubfx(result_reg, scratch_high,
613 0, HeapNumber::kMantissaBitsInTopWord);
614 // Set the implicit 1 before the mantissa part in scratch_high.
615 __ orr(result_reg, result_reg,
616 Operand(1 << HeapNumber::kMantissaBitsInTopWord));
617 __ orr(result_reg, scratch_low, Operand(result_reg, LSL, scratch));
618 __ b(&negate);
619
620 __ bind(&out_of_range);
621 __ mov(result_reg, Operand::Zero());
622 __ b(&done);
623
624 __ bind(&only_low);
625 // 52 <= exponent <= 83, shift only scratch_low.
626 // On entry, scratch contains: 52 - exponent.
627 __ rsb(scratch, scratch, Operand::Zero());
628 __ mov(result_reg, Operand(scratch_low, LSL, scratch));
629
630 __ bind(&negate);
631 // If input was positive, scratch_high ASR 31 equals 0 and
632 // scratch_high LSR 31 equals zero.
633 // New result = (result eor 0) + 0 = result.
634 // If the input was negative, we have to negate the result.
635 // Input_high ASR 31 equals 0xffffffff and scratch_high LSR 31 equals 1.
636 // New result = (result eor 0xffffffff) + 1 = 0 - result.
637 __ eor(result_reg, result_reg, Operand(scratch_high, ASR, 31));
638 __ add(result_reg, result_reg, Operand(scratch_high, LSR, 31));
639
640 __ bind(&done);
641
642 __ Pop(scratch_high, scratch_low);
643 __ Ret();
644}
645
646
dslomov@chromium.orge97852d2013-09-12 09:02:59 +0000647bool WriteInt32ToHeapNumberStub::IsPregenerated(Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000648 // These variants are compiled ahead of time. See next method.
649 if (the_int_.is(r1) && the_heap_number_.is(r0) && scratch_.is(r2)) {
650 return true;
651 }
652 if (the_int_.is(r2) && the_heap_number_.is(r0) && scratch_.is(r3)) {
653 return true;
654 }
655 // Other register combinations are generated as and when they are needed,
656 // so it is unsafe to call them from stubs (we can't generate a stub while
657 // we are generating a stub).
658 return false;
659}
660
661
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000662void WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(
663 Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000664 WriteInt32ToHeapNumberStub stub1(r1, r0, r2);
665 WriteInt32ToHeapNumberStub stub2(r2, r0, r3);
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000666 stub1.GetCode(isolate)->set_is_pregenerated(true);
667 stub2.GetCode(isolate)->set_is_pregenerated(true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000668}
669
670
ricow@chromium.org65fae842010-08-25 15:26:24 +0000671// See comment for class.
672void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
673 Label max_negative_int;
674 // the_int_ has the answer which is a signed int32 but not a Smi.
675 // We test for the special value that has a different exponent. This test
676 // has the neat side effect of setting the flags according to the sign.
677 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
678 __ cmp(the_int_, Operand(0x80000000u));
679 __ b(eq, &max_negative_int);
680 // Set up the correct exponent in scratch_. All non-Smi int32s have the same.
681 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased).
682 uint32_t non_smi_exponent =
683 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
684 __ mov(scratch_, Operand(non_smi_exponent));
685 // Set the sign bit in scratch_ if the value was negative.
686 __ orr(scratch_, scratch_, Operand(HeapNumber::kSignMask), LeaveCC, cs);
687 // Subtract from 0 if the value was negative.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000688 __ rsb(the_int_, the_int_, Operand::Zero(), LeaveCC, cs);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000689 // We should be masking the implict first digit of the mantissa away here,
690 // but it just ends up combining harmlessly with the last digit of the
691 // exponent that happens to be 1. The sign bit is 0 so we shift 10 to get
692 // the most significant 1 to hit the last bit of the 12 bit sign and exponent.
693 ASSERT(((1 << HeapNumber::kExponentShift) & non_smi_exponent) != 0);
694 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
695 __ orr(scratch_, scratch_, Operand(the_int_, LSR, shift_distance));
696 __ str(scratch_, FieldMemOperand(the_heap_number_,
697 HeapNumber::kExponentOffset));
698 __ mov(scratch_, Operand(the_int_, LSL, 32 - shift_distance));
699 __ str(scratch_, FieldMemOperand(the_heap_number_,
700 HeapNumber::kMantissaOffset));
701 __ Ret();
702
703 __ bind(&max_negative_int);
704 // The max negative int32 is stored as a positive number in the mantissa of
705 // a double because it uses a sign bit instead of using two's complement.
706 // The actual mantissa bits stored are all 0 because the implicit most
707 // significant 1 bit is not stored.
708 non_smi_exponent += 1 << HeapNumber::kExponentShift;
709 __ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent));
710 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000711 __ mov(ip, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000712 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset));
713 __ Ret();
714}
715
716
717// Handle the case where the lhs and rhs are the same object.
718// Equality is almost reflexive (everything but NaN), so this is a test
719// for "identity and not NaN".
720static void EmitIdenticalObjectComparison(MacroAssembler* masm,
721 Label* slow,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000722 Condition cond) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000723 Label not_identical;
724 Label heap_number, return_equal;
725 __ cmp(r0, r1);
726 __ b(ne, &not_identical);
727
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000728 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000729 // so we do the second best thing - test it ourselves.
730 // They are both equal and they are not both Smis so both of them are not
731 // Smis. If it's not a heap number, then return equal.
732 if (cond == lt || cond == gt) {
733 __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE);
734 __ b(ge, slow);
735 } else {
736 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
737 __ b(eq, &heap_number);
738 // Comparing JS objects with <=, >= is complicated.
739 if (cond != eq) {
740 __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000741 __ b(ge, slow);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000742 // Normally here we fall through to return_equal, but undefined is
743 // special: (undefined == undefined) == true, but
744 // (undefined <= undefined) == false! See ECMAScript 11.8.5.
745 if (cond == le || cond == ge) {
746 __ cmp(r4, Operand(ODDBALL_TYPE));
747 __ b(ne, &return_equal);
748 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
749 __ cmp(r0, r2);
750 __ b(ne, &return_equal);
751 if (cond == le) {
752 // undefined <= undefined should fail.
753 __ mov(r0, Operand(GREATER));
754 } else {
755 // undefined >= undefined should fail.
756 __ mov(r0, Operand(LESS));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000757 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000758 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000759 }
760 }
761 }
762
763 __ bind(&return_equal);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000764 if (cond == lt) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000765 __ mov(r0, Operand(GREATER)); // Things aren't less than themselves.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000766 } else if (cond == gt) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000767 __ mov(r0, Operand(LESS)); // Things aren't greater than themselves.
768 } else {
769 __ mov(r0, Operand(EQUAL)); // Things are <=, >=, ==, === themselves.
770 }
771 __ Ret();
772
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000773 // For less and greater we don't have to check for NaN since the result of
774 // x < x is false regardless. For the others here is some code to check
775 // for NaN.
776 if (cond != lt && cond != gt) {
777 __ bind(&heap_number);
778 // It is a heap number, so return non-equal if it's NaN and equal if it's
779 // not NaN.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000780
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000781 // The representation of NaN values has all exponent bits (52..62) set,
782 // and not all mantissa bits (0..51) clear.
783 // Read top bits of double representation (second word of value).
784 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
785 // Test that exponent bits are all set.
786 __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
787 // NaNs have all-one exponents so they sign extend to -1.
788 __ cmp(r3, Operand(-1));
789 __ b(ne, &return_equal);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000790
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000791 // Shift out flag and all exponent bits, retaining only mantissa.
792 __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord));
793 // Or with all low-bits of mantissa.
794 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
795 __ orr(r0, r3, Operand(r2), SetCC);
796 // For equal we already have the right value in r0: Return zero (equal)
797 // if all bits in mantissa are zero (it's an Infinity) and non-zero if
798 // not (it's a NaN). For <= and >= we need to load r0 with the failing
799 // value if it's a NaN.
800 if (cond != eq) {
801 // All-zero means Infinity means equal.
802 __ Ret(eq);
803 if (cond == le) {
804 __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail.
805 } else {
806 __ mov(r0, Operand(LESS)); // NaN >= NaN should fail.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000807 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000808 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000809 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000810 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000811 // No fall through here.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000812
813 __ bind(&not_identical);
814}
815
816
817// See comment at call site.
818static void EmitSmiNonsmiComparison(MacroAssembler* masm,
819 Register lhs,
820 Register rhs,
821 Label* lhs_not_nan,
822 Label* slow,
823 bool strict) {
824 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
825 (lhs.is(r1) && rhs.is(r0)));
826
827 Label rhs_is_smi;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000828 __ JumpIfSmi(rhs, &rhs_is_smi);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000829
830 // Lhs is a Smi. Check whether the rhs is a heap number.
831 __ CompareObjectType(rhs, r4, r4, HEAP_NUMBER_TYPE);
832 if (strict) {
833 // If rhs is not a number and lhs is a Smi then strict equality cannot
834 // succeed. Return non-equal
835 // If rhs is r0 then there is already a non zero value in it.
836 if (!rhs.is(r0)) {
837 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne);
838 }
839 __ Ret(ne);
840 } else {
841 // Smi compared non-strictly with a non-Smi non-heap-number. Call
842 // the runtime.
843 __ b(ne, slow);
844 }
845
846 // Lhs is a smi, rhs is a number.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000847 // Convert lhs to a double in d7.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000848 __ SmiToDouble(d7, lhs);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000849 // Load the double from rhs, tagged HeapNumber r0, to d6.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000850 __ vldr(d6, rhs, HeapNumber::kValueOffset - kHeapObjectTag);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000851
852 // We now have both loaded as doubles but we can skip the lhs nan check
853 // since it's a smi.
854 __ jmp(lhs_not_nan);
855
856 __ bind(&rhs_is_smi);
857 // Rhs is a smi. Check whether the non-smi lhs is a heap number.
858 __ CompareObjectType(lhs, r4, r4, HEAP_NUMBER_TYPE);
859 if (strict) {
860 // If lhs is not a number and rhs is a smi then strict equality cannot
861 // succeed. Return non-equal.
862 // If lhs is r0 then there is already a non zero value in it.
863 if (!lhs.is(r0)) {
864 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne);
865 }
866 __ Ret(ne);
867 } else {
868 // Smi compared non-strictly with a non-smi non-heap-number. Call
869 // the runtime.
870 __ b(ne, slow);
871 }
872
873 // Rhs is a smi, lhs is a heap number.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000874 // Load the double from lhs, tagged HeapNumber r1, to d7.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000875 __ vldr(d7, lhs, HeapNumber::kValueOffset - kHeapObjectTag);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000876 // Convert rhs to a double in d6 .
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000877 __ SmiToDouble(d6, rhs);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000878 // Fall through to both_loaded_as_doubles.
879}
880
881
ricow@chromium.org65fae842010-08-25 15:26:24 +0000882// See comment at call site.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000883static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
884 Register lhs,
885 Register rhs) {
886 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
887 (lhs.is(r1) && rhs.is(r0)));
888
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000889 // If either operand is a JS object or an oddball value, then they are
ricow@chromium.org65fae842010-08-25 15:26:24 +0000890 // not equal since their pointers are different.
891 // There is no test for undetectability in strict equality.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000892 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000893 Label first_non_object;
894 // Get the type of the first operand into r2 and compare it with
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000895 // FIRST_SPEC_OBJECT_TYPE.
896 __ CompareObjectType(rhs, r2, r2, FIRST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000897 __ b(lt, &first_non_object);
898
899 // Return non-zero (r0 is not zero)
900 Label return_not_equal;
901 __ bind(&return_not_equal);
902 __ Ret();
903
904 __ bind(&first_non_object);
905 // Check for oddballs: true, false, null, undefined.
906 __ cmp(r2, Operand(ODDBALL_TYPE));
907 __ b(eq, &return_not_equal);
908
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000909 __ CompareObjectType(lhs, r3, r3, FIRST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000910 __ b(ge, &return_not_equal);
911
912 // Check for oddballs: true, false, null, undefined.
913 __ cmp(r3, Operand(ODDBALL_TYPE));
914 __ b(eq, &return_not_equal);
915
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000916 // Now that we have the types we might as well check for
917 // internalized-internalized.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000918 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
919 __ orr(r2, r2, Operand(r3));
920 __ tst(r2, Operand(kIsNotStringMask | kIsNotInternalizedMask));
921 __ b(eq, &return_not_equal);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000922}
923
924
925// See comment at call site.
926static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
927 Register lhs,
928 Register rhs,
929 Label* both_loaded_as_doubles,
930 Label* not_heap_numbers,
931 Label* slow) {
932 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
933 (lhs.is(r1) && rhs.is(r0)));
934
935 __ CompareObjectType(rhs, r3, r2, HEAP_NUMBER_TYPE);
936 __ b(ne, not_heap_numbers);
937 __ ldr(r2, FieldMemOperand(lhs, HeapObject::kMapOffset));
938 __ cmp(r2, r3);
939 __ b(ne, slow); // First was a heap number, second wasn't. Go slow case.
940
941 // Both are heap numbers. Load them up then jump to the code we have
942 // for that.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000943 __ vldr(d6, rhs, HeapNumber::kValueOffset - kHeapObjectTag);
944 __ vldr(d7, lhs, HeapNumber::kValueOffset - kHeapObjectTag);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000945 __ jmp(both_loaded_as_doubles);
946}
947
948
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000949// Fast negative check for internalized-to-internalized equality.
950static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
951 Register lhs,
952 Register rhs,
953 Label* possible_strings,
954 Label* not_both_strings) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000955 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
956 (lhs.is(r1) && rhs.is(r0)));
957
958 // r2 is object type of rhs.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000959 Label object_test;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000960 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000961 __ tst(r2, Operand(kIsNotStringMask));
962 __ b(ne, &object_test);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000963 __ tst(r2, Operand(kIsNotInternalizedMask));
964 __ b(ne, possible_strings);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000965 __ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE);
966 __ b(ge, not_both_strings);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000967 __ tst(r3, Operand(kIsNotInternalizedMask));
968 __ b(ne, possible_strings);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000969
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000970 // Both are internalized. We already checked they weren't the same pointer
ricow@chromium.org65fae842010-08-25 15:26:24 +0000971 // so they are not equal.
972 __ mov(r0, Operand(NOT_EQUAL));
973 __ Ret();
974
975 __ bind(&object_test);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000976 __ cmp(r2, Operand(FIRST_SPEC_OBJECT_TYPE));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000977 __ b(lt, not_both_strings);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000978 __ CompareObjectType(lhs, r2, r3, FIRST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000979 __ b(lt, not_both_strings);
980 // If both objects are undetectable, they are equal. Otherwise, they
981 // are not equal, since they are different objects and an object is not
982 // equal to undefined.
983 __ ldr(r3, FieldMemOperand(rhs, HeapObject::kMapOffset));
984 __ ldrb(r2, FieldMemOperand(r2, Map::kBitFieldOffset));
985 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
986 __ and_(r0, r2, Operand(r3));
987 __ and_(r0, r0, Operand(1 << Map::kIsUndetectable));
988 __ eor(r0, r0, Operand(1 << Map::kIsUndetectable));
989 __ Ret();
990}
991
992
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000993static void ICCompareStub_CheckInputType(MacroAssembler* masm,
994 Register input,
995 Register scratch,
996 CompareIC::State expected,
997 Label* fail) {
998 Label ok;
999 if (expected == CompareIC::SMI) {
1000 __ JumpIfNotSmi(input, fail);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001001 } else if (expected == CompareIC::NUMBER) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001002 __ JumpIfSmi(input, &ok);
1003 __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail,
1004 DONT_DO_SMI_CHECK);
1005 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001006 // We could be strict about internalized/non-internalized here, but as long as
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001007 // hydrogen doesn't care, the stub doesn't have to care either.
1008 __ bind(&ok);
1009}
1010
1011
1012// On entry r1 and r2 are the values to be compared.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001013// On exit r0 is 0, positive or negative to indicate the result of
1014// the comparison.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001015void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
1016 Register lhs = r1;
1017 Register rhs = r0;
1018 Condition cc = GetCondition();
1019
1020 Label miss;
1021 ICCompareStub_CheckInputType(masm, lhs, r2, left_, &miss);
1022 ICCompareStub_CheckInputType(masm, rhs, r3, right_, &miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001023
1024 Label slow; // Call builtin.
1025 Label not_smis, both_loaded_as_doubles, lhs_not_nan;
1026
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001027 Label not_two_smis, smi_done;
1028 __ orr(r2, r1, r0);
1029 __ JumpIfNotSmi(r2, &not_two_smis);
1030 __ mov(r1, Operand(r1, ASR, 1));
1031 __ sub(r0, r1, Operand(r0, ASR, 1));
1032 __ Ret();
1033 __ bind(&not_two_smis);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001034
ricow@chromium.org65fae842010-08-25 15:26:24 +00001035 // NOTICE! This code is only reached after a smi-fast-case check, so
1036 // it is certain that at least one operand isn't a smi.
1037
1038 // Handle the case where the objects are identical. Either returns the answer
1039 // or goes to slow. Only falls through if the objects were not identical.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001040 EmitIdenticalObjectComparison(masm, &slow, cc);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001041
1042 // If either is a Smi (we know that not both are), then they can only
1043 // be strictly equal if the other is a HeapNumber.
1044 STATIC_ASSERT(kSmiTag == 0);
1045 ASSERT_EQ(0, Smi::FromInt(0));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001046 __ and_(r2, lhs, Operand(rhs));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001047 __ JumpIfNotSmi(r2, &not_smis);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001048 // One operand is a smi. EmitSmiNonsmiComparison generates code that can:
1049 // 1) Return the answer.
1050 // 2) Go to slow.
1051 // 3) Fall through to both_loaded_as_doubles.
1052 // 4) Jump to lhs_not_nan.
1053 // In cases 3 and 4 we have found out we were dealing with a number-number
1054 // comparison. If VFP3 is supported the double values of the numbers have
1055 // been loaded into d7 and d6. Otherwise, the double values have been loaded
1056 // into r0, r1, r2, and r3.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001057 EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001058
1059 __ bind(&both_loaded_as_doubles);
1060 // The arguments have been converted to doubles and stored in d6 and d7, if
1061 // VFP3 is supported, or in r0, r1, r2, and r3.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001062 Isolate* isolate = masm->isolate();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001063 __ bind(&lhs_not_nan);
1064 Label no_nan;
1065 // ARMv7 VFP3 instructions to implement double precision comparison.
1066 __ VFPCompareAndSetFlags(d7, d6);
1067 Label nan;
1068 __ b(vs, &nan);
1069 __ mov(r0, Operand(EQUAL), LeaveCC, eq);
1070 __ mov(r0, Operand(LESS), LeaveCC, lt);
1071 __ mov(r0, Operand(GREATER), LeaveCC, gt);
1072 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001073
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001074 __ bind(&nan);
1075 // If one of the sides was a NaN then the v flag is set. Load r0 with
1076 // whatever it takes to make the comparison fail, since comparisons with NaN
1077 // always fail.
1078 if (cc == lt || cc == le) {
1079 __ mov(r0, Operand(GREATER));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001080 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001081 __ mov(r0, Operand(LESS));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001082 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001083 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001084
1085 __ bind(&not_smis);
1086 // At this point we know we are dealing with two different objects,
1087 // and neither of them is a Smi. The objects are in rhs_ and lhs_.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001088 if (strict()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001089 // This returns non-equal for some object types, or falls through if it
1090 // was not lucky.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001091 EmitStrictTwoHeapObjectCompare(masm, lhs, rhs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001092 }
1093
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001094 Label check_for_internalized_strings;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001095 Label flat_string_check;
1096 // Check for heap-number-heap-number comparison. Can jump to slow case,
1097 // or load both doubles into r0, r1, r2, r3 and jump to the code that handles
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001098 // that case. If the inputs are not doubles then jumps to
1099 // check_for_internalized_strings.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001100 // In this case r2 will contain the type of rhs_. Never falls through.
1101 EmitCheckForTwoHeapNumbers(masm,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001102 lhs,
1103 rhs,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001104 &both_loaded_as_doubles,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001105 &check_for_internalized_strings,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001106 &flat_string_check);
1107
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001108 __ bind(&check_for_internalized_strings);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001109 // In the strict case the EmitStrictTwoHeapObjectCompare already took care of
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001110 // internalized strings.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001111 if (cc == eq && !strict()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001112 // Returns an answer for two internalized strings or two detectable objects.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001113 // Otherwise jumps to string case or not both strings case.
1114 // Assumes that r2 is the type of rhs_ on entry.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001115 EmitCheckForInternalizedStringsOrObjects(
1116 masm, lhs, rhs, &flat_string_check, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001117 }
1118
1119 // Check for both being sequential ASCII strings, and inline if that is the
1120 // case.
1121 __ bind(&flat_string_check);
1122
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001123 __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs, rhs, r2, r3, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001124
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001125 __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001126 if (cc == eq) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001127 StringCompareStub::GenerateFlatAsciiStringEquals(masm,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001128 lhs,
1129 rhs,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001130 r2,
1131 r3,
lrn@chromium.org1c092762011-05-09 09:42:16 +00001132 r4);
1133 } else {
1134 StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001135 lhs,
1136 rhs,
lrn@chromium.org1c092762011-05-09 09:42:16 +00001137 r2,
1138 r3,
1139 r4,
1140 r5);
1141 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001142 // Never falls through to here.
1143
1144 __ bind(&slow);
1145
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001146 __ Push(lhs, rhs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001147 // Figure out which native to call and setup the arguments.
1148 Builtins::JavaScript native;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001149 if (cc == eq) {
1150 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001151 } else {
1152 native = Builtins::COMPARE;
1153 int ncr; // NaN compare result
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001154 if (cc == lt || cc == le) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001155 ncr = GREATER;
1156 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001157 ASSERT(cc == gt || cc == ge); // remaining cases
ricow@chromium.org65fae842010-08-25 15:26:24 +00001158 ncr = LESS;
1159 }
1160 __ mov(r0, Operand(Smi::FromInt(ncr)));
1161 __ push(r0);
1162 }
1163
1164 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
1165 // tagged as a small integer.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001166 __ InvokeBuiltin(native, JUMP_FUNCTION);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001167
1168 __ bind(&miss);
1169 GenerateMiss(masm);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001170}
1171
1172
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001173void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
1174 // We don't allow a GC during a store buffer overflow so there is no need to
1175 // store the registers in any particular way, but we do have to store and
1176 // restore them.
1177 __ stm(db_w, sp, kCallerSaved | lr.bit());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001178
1179 const Register scratch = r1;
1180
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001181 if (save_doubles_ == kSaveFPRegs) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001182 __ SaveFPRegs(sp, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001183 }
1184 const int argument_count = 1;
1185 const int fp_argument_count = 0;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001186
1187 AllowExternalCallThatCantCauseGC scope(masm);
1188 __ PrepareCallCFunction(argument_count, fp_argument_count, scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001189 __ mov(r0, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001190 __ CallCFunction(
1191 ExternalReference::store_buffer_overflow_function(masm->isolate()),
1192 argument_count);
1193 if (save_doubles_ == kSaveFPRegs) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001194 __ RestoreFPRegs(sp, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001195 }
1196 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0).
1197}
1198
1199
ricow@chromium.org65fae842010-08-25 15:26:24 +00001200void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001201 // Untagged case: double input in d2, double result goes
1202 // into d2.
1203 // Tagged case: tagged input on top of stack and in r0,
1204 // tagged result (heap number) goes into r0.
1205
ricow@chromium.org65fae842010-08-25 15:26:24 +00001206 Label input_not_smi;
1207 Label loaded;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001208 Label calculate;
1209 Label invalid_cache;
1210 const Register scratch0 = r9;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001211 Register scratch1 = no_reg; // will be r4
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001212 const Register cache_entry = r0;
1213 const bool tagged = (argument_type_ == TAGGED);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001214
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001215 if (tagged) {
1216 // Argument is a number and is on stack and in r0.
1217 // Load argument and check if it is a smi.
1218 __ JumpIfNotSmi(r0, &input_not_smi);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001219
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001220 // Input is a smi. Convert to double and load the low and high words
1221 // of the double into r2, r3.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001222 __ SmiToDouble(d7, r0);
1223 __ vmov(r2, r3, d7);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001224 __ b(&loaded);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001225
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001226 __ bind(&input_not_smi);
1227 // Check if input is a HeapNumber.
1228 __ CheckMap(r0,
1229 r1,
1230 Heap::kHeapNumberMapRootIndex,
1231 &calculate,
1232 DONT_DO_SMI_CHECK);
1233 // Input is a HeapNumber. Load it to a double register and store the
1234 // low and high words into r2, r3.
1235 __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
1236 __ vmov(r2, r3, d0);
1237 } else {
1238 // Input is untagged double in d2. Output goes to d2.
1239 __ vmov(r2, r3, d2);
1240 }
1241 __ bind(&loaded);
1242 // r2 = low 32 bits of double value
1243 // r3 = high 32 bits of double value
1244 // Compute hash (the shifts are arithmetic):
1245 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
1246 __ eor(r1, r2, Operand(r3));
1247 __ eor(r1, r1, Operand(r1, ASR, 16));
1248 __ eor(r1, r1, Operand(r1, ASR, 8));
1249 ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
1250 __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001251
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001252 // r2 = low 32 bits of double value.
1253 // r3 = high 32 bits of double value.
1254 // r1 = TranscendentalCache::hash(double value).
1255 Isolate* isolate = masm->isolate();
1256 ExternalReference cache_array =
1257 ExternalReference::transcendental_cache_array_address(isolate);
1258 __ mov(cache_entry, Operand(cache_array));
1259 // cache_entry points to cache array.
1260 int cache_array_index
1261 = type_ * sizeof(isolate->transcendental_cache()->caches_[0]);
1262 __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index));
1263 // r0 points to the cache for the type type_.
1264 // If NULL, the cache hasn't been initialized yet, so go through runtime.
1265 __ cmp(cache_entry, Operand::Zero());
1266 __ b(eq, &invalid_cache);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001267
1268#ifdef DEBUG
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001269 // Check that the layout of cache elements match expectations.
1270 { TranscendentalCache::SubCache::Element test_elem[2];
1271 char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
1272 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
1273 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
1274 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
1275 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
1276 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
1277 CHECK_EQ(0, elem_in0 - elem_start);
1278 CHECK_EQ(kIntSize, elem_in1 - elem_start);
1279 CHECK_EQ(2 * kIntSize, elem_out - elem_start);
1280 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001281#endif
1282
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001283 // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12].
1284 __ add(r1, r1, Operand(r1, LSL, 1));
1285 __ add(cache_entry, cache_entry, Operand(r1, LSL, 2));
1286 // Check if cache matches: Double value is stored in uint32_t[2] array.
1287 __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit());
1288 __ cmp(r2, r4);
1289 __ cmp(r3, r5, eq);
1290 __ b(ne, &calculate);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001291
1292 scratch1 = r4; // Start of scratch1 range.
1293
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001294 // Cache hit. Load result, cleanup and return.
1295 Counters* counters = masm->isolate()->counters();
1296 __ IncrementCounter(
1297 counters->transcendental_cache_hit(), 1, scratch0, scratch1);
1298 if (tagged) {
1299 // Pop input value from stack and load result into r0.
1300 __ pop();
1301 __ mov(r0, Operand(r6));
1302 } else {
1303 // Load result into d2.
1304 __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
1305 }
1306 __ Ret();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001307
1308 __ bind(&calculate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001309 __ IncrementCounter(
1310 counters->transcendental_cache_miss(), 1, scratch0, scratch1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001311 if (tagged) {
1312 __ bind(&invalid_cache);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001313 ExternalReference runtime_function =
1314 ExternalReference(RuntimeFunction(), masm->isolate());
1315 __ TailCallExternalReference(runtime_function, 1, 1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001316 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001317 Label no_update;
1318 Label skip_cache;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001319
1320 // Call C function to calculate the result and update the cache.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001321 // r0: precalculated cache entry address.
1322 // r2 and r3: parts of the double value.
1323 // Store r0, r2 and r3 on stack for later before calling C function.
1324 __ Push(r3, r2, cache_entry);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001325 GenerateCallCFunction(masm, scratch0);
1326 __ GetCFunctionDoubleResult(d2);
1327
1328 // Try to update the cache. If we cannot allocate a
1329 // heap number, we return the result without updating.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001330 __ Pop(r3, r2, cache_entry);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001331 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex);
1332 __ AllocateHeapNumber(r6, scratch0, scratch1, r5, &no_update);
1333 __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
1334 __ stm(ia, cache_entry, r2.bit() | r3.bit() | r6.bit());
1335 __ Ret();
1336
1337 __ bind(&invalid_cache);
1338 // The cache is invalid. Call runtime which will recreate the
1339 // cache.
1340 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex);
1341 __ AllocateHeapNumber(r0, scratch0, scratch1, r5, &skip_cache);
1342 __ vstr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001343 {
1344 FrameScope scope(masm, StackFrame::INTERNAL);
1345 __ push(r0);
1346 __ CallRuntime(RuntimeFunction(), 1);
1347 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001348 __ vldr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset));
1349 __ Ret();
1350
1351 __ bind(&skip_cache);
1352 // Call C function to calculate the result and answer directly
1353 // without updating the cache.
1354 GenerateCallCFunction(masm, scratch0);
1355 __ GetCFunctionDoubleResult(d2);
1356 __ bind(&no_update);
1357
1358 // We return the value in d2 without adding it to the cache, but
1359 // we cause a scavenging GC so that future allocations will succeed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001360 {
1361 FrameScope scope(masm, StackFrame::INTERNAL);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001362
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001363 // Allocate an aligned object larger than a HeapNumber.
1364 ASSERT(4 * kPointerSize >= HeapNumber::kSize);
1365 __ mov(scratch0, Operand(4 * kPointerSize));
1366 __ push(scratch0);
1367 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
1368 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001369 __ Ret();
1370 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001371}
ricow@chromium.org65fae842010-08-25 15:26:24 +00001372
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001373
1374void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm,
1375 Register scratch) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001376 Isolate* isolate = masm->isolate();
1377
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001378 __ push(lr);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001379 __ PrepareCallCFunction(0, 1, scratch);
1380 if (masm->use_eabi_hardfloat()) {
1381 __ vmov(d0, d2);
1382 } else {
1383 __ vmov(r0, r1, d2);
1384 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001385 AllowExternalCallThatCantCauseGC scope(masm);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001386 switch (type_) {
1387 case TranscendentalCache::SIN:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001388 __ CallCFunction(ExternalReference::math_sin_double_function(isolate),
1389 0, 1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001390 break;
1391 case TranscendentalCache::COS:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001392 __ CallCFunction(ExternalReference::math_cos_double_function(isolate),
1393 0, 1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001394 break;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001395 case TranscendentalCache::TAN:
1396 __ CallCFunction(ExternalReference::math_tan_double_function(isolate),
1397 0, 1);
1398 break;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001399 case TranscendentalCache::LOG:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001400 __ CallCFunction(ExternalReference::math_log_double_function(isolate),
1401 0, 1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001402 break;
1403 default:
1404 UNIMPLEMENTED();
1405 break;
1406 }
1407 __ pop(lr);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001408}
1409
1410
1411Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
1412 switch (type_) {
1413 // Add more cases when necessary.
1414 case TranscendentalCache::SIN: return Runtime::kMath_sin;
1415 case TranscendentalCache::COS: return Runtime::kMath_cos;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001416 case TranscendentalCache::TAN: return Runtime::kMath_tan;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001417 case TranscendentalCache::LOG: return Runtime::kMath_log;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001418 default:
1419 UNIMPLEMENTED();
1420 return Runtime::kAbort;
1421 }
1422}
1423
1424
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001425void MathPowStub::Generate(MacroAssembler* masm) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001426 const Register base = r1;
1427 const Register exponent = r2;
1428 const Register heapnumbermap = r5;
1429 const Register heapnumber = r0;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001430 const DwVfpRegister double_base = d1;
1431 const DwVfpRegister double_exponent = d2;
1432 const DwVfpRegister double_result = d3;
1433 const DwVfpRegister double_scratch = d0;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001434 const SwVfpRegister single_scratch = s0;
1435 const Register scratch = r9;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001436 const Register scratch2 = r4;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001437
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001438 Label call_runtime, done, int_exponent;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001439 if (exponent_type_ == ON_STACK) {
1440 Label base_is_smi, unpack_exponent;
1441 // The exponent and base are supplied as arguments on the stack.
1442 // This can only happen if the stub is called from non-optimized code.
1443 // Load input parameters from stack to double registers.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001444 __ ldr(base, MemOperand(sp, 1 * kPointerSize));
1445 __ ldr(exponent, MemOperand(sp, 0 * kPointerSize));
1446
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001447 __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001448
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001449 __ UntagAndJumpIfSmi(scratch, base, &base_is_smi);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001450 __ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset));
1451 __ cmp(scratch, heapnumbermap);
1452 __ b(ne, &call_runtime);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001453
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001454 __ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
1455 __ jmp(&unpack_exponent);
1456
1457 __ bind(&base_is_smi);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001458 __ vmov(single_scratch, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001459 __ vcvt_f64_s32(double_base, single_scratch);
1460 __ bind(&unpack_exponent);
1461
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001462 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001463
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001464 __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset));
1465 __ cmp(scratch, heapnumbermap);
1466 __ b(ne, &call_runtime);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001467 __ vldr(double_exponent,
1468 FieldMemOperand(exponent, HeapNumber::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001469 } else if (exponent_type_ == TAGGED) {
1470 // Base is already in double_base.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001471 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001472
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001473 __ vldr(double_exponent,
1474 FieldMemOperand(exponent, HeapNumber::kValueOffset));
1475 }
1476
1477 if (exponent_type_ != INTEGER) {
1478 Label int_exponent_convert;
1479 // Detect integer exponents stored as double.
1480 __ vcvt_u32_f64(single_scratch, double_exponent);
1481 // We do not check for NaN or Infinity here because comparing numbers on
1482 // ARM correctly distinguishes NaNs. We end up calling the built-in.
1483 __ vcvt_f64_u32(double_scratch, single_scratch);
1484 __ VFPCompareAndSetFlags(double_scratch, double_exponent);
1485 __ b(eq, &int_exponent_convert);
1486
1487 if (exponent_type_ == ON_STACK) {
1488 // Detect square root case. Crankshaft detects constant +/-0.5 at
1489 // compile time and uses DoMathPowHalf instead. We then skip this check
1490 // for non-constant cases of +/-0.5 as these hardly occur.
1491 Label not_plus_half;
1492
1493 // Test for 0.5.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001494 __ vmov(double_scratch, 0.5, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001495 __ VFPCompareAndSetFlags(double_exponent, double_scratch);
1496 __ b(ne, &not_plus_half);
1497
1498 // Calculates square root of base. Check for the special case of
1499 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001500 __ vmov(double_scratch, -V8_INFINITY, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001501 __ VFPCompareAndSetFlags(double_base, double_scratch);
1502 __ vneg(double_result, double_scratch, eq);
1503 __ b(eq, &done);
1504
1505 // Add +0 to convert -0 to +0.
1506 __ vadd(double_scratch, double_base, kDoubleRegZero);
1507 __ vsqrt(double_result, double_scratch);
1508 __ jmp(&done);
1509
1510 __ bind(&not_plus_half);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001511 __ vmov(double_scratch, -0.5, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001512 __ VFPCompareAndSetFlags(double_exponent, double_scratch);
1513 __ b(ne, &call_runtime);
1514
1515 // Calculates square root of base. Check for the special case of
1516 // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001517 __ vmov(double_scratch, -V8_INFINITY, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001518 __ VFPCompareAndSetFlags(double_base, double_scratch);
1519 __ vmov(double_result, kDoubleRegZero, eq);
1520 __ b(eq, &done);
1521
1522 // Add +0 to convert -0 to +0.
1523 __ vadd(double_scratch, double_base, kDoubleRegZero);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001524 __ vmov(double_result, 1.0, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001525 __ vsqrt(double_scratch, double_scratch);
1526 __ vdiv(double_result, double_result, double_scratch);
1527 __ jmp(&done);
1528 }
1529
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001530 __ push(lr);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001531 {
1532 AllowExternalCallThatCantCauseGC scope(masm);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001533 __ PrepareCallCFunction(0, 2, scratch);
1534 __ SetCallCDoubleArguments(double_base, double_exponent);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001535 __ CallCFunction(
1536 ExternalReference::power_double_double_function(masm->isolate()),
1537 0, 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001538 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001539 __ pop(lr);
1540 __ GetCFunctionDoubleResult(double_result);
1541 __ jmp(&done);
1542
1543 __ bind(&int_exponent_convert);
1544 __ vcvt_u32_f64(single_scratch, double_exponent);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001545 __ vmov(scratch, single_scratch);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001546 }
1547
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001548 // Calculate power with integer exponent.
1549 __ bind(&int_exponent);
1550
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001551 // Get two copies of exponent in the registers scratch and exponent.
1552 if (exponent_type_ == INTEGER) {
1553 __ mov(scratch, exponent);
1554 } else {
1555 // Exponent has previously been stored into scratch as untagged integer.
1556 __ mov(exponent, scratch);
1557 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001558 __ vmov(double_scratch, double_base); // Back up base.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001559 __ vmov(double_result, 1.0, scratch2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001560
1561 // Get absolute value of exponent.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001562 __ cmp(scratch, Operand::Zero());
1563 __ mov(scratch2, Operand::Zero(), LeaveCC, mi);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001564 __ sub(scratch, scratch2, scratch, LeaveCC, mi);
1565
1566 Label while_true;
1567 __ bind(&while_true);
1568 __ mov(scratch, Operand(scratch, ASR, 1), SetCC);
1569 __ vmul(double_result, double_result, double_scratch, cs);
1570 __ vmul(double_scratch, double_scratch, double_scratch, ne);
1571 __ b(ne, &while_true);
1572
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001573 __ cmp(exponent, Operand::Zero());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001574 __ b(ge, &done);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001575 __ vmov(double_scratch, 1.0, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001576 __ vdiv(double_result, double_scratch, double_result);
1577 // Test whether result is zero. Bail out to check for subnormal result.
1578 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
1579 __ VFPCompareAndSetFlags(double_result, 0.0);
1580 __ b(ne, &done);
1581 // double_exponent may not containe the exponent value if the input was a
1582 // smi. We set it with exponent value before bailing out.
1583 __ vmov(single_scratch, exponent);
1584 __ vcvt_f64_s32(double_exponent, single_scratch);
1585
1586 // Returning or bailing out.
1587 Counters* counters = masm->isolate()->counters();
1588 if (exponent_type_ == ON_STACK) {
1589 // The arguments are still on the stack.
1590 __ bind(&call_runtime);
1591 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
1592
1593 // The stub is called from non-optimized code, which expects the result
1594 // as heap number in exponent.
1595 __ bind(&done);
1596 __ AllocateHeapNumber(
1597 heapnumber, scratch, scratch2, heapnumbermap, &call_runtime);
1598 __ vstr(double_result,
1599 FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
1600 ASSERT(heapnumber.is(r0));
1601 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
1602 __ Ret(2);
1603 } else {
1604 __ push(lr);
1605 {
1606 AllowExternalCallThatCantCauseGC scope(masm);
1607 __ PrepareCallCFunction(0, 2, scratch);
1608 __ SetCallCDoubleArguments(double_base, double_exponent);
1609 __ CallCFunction(
1610 ExternalReference::power_double_double_function(masm->isolate()),
1611 0, 2);
1612 }
1613 __ pop(lr);
1614 __ GetCFunctionDoubleResult(double_result);
1615
1616 __ bind(&done);
1617 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
1618 __ Ret();
1619 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001620}
1621
1622
1623bool CEntryStub::NeedsImmovableCode() {
1624 return true;
1625}
1626
1627
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00001628bool CEntryStub::IsPregenerated(Isolate* isolate) {
1629 return (!save_doubles_ || isolate->fp_stubs_generated()) &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001630 result_size_ == 1;
1631}
1632
1633
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001634void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
1635 CEntryStub::GenerateAheadOfTime(isolate);
1636 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
1637 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001638 StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001639 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001640 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001641 CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00001642 BinaryOpStub::GenerateAheadOfTime(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001643}
1644
1645
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001646void CodeStub::GenerateFPStubs(Isolate* isolate) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001647 SaveFPRegsMode mode = kSaveFPRegs;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001648 CEntryStub save_doubles(1, mode);
1649 StoreBufferOverflowStub stub(mode);
1650 // These stubs might already be in the snapshot, detect that and don't
1651 // regenerate, which would lead to code stub initialization state being messed
1652 // up.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001653 Code* save_doubles_code;
1654 if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) {
1655 save_doubles_code = *save_doubles.GetCode(isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001656 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001657 Code* store_buffer_overflow_code;
1658 if (!stub.FindCodeInCache(&store_buffer_overflow_code, isolate)) {
1659 store_buffer_overflow_code = *stub.GetCode(isolate);
1660 }
1661 save_doubles_code->set_is_pregenerated(true);
1662 store_buffer_overflow_code->set_is_pregenerated(true);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001663 isolate->set_fp_stubs_generated(true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001664}
1665
1666
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001667void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001668 CEntryStub stub(1, kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001669 Handle<Code> code = stub.GetCode(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001670 code->set_is_pregenerated(true);
1671}
1672
1673
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001674static void JumpIfOOM(MacroAssembler* masm,
1675 Register value,
1676 Register scratch,
1677 Label* oom_label) {
1678 STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
1679 STATIC_ASSERT(kFailureTag == 3);
1680 __ and_(scratch, value, Operand(0xf));
1681 __ cmp(scratch, Operand(0xf));
1682 __ b(eq, oom_label);
1683}
1684
1685
ricow@chromium.org65fae842010-08-25 15:26:24 +00001686void CEntryStub::GenerateCore(MacroAssembler* masm,
1687 Label* throw_normal_exception,
1688 Label* throw_termination_exception,
1689 Label* throw_out_of_memory_exception,
1690 bool do_gc,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001691 bool always_allocate) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001692 // r0: result parameter for PerformGC, if any
1693 // r4: number of arguments including receiver (C callee-saved)
1694 // r5: pointer to builtin function (C callee-saved)
1695 // r6: pointer to the first argument (C callee-saved)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001696 Isolate* isolate = masm->isolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001697
1698 if (do_gc) {
1699 // Passing r0.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001700 __ PrepareCallCFunction(2, 0, r1);
1701 __ mov(r1, Operand(ExternalReference::isolate_address(masm->isolate())));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001702 __ CallCFunction(ExternalReference::perform_gc_function(isolate),
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001703 2, 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001704 }
1705
1706 ExternalReference scope_depth =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001707 ExternalReference::heap_always_allocate_scope_depth(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001708 if (always_allocate) {
1709 __ mov(r0, Operand(scope_depth));
1710 __ ldr(r1, MemOperand(r0));
1711 __ add(r1, r1, Operand(1));
1712 __ str(r1, MemOperand(r0));
1713 }
1714
1715 // Call C built-in.
1716 // r0 = argc, r1 = argv
1717 __ mov(r0, Operand(r4));
1718 __ mov(r1, Operand(r6));
1719
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00001720#if V8_HOST_ARCH_ARM
ricow@chromium.org65fae842010-08-25 15:26:24 +00001721 int frame_alignment = MacroAssembler::ActivationFrameAlignment();
1722 int frame_alignment_mask = frame_alignment - 1;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001723 if (FLAG_debug_code) {
1724 if (frame_alignment > kPointerSize) {
1725 Label alignment_as_expected;
1726 ASSERT(IsPowerOf2(frame_alignment));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001727 __ tst(sp, Operand(frame_alignment_mask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001728 __ b(eq, &alignment_as_expected);
1729 // Don't use Check here, as it will call Runtime_Abort re-entering here.
1730 __ stop("Unexpected alignment");
1731 __ bind(&alignment_as_expected);
1732 }
1733 }
1734#endif
1735
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001736 __ mov(r2, Operand(ExternalReference::isolate_address(isolate)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001738 // To let the GC traverse the return address of the exit frames, we need to
1739 // know where the return address is. The CEntryStub is unmovable, so
1740 // we can store the address on the stack to be able to find it again and
1741 // we never have to restore it, because it will not change.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001742 // Compute the return address in lr to return to after the jump below. Pc is
1743 // already at '+ 8' from the current instruction but return is after three
1744 // instructions so add another 4 to pc to get the return address.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001745 {
1746 // Prevent literal pool emission before return address.
1747 Assembler::BlockConstPoolScope block_const_pool(masm);
1748 masm->add(lr, pc, Operand(4));
1749 __ str(lr, MemOperand(sp, 0));
1750 masm->Jump(r5);
1751 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001752
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001753 __ VFPEnsureFPSCRState(r2);
1754
ricow@chromium.org65fae842010-08-25 15:26:24 +00001755 if (always_allocate) {
1756 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
1757 // though (contain the result).
1758 __ mov(r2, Operand(scope_depth));
1759 __ ldr(r3, MemOperand(r2));
1760 __ sub(r3, r3, Operand(1));
1761 __ str(r3, MemOperand(r2));
1762 }
1763
1764 // check for failure result
1765 Label failure_returned;
1766 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
1767 // Lower 2 bits of r2 are 0 iff r0 has failure tag.
1768 __ add(r2, r0, Operand(1));
1769 __ tst(r2, Operand(kFailureTagMask));
1770 __ b(eq, &failure_returned);
1771
1772 // Exit C frame and return.
1773 // r0:r1: result
1774 // sp: stack pointer
1775 // fp: frame pointer
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001776 // Callee-saved register r4 still holds argc.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001777 __ LeaveExitFrame(save_doubles_, r4, true);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001778 __ mov(pc, lr);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001779
1780 // check if we should retry or throw exception
1781 Label retry;
1782 __ bind(&failure_returned);
1783 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
1784 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
1785 __ b(eq, &retry);
1786
1787 // Special handling of out of memory exceptions.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001788 JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001789
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001790 // Retrieve the pending exception.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001791 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001792 isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001793 __ ldr(r0, MemOperand(ip));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001794
1795 // See if we just retrieved an OOM exception.
1796 JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
1797
1798 // Clear the pending exception.
1799 __ mov(r3, Operand(isolate->factory()->the_hole_value()));
1800 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
1801 isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001802 __ str(r3, MemOperand(ip));
1803
1804 // Special handling of termination exceptions which are uncatchable
1805 // by javascript code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001806 __ cmp(r0, Operand(isolate->factory()->termination_exception()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001807 __ b(eq, throw_termination_exception);
1808
1809 // Handle normal exception.
1810 __ jmp(throw_normal_exception);
1811
1812 __ bind(&retry); // pass last failure (r0) as parameter (r0) when retrying
1813}
1814
1815
1816void CEntryStub::Generate(MacroAssembler* masm) {
1817 // Called from JavaScript; parameters are on stack as if calling JS function
1818 // r0: number of arguments including receiver
1819 // r1: pointer to builtin function
1820 // fp: frame pointer (restored after C call)
1821 // sp: stack pointer (restored as callee's sp after C call)
1822 // cp: current context (C callee-saved)
1823
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001824 ProfileEntryHookStub::MaybeCallEntryHook(masm);
1825
ricow@chromium.org65fae842010-08-25 15:26:24 +00001826 // Result returned in r0 or r0+r1 by default.
1827
1828 // NOTE: Invocations of builtins may return failure objects
1829 // instead of a proper result. The builtin entry handles
1830 // this by performing a garbage collection and retrying the
1831 // builtin once.
1832
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001833 // Compute the argv pointer in a callee-saved register.
1834 __ add(r6, sp, Operand(r0, LSL, kPointerSizeLog2));
1835 __ sub(r6, r6, Operand(kPointerSize));
1836
ricow@chromium.org65fae842010-08-25 15:26:24 +00001837 // Enter the exit frame that transitions from JavaScript to C++.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001838 FrameScope scope(masm, StackFrame::MANUAL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001839 __ EnterExitFrame(save_doubles_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001840
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001841 // Set up argc and the builtin function in callee-saved registers.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001842 __ mov(r4, Operand(r0));
1843 __ mov(r5, Operand(r1));
1844
ricow@chromium.org65fae842010-08-25 15:26:24 +00001845 // r4: number of arguments (C callee-saved)
1846 // r5: pointer to builtin function (C callee-saved)
1847 // r6: pointer to first argument (C callee-saved)
1848
1849 Label throw_normal_exception;
1850 Label throw_termination_exception;
1851 Label throw_out_of_memory_exception;
1852
1853 // Call into the runtime system.
1854 GenerateCore(masm,
1855 &throw_normal_exception,
1856 &throw_termination_exception,
1857 &throw_out_of_memory_exception,
1858 false,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001859 false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001860
1861 // Do space-specific GC and retry runtime call.
1862 GenerateCore(masm,
1863 &throw_normal_exception,
1864 &throw_termination_exception,
1865 &throw_out_of_memory_exception,
1866 true,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001867 false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001868
1869 // Do full GC and retry runtime call one final time.
1870 Failure* failure = Failure::InternalError();
1871 __ mov(r0, Operand(reinterpret_cast<int32_t>(failure)));
1872 GenerateCore(masm,
1873 &throw_normal_exception,
1874 &throw_termination_exception,
1875 &throw_out_of_memory_exception,
1876 true,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001877 true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001878
1879 __ bind(&throw_out_of_memory_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001880 // Set external caught exception to false.
1881 Isolate* isolate = masm->isolate();
1882 ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
1883 isolate);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001884 __ mov(r0, Operand(false, RelocInfo::NONE32));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001885 __ mov(r2, Operand(external_caught));
1886 __ str(r0, MemOperand(r2));
1887
1888 // Set pending exception and r0 to out of memory exception.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001889 Label already_have_failure;
1890 JumpIfOOM(masm, r0, ip, &already_have_failure);
1891 Failure* out_of_memory = Failure::OutOfMemoryException(0x1);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001892 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001893 __ bind(&already_have_failure);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001894 __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
1895 isolate)));
1896 __ str(r0, MemOperand(r2));
1897 // Fall through to the next label.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001898
1899 __ bind(&throw_termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001900 __ ThrowUncatchable(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001901
1902 __ bind(&throw_normal_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001903 __ Throw(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001904}
1905
1906
1907void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
1908 // r0: code entry
1909 // r1: function
1910 // r2: receiver
1911 // r3: argc
1912 // [sp+0]: argv
1913
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001914 Label invoke, handler_entry, exit;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001915
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001916 ProfileEntryHookStub::MaybeCallEntryHook(masm);
1917
ricow@chromium.org65fae842010-08-25 15:26:24 +00001918 // Called from C, so do not pop argc and args on exit (preserve sp)
1919 // No need to save register-passed args
1920 // Save callee-saved registers (incl. cp and fp), sp, and lr
1921 __ stm(db_w, sp, kCalleeSaved | lr.bit());
1922
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001923 // Save callee-saved vfp registers.
1924 __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
1925 // Set up the reserved register for 0.0.
1926 __ vmov(kDoubleRegZero, 0.0);
1927 __ VFPEnsureFPSCRState(r4);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001928
ricow@chromium.org65fae842010-08-25 15:26:24 +00001929 // Get address of argv, see stm above.
1930 // r0: code entry
1931 // r1: function
1932 // r2: receiver
1933 // r3: argc
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001934
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001935 // Set up argv in r4.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001936 int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001937 offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001938 __ ldr(r4, MemOperand(sp, offset_to_argv));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001939
1940 // Push a frame with special values setup to mark it as an entry frame.
1941 // r0: code entry
1942 // r1: function
1943 // r2: receiver
1944 // r3: argc
1945 // r4: argv
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001946 Isolate* isolate = masm->isolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001947 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001948 __ mov(r8, Operand(Smi::FromInt(marker)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001949 __ mov(r6, Operand(Smi::FromInt(marker)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001950 __ mov(r5,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001951 Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001952 __ ldr(r5, MemOperand(r5));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001953 __ mov(ip, Operand(-1)); // Push a bad frame pointer to fail if it is used.
1954 __ Push(ip, r8, r6, r5);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001955
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001956 // Set up frame pointer for the frame to be pushed.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001957 __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
1958
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001959 // If this is the outermost JS call, set js_entry_sp value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001960 Label non_outermost_js;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001961 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001962 __ mov(r5, Operand(ExternalReference(js_entry_sp)));
1963 __ ldr(r6, MemOperand(r5));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001964 __ cmp(r6, Operand::Zero());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001965 __ b(ne, &non_outermost_js);
1966 __ str(fp, MemOperand(r5));
1967 __ mov(ip, Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
1968 Label cont;
1969 __ b(&cont);
1970 __ bind(&non_outermost_js);
1971 __ mov(ip, Operand(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
1972 __ bind(&cont);
1973 __ push(ip);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001974
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001975 // Jump to a faked try block that does the invoke, with a faked catch
1976 // block that sets the pending exception.
1977 __ jmp(&invoke);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001978
1979 // Block literal pool emission whilst taking the position of the handler
1980 // entry. This avoids making the assumption that literal pools are always
1981 // emitted after an instruction is emitted, rather than before.
1982 {
1983 Assembler::BlockConstPoolScope block_const_pool(masm);
1984 __ bind(&handler_entry);
1985 handler_offset_ = handler_entry.pos();
1986 // Caught exception: Store result (exception) in the pending exception
1987 // field in the JSEnv and return a failure sentinel. Coming in here the
1988 // fp will be invalid because the PushTryHandler below sets it to 0 to
1989 // signal the existence of the JSEntry frame.
1990 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
1991 isolate)));
1992 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001993 __ str(r0, MemOperand(ip));
1994 __ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
1995 __ b(&exit);
1996
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001997 // Invoke: Link this frame into the handler chain. There's only one
1998 // handler block in this code object, so its index is 0.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001999 __ bind(&invoke);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002000 // Must preserve r0-r4, r5-r6 are available.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002001 __ PushTryHandler(StackHandler::JS_ENTRY, 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002002 // If an exception not caught by another handler occurs, this handler
2003 // returns control to the code after the bl(&invoke) above, which
2004 // restores all kCalleeSaved registers (including cp and fp) to their
2005 // saved values before returning a failure to C.
2006
2007 // Clear any pending exceptions.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002008 __ mov(r5, Operand(isolate->factory()->the_hole_value()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002009 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002010 isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002011 __ str(r5, MemOperand(ip));
2012
2013 // Invoke the function by calling through JS entry trampoline builtin.
2014 // Notice that we cannot store a reference to the trampoline code directly in
2015 // this stub, because runtime stubs are not traversed when doing GC.
2016
2017 // Expected registers by Builtins::JSEntryTrampoline
2018 // r0: code entry
2019 // r1: function
2020 // r2: receiver
2021 // r3: argc
2022 // r4: argv
2023 if (is_construct) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002024 ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002025 isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002026 __ mov(ip, Operand(construct_entry));
2027 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002028 ExternalReference entry(Builtins::kJSEntryTrampoline, isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002029 __ mov(ip, Operand(entry));
2030 }
2031 __ ldr(ip, MemOperand(ip)); // deref address
2032
2033 // Branch and link to JSEntryTrampoline. We don't use the double underscore
2034 // macro for the add instruction because we don't want the coverage tool
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002035 // inserting instructions here after we read the pc. We block literal pool
2036 // emission for the same reason.
2037 {
2038 Assembler::BlockConstPoolScope block_const_pool(masm);
2039 __ mov(lr, Operand(pc));
2040 masm->add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
2041 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002042
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002043 // Unlink this frame from the handler chain.
2044 __ PopTryHandler();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002045
2046 __ bind(&exit); // r0 holds result
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002047 // Check if the current stack frame is marked as the outermost JS frame.
2048 Label non_outermost_js_2;
2049 __ pop(r5);
2050 __ cmp(r5, Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
2051 __ b(ne, &non_outermost_js_2);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002052 __ mov(r6, Operand::Zero());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002053 __ mov(r5, Operand(ExternalReference(js_entry_sp)));
2054 __ str(r6, MemOperand(r5));
2055 __ bind(&non_outermost_js_2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002056
ricow@chromium.org65fae842010-08-25 15:26:24 +00002057 // Restore the top frame descriptors from the stack.
2058 __ pop(r3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002059 __ mov(ip,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002060 Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002061 __ str(r3, MemOperand(ip));
2062
2063 // Reset the stack to the callee saved registers.
2064 __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
2065
2066 // Restore callee-saved registers and return.
2067#ifdef DEBUG
2068 if (FLAG_debug_code) {
2069 __ mov(lr, Operand(pc));
2070 }
2071#endif
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002072
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002073 // Restore callee-saved vfp registers.
2074 __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002075
ricow@chromium.org65fae842010-08-25 15:26:24 +00002076 __ ldm(ia_w, sp, kCalleeSaved | pc.bit());
2077}
2078
2079
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002080// Uses registers r0 to r4.
2081// Expected input (depending on whether args are in registers or on the stack):
2082// * object: r0 or at sp + 1 * kPointerSize.
2083// * function: r1 or at sp.
2084//
2085// An inlined call site may have been generated before calling this stub.
2086// In this case the offset to the inline site to patch is passed on the stack,
2087// in the safepoint slot for register r4.
2088// (See LCodeGen::DoInstanceOfKnownGlobal)
ricow@chromium.org65fae842010-08-25 15:26:24 +00002089void InstanceofStub::Generate(MacroAssembler* masm) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002090 // Call site inlining and patching implies arguments in registers.
2091 ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck());
2092 // ReturnTrueFalse is only implemented for inlined call sites.
2093 ASSERT(!ReturnTrueFalseObject() || HasCallSiteInlineCheck());
2094
whesse@chromium.org023421e2010-12-21 12:19:12 +00002095 // Fixed register usage throughout the stub:
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002096 const Register object = r0; // Object (lhs).
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002097 Register map = r3; // Map of the object.
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002098 const Register function = r1; // Function (rhs).
whesse@chromium.org023421e2010-12-21 12:19:12 +00002099 const Register prototype = r4; // Prototype of the function.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002100 const Register inline_site = r9;
whesse@chromium.org023421e2010-12-21 12:19:12 +00002101 const Register scratch = r2;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002102
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002103 const int32_t kDeltaToLoadBoolResult = 4 * kPointerSize;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002104
whesse@chromium.org023421e2010-12-21 12:19:12 +00002105 Label slow, loop, is_instance, is_not_instance, not_js_object;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002106
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002107 if (!HasArgsInRegisters()) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002108 __ ldr(object, MemOperand(sp, 1 * kPointerSize));
2109 __ ldr(function, MemOperand(sp, 0));
whesse@chromium.org023421e2010-12-21 12:19:12 +00002110 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002111
whesse@chromium.org023421e2010-12-21 12:19:12 +00002112 // Check that the left hand is a JS object and load map.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002113 __ JumpIfSmi(object, &not_js_object);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002114 __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002115
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002116 // If there is a call site cache don't look in the global cache, but do the
2117 // real lookup and update the call site cache.
2118 if (!HasCallSiteInlineCheck()) {
2119 Label miss;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002120 __ CompareRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002121 __ b(ne, &miss);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002122 __ CompareRoot(map, Heap::kInstanceofCacheMapRootIndex);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002123 __ b(ne, &miss);
2124 __ LoadRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
2125 __ Ret(HasArgsInRegisters() ? 0 : 2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002126
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002127 __ bind(&miss);
2128 }
2129
2130 // Get the prototype of the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002131 __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002132
2133 // Check that the function prototype is a JS object.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002134 __ JumpIfSmi(prototype, &slow);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002135 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002136
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002137 // Update the global instanceof or call site inlined cache with the current
2138 // map and function. The cached answer will be set when it is known below.
2139 if (!HasCallSiteInlineCheck()) {
2140 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
2141 __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);
2142 } else {
2143 ASSERT(HasArgsInRegisters());
2144 // Patch the (relocated) inlined map check.
2145
2146 // The offset was stored in r4 safepoint slot.
2147 // (See LCodeGen::DoDeferredLInstanceOfKnownGlobal)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002148 __ LoadFromSafepointRegisterSlot(scratch, r4);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002149 __ sub(inline_site, lr, scratch);
2150 // Get the map location in scratch and patch it.
2151 __ GetRelocatedValueLocation(inline_site, scratch);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002152 __ ldr(scratch, MemOperand(scratch));
danno@chromium.org41728482013-06-12 22:31:22 +00002153 __ str(map, FieldMemOperand(scratch, Cell::kValueOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002154 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002155
2156 // Register mapping: r3 is object map and r4 is function prototype.
2157 // Get prototype of object into r2.
whesse@chromium.org023421e2010-12-21 12:19:12 +00002158 __ ldr(scratch, FieldMemOperand(map, Map::kPrototypeOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002159
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002160 // We don't need map any more. Use it as a scratch register.
2161 Register scratch2 = map;
2162 map = no_reg;
2163
ricow@chromium.org65fae842010-08-25 15:26:24 +00002164 // Loop through the prototype chain looking for the function prototype.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002165 __ LoadRoot(scratch2, Heap::kNullValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002166 __ bind(&loop);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002167 __ cmp(scratch, Operand(prototype));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002168 __ b(eq, &is_instance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002169 __ cmp(scratch, scratch2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002170 __ b(eq, &is_not_instance);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002171 __ ldr(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset));
2172 __ ldr(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002173 __ jmp(&loop);
2174
2175 __ bind(&is_instance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002176 if (!HasCallSiteInlineCheck()) {
2177 __ mov(r0, Operand(Smi::FromInt(0)));
2178 __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
2179 } else {
2180 // Patch the call site to return true.
2181 __ LoadRoot(r0, Heap::kTrueValueRootIndex);
2182 __ add(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
2183 // Get the boolean result location in scratch and patch it.
2184 __ GetRelocatedValueLocation(inline_site, scratch);
2185 __ str(r0, MemOperand(scratch));
2186
2187 if (!ReturnTrueFalseObject()) {
2188 __ mov(r0, Operand(Smi::FromInt(0)));
2189 }
2190 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002191 __ Ret(HasArgsInRegisters() ? 0 : 2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002192
2193 __ bind(&is_not_instance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002194 if (!HasCallSiteInlineCheck()) {
2195 __ mov(r0, Operand(Smi::FromInt(1)));
2196 __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
2197 } else {
2198 // Patch the call site to return false.
2199 __ LoadRoot(r0, Heap::kFalseValueRootIndex);
2200 __ add(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
2201 // Get the boolean result location in scratch and patch it.
2202 __ GetRelocatedValueLocation(inline_site, scratch);
2203 __ str(r0, MemOperand(scratch));
2204
2205 if (!ReturnTrueFalseObject()) {
2206 __ mov(r0, Operand(Smi::FromInt(1)));
2207 }
2208 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002209 __ Ret(HasArgsInRegisters() ? 0 : 2);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002210
2211 Label object_not_null, object_not_null_or_smi;
2212 __ bind(&not_js_object);
2213 // Before null, smi and string value checks, check that the rhs is a function
2214 // as for a non-function rhs an exception needs to be thrown.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002215 __ JumpIfSmi(function, &slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002216 __ CompareObjectType(function, scratch2, scratch, JS_FUNCTION_TYPE);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002217 __ b(ne, &slow);
2218
2219 // Null is not instance of anything.
danno@chromium.org160a7b02011-04-18 15:51:38 +00002220 __ cmp(scratch, Operand(masm->isolate()->factory()->null_value()));
whesse@chromium.org023421e2010-12-21 12:19:12 +00002221 __ b(ne, &object_not_null);
2222 __ mov(r0, Operand(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002223 __ Ret(HasArgsInRegisters() ? 0 : 2);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002224
2225 __ bind(&object_not_null);
2226 // Smi values are not instances of anything.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002227 __ JumpIfNotSmi(object, &object_not_null_or_smi);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002228 __ mov(r0, Operand(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002229 __ Ret(HasArgsInRegisters() ? 0 : 2);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002230
2231 __ bind(&object_not_null_or_smi);
2232 // String values are not instances of anything.
2233 __ IsObjectJSStringType(object, scratch, &slow);
2234 __ mov(r0, Operand(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002235 __ Ret(HasArgsInRegisters() ? 0 : 2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002236
2237 // Slow-case. Tail call builtin.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002238 __ bind(&slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002239 if (!ReturnTrueFalseObject()) {
2240 if (HasArgsInRegisters()) {
2241 __ Push(r0, r1);
2242 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002243 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002244 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002245 {
2246 FrameScope scope(masm, StackFrame::INTERNAL);
2247 __ Push(r0, r1);
2248 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
2249 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002250 __ cmp(r0, Operand::Zero());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002251 __ LoadRoot(r0, Heap::kTrueValueRootIndex, eq);
2252 __ LoadRoot(r0, Heap::kFalseValueRootIndex, ne);
2253 __ Ret(HasArgsInRegisters() ? 0 : 2);
2254 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002255}
2256
2257
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002258void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
2259 Label miss;
2260 Register receiver;
2261 if (kind() == Code::KEYED_LOAD_IC) {
2262 // ----------- S t a t e -------------
2263 // -- lr : return address
2264 // -- r0 : key
2265 // -- r1 : receiver
2266 // -----------------------------------
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002267 __ cmp(r0, Operand(masm->isolate()->factory()->prototype_string()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002268 __ b(ne, &miss);
2269 receiver = r1;
2270 } else {
2271 ASSERT(kind() == Code::LOAD_IC);
2272 // ----------- S t a t e -------------
2273 // -- r2 : name
2274 // -- lr : return address
2275 // -- r0 : receiver
2276 // -- sp[0] : receiver
2277 // -----------------------------------
2278 receiver = r0;
2279 }
2280
2281 StubCompiler::GenerateLoadFunctionPrototype(masm, receiver, r3, r4, &miss);
2282 __ bind(&miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +00002283 StubCompiler::TailCallBuiltin(
2284 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002285}
2286
2287
2288void StringLengthStub::Generate(MacroAssembler* masm) {
2289 Label miss;
2290 Register receiver;
2291 if (kind() == Code::KEYED_LOAD_IC) {
2292 // ----------- S t a t e -------------
2293 // -- lr : return address
2294 // -- r0 : key
2295 // -- r1 : receiver
2296 // -----------------------------------
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002297 __ cmp(r0, Operand(masm->isolate()->factory()->length_string()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002298 __ b(ne, &miss);
2299 receiver = r1;
2300 } else {
2301 ASSERT(kind() == Code::LOAD_IC);
2302 // ----------- S t a t e -------------
2303 // -- r2 : name
2304 // -- lr : return address
2305 // -- r0 : receiver
2306 // -- sp[0] : receiver
2307 // -----------------------------------
2308 receiver = r0;
2309 }
2310
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002311 StubCompiler::GenerateLoadStringLength(masm, receiver, r3, r4, &miss);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002312
2313 __ bind(&miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +00002314 StubCompiler::TailCallBuiltin(
2315 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002316}
2317
2318
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002319void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
2320 // This accepts as a receiver anything JSArray::SetElementsLength accepts
2321 // (currently anything except for external arrays which means anything with
2322 // elements of FixedArray type). Value must be a number, but only smis are
2323 // accepted as the most common case.
2324 Label miss;
2325
2326 Register receiver;
2327 Register value;
2328 if (kind() == Code::KEYED_STORE_IC) {
2329 // ----------- S t a t e -------------
2330 // -- lr : return address
2331 // -- r0 : value
2332 // -- r1 : key
2333 // -- r2 : receiver
2334 // -----------------------------------
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002335 __ cmp(r1, Operand(masm->isolate()->factory()->length_string()));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002336 __ b(ne, &miss);
2337 receiver = r2;
2338 value = r0;
2339 } else {
2340 ASSERT(kind() == Code::STORE_IC);
2341 // ----------- S t a t e -------------
2342 // -- lr : return address
2343 // -- r0 : value
2344 // -- r1 : receiver
2345 // -- r2 : key
2346 // -----------------------------------
2347 receiver = r1;
2348 value = r0;
2349 }
2350 Register scratch = r3;
2351
2352 // Check that the receiver isn't a smi.
2353 __ JumpIfSmi(receiver, &miss);
2354
2355 // Check that the object is a JS array.
2356 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
2357 __ b(ne, &miss);
2358
2359 // Check that elements are FixedArray.
2360 // We rely on StoreIC_ArrayLength below to deal with all types of
2361 // fast elements (including COW).
2362 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
2363 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
2364 __ b(ne, &miss);
2365
2366 // Check that the array has fast properties, otherwise the length
2367 // property might have been redefined.
2368 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset));
2369 __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset));
2370 __ CompareRoot(scratch, Heap::kHashTableMapRootIndex);
2371 __ b(eq, &miss);
2372
2373 // Check that value is a smi.
2374 __ JumpIfNotSmi(value, &miss);
2375
2376 // Prepare tail call to StoreIC_ArrayLength.
2377 __ Push(receiver, value);
2378
2379 ExternalReference ref =
2380 ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength), masm->isolate());
2381 __ TailCallExternalReference(ref, 2, 1);
2382
2383 __ bind(&miss);
2384
danno@chromium.orgbee51992013-07-10 14:57:15 +00002385 StubCompiler::TailCallBuiltin(
2386 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002387}
2388
2389
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002390Register InstanceofStub::left() { return r0; }
2391
2392
2393Register InstanceofStub::right() { return r1; }
2394
2395
ricow@chromium.org65fae842010-08-25 15:26:24 +00002396void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
2397 // The displacement is the offset of the last parameter (if any)
2398 // relative to the frame pointer.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002399 const int kDisplacement =
ricow@chromium.org65fae842010-08-25 15:26:24 +00002400 StandardFrameConstants::kCallerSPOffset - kPointerSize;
2401
2402 // Check that the key is a smi.
2403 Label slow;
ager@chromium.org378b34e2011-01-28 08:04:38 +00002404 __ JumpIfNotSmi(r1, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002405
2406 // Check if the calling frame is an arguments adaptor frame.
2407 Label adaptor;
2408 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2409 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
2410 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2411 __ b(eq, &adaptor);
2412
2413 // Check index against formal parameters count limit passed in
2414 // through register r0. Use unsigned comparison to get negative
2415 // check for free.
2416 __ cmp(r1, r0);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002417 __ b(hs, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002418
2419 // Read the argument from the stack and return it.
2420 __ sub(r3, r0, r1);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002421 __ add(r3, fp, Operand::PointerOffsetFromSmiKey(r3));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002422 __ ldr(r0, MemOperand(r3, kDisplacement));
2423 __ Jump(lr);
2424
2425 // Arguments adaptor case: Check index against actual arguments
2426 // limit found in the arguments adaptor frame. Use unsigned
2427 // comparison to get negative check for free.
2428 __ bind(&adaptor);
2429 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
2430 __ cmp(r1, r0);
2431 __ b(cs, &slow);
2432
2433 // Read the argument from the adaptor frame and return it.
2434 __ sub(r3, r0, r1);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002435 __ add(r3, r2, Operand::PointerOffsetFromSmiKey(r3));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002436 __ ldr(r0, MemOperand(r3, kDisplacement));
2437 __ Jump(lr);
2438
2439 // Slow-case: Handle non-smi or out-of-bounds access to arguments
2440 // by calling the runtime system.
2441 __ bind(&slow);
2442 __ push(r1);
2443 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
2444}
2445
2446
whesse@chromium.org7b260152011-06-20 15:33:18 +00002447void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002448 // sp[0] : number of parameters
2449 // sp[4] : receiver displacement
2450 // sp[8] : function
2451
2452 // Check if the calling frame is an arguments adaptor frame.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002453 Label runtime;
2454 __ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2455 __ ldr(r2, MemOperand(r3, StandardFrameConstants::kContextOffset));
2456 __ cmp(r2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2457 __ b(ne, &runtime);
2458
2459 // Patch the arguments.length and the parameters pointer in the current frame.
2460 __ ldr(r2, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset));
2461 __ str(r2, MemOperand(sp, 0 * kPointerSize));
2462 __ add(r3, r3, Operand(r2, LSL, 1));
2463 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
2464 __ str(r3, MemOperand(sp, 1 * kPointerSize));
2465
2466 __ bind(&runtime);
2467 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
2468}
2469
2470
2471void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
2472 // Stack layout:
2473 // sp[0] : number of parameters (tagged)
2474 // sp[4] : address of receiver argument
2475 // sp[8] : function
2476 // Registers used over whole function:
2477 // r6 : allocated object (tagged)
2478 // r9 : mapped parameter count (tagged)
2479
2480 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
2481 // r1 = parameter count (tagged)
2482
2483 // Check if the calling frame is an arguments adaptor frame.
2484 Label runtime;
2485 Label adaptor_frame, try_allocate;
2486 __ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2487 __ ldr(r2, MemOperand(r3, StandardFrameConstants::kContextOffset));
2488 __ cmp(r2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2489 __ b(eq, &adaptor_frame);
2490
2491 // No adaptor, parameter count = argument count.
2492 __ mov(r2, r1);
2493 __ b(&try_allocate);
2494
2495 // We have an adaptor frame. Patch the parameters pointer.
2496 __ bind(&adaptor_frame);
2497 __ ldr(r2, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset));
2498 __ add(r3, r3, Operand(r2, LSL, 1));
2499 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
2500 __ str(r3, MemOperand(sp, 1 * kPointerSize));
2501
2502 // r1 = parameter count (tagged)
2503 // r2 = argument count (tagged)
2504 // Compute the mapped parameter count = min(r1, r2) in r1.
2505 __ cmp(r1, Operand(r2));
2506 __ mov(r1, Operand(r2), LeaveCC, gt);
2507
2508 __ bind(&try_allocate);
2509
2510 // Compute the sizes of backing store, parameter map, and arguments object.
2511 // 1. Parameter map, has 2 extra words containing context and backing store.
2512 const int kParameterMapHeaderSize =
2513 FixedArray::kHeaderSize + 2 * kPointerSize;
2514 // If there are no mapped parameters, we do not need the parameter_map.
2515 __ cmp(r1, Operand(Smi::FromInt(0)));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002516 __ mov(r9, Operand::Zero(), LeaveCC, eq);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002517 __ mov(r9, Operand(r1, LSL, 1), LeaveCC, ne);
2518 __ add(r9, r9, Operand(kParameterMapHeaderSize), LeaveCC, ne);
2519
2520 // 2. Backing store.
2521 __ add(r9, r9, Operand(r2, LSL, 1));
2522 __ add(r9, r9, Operand(FixedArray::kHeaderSize));
2523
2524 // 3. Arguments object.
2525 __ add(r9, r9, Operand(Heap::kArgumentsObjectSize));
2526
2527 // Do the allocation of all three objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002528 __ Allocate(r9, r0, r3, r4, &runtime, TAG_OBJECT);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002529
2530 // r0 = address of new object(s) (tagged)
2531 // r2 = argument count (tagged)
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002532 // Get the arguments boilerplate from the current native context into r4.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002533 const int kNormalOffset =
2534 Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
2535 const int kAliasedOffset =
2536 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX);
2537
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002538 __ ldr(r4, MemOperand(r8, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2539 __ ldr(r4, FieldMemOperand(r4, GlobalObject::kNativeContextOffset));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002540 __ cmp(r1, Operand::Zero());
whesse@chromium.org7b260152011-06-20 15:33:18 +00002541 __ ldr(r4, MemOperand(r4, kNormalOffset), eq);
2542 __ ldr(r4, MemOperand(r4, kAliasedOffset), ne);
2543
2544 // r0 = address of new object (tagged)
2545 // r1 = mapped parameter count (tagged)
2546 // r2 = argument count (tagged)
2547 // r4 = address of boilerplate object (tagged)
2548 // Copy the JS object part.
2549 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
2550 __ ldr(r3, FieldMemOperand(r4, i));
2551 __ str(r3, FieldMemOperand(r0, i));
2552 }
2553
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002554 // Set up the callee in-object property.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002555 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
2556 __ ldr(r3, MemOperand(sp, 2 * kPointerSize));
2557 const int kCalleeOffset = JSObject::kHeaderSize +
2558 Heap::kArgumentsCalleeIndex * kPointerSize;
2559 __ str(r3, FieldMemOperand(r0, kCalleeOffset));
2560
2561 // Use the length (smi tagged) and set that as an in-object property too.
2562 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
2563 const int kLengthOffset = JSObject::kHeaderSize +
2564 Heap::kArgumentsLengthIndex * kPointerSize;
2565 __ str(r2, FieldMemOperand(r0, kLengthOffset));
2566
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002567 // Set up the elements pointer in the allocated arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002568 // If we allocated a parameter map, r4 will point there, otherwise
2569 // it will point to the backing store.
2570 __ add(r4, r0, Operand(Heap::kArgumentsObjectSize));
2571 __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
2572
2573 // r0 = address of new object (tagged)
2574 // r1 = mapped parameter count (tagged)
2575 // r2 = argument count (tagged)
2576 // r4 = address of parameter map or backing store (tagged)
2577 // Initialize parameter map. If there are no mapped arguments, we're done.
2578 Label skip_parameter_map;
2579 __ cmp(r1, Operand(Smi::FromInt(0)));
2580 // Move backing store address to r3, because it is
2581 // expected there when filling in the unmapped arguments.
2582 __ mov(r3, r4, LeaveCC, eq);
2583 __ b(eq, &skip_parameter_map);
2584
2585 __ LoadRoot(r6, Heap::kNonStrictArgumentsElementsMapRootIndex);
2586 __ str(r6, FieldMemOperand(r4, FixedArray::kMapOffset));
2587 __ add(r6, r1, Operand(Smi::FromInt(2)));
2588 __ str(r6, FieldMemOperand(r4, FixedArray::kLengthOffset));
2589 __ str(r8, FieldMemOperand(r4, FixedArray::kHeaderSize + 0 * kPointerSize));
2590 __ add(r6, r4, Operand(r1, LSL, 1));
2591 __ add(r6, r6, Operand(kParameterMapHeaderSize));
2592 __ str(r6, FieldMemOperand(r4, FixedArray::kHeaderSize + 1 * kPointerSize));
2593
2594 // Copy the parameter slots and the holes in the arguments.
2595 // We need to fill in mapped_parameter_count slots. They index the context,
2596 // where parameters are stored in reverse order, at
2597 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
2598 // The mapped parameter thus need to get indices
2599 // MIN_CONTEXT_SLOTS+parameter_count-1 ..
2600 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
2601 // We loop from right to left.
2602 Label parameters_loop, parameters_test;
2603 __ mov(r6, r1);
2604 __ ldr(r9, MemOperand(sp, 0 * kPointerSize));
2605 __ add(r9, r9, Operand(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
2606 __ sub(r9, r9, Operand(r1));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002607 __ LoadRoot(r5, Heap::kTheHoleValueRootIndex);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002608 __ add(r3, r4, Operand(r6, LSL, 1));
2609 __ add(r3, r3, Operand(kParameterMapHeaderSize));
2610
2611 // r6 = loop variable (tagged)
2612 // r1 = mapping index (tagged)
2613 // r3 = address of backing store (tagged)
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002614 // r4 = address of parameter map (tagged), which is also the address of new
2615 // object + Heap::kArgumentsObjectSize (tagged)
2616 // r0 = temporary scratch (a.o., for address calculation)
2617 // r5 = the hole value
whesse@chromium.org7b260152011-06-20 15:33:18 +00002618 __ jmp(&parameters_test);
2619
2620 __ bind(&parameters_loop);
2621 __ sub(r6, r6, Operand(Smi::FromInt(1)));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002622 __ mov(r0, Operand(r6, LSL, 1));
2623 __ add(r0, r0, Operand(kParameterMapHeaderSize - kHeapObjectTag));
2624 __ str(r9, MemOperand(r4, r0));
2625 __ sub(r0, r0, Operand(kParameterMapHeaderSize - FixedArray::kHeaderSize));
2626 __ str(r5, MemOperand(r3, r0));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002627 __ add(r9, r9, Operand(Smi::FromInt(1)));
2628 __ bind(&parameters_test);
2629 __ cmp(r6, Operand(Smi::FromInt(0)));
2630 __ b(ne, &parameters_loop);
2631
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002632 // Restore r0 = new object (tagged)
2633 __ sub(r0, r4, Operand(Heap::kArgumentsObjectSize));
2634
whesse@chromium.org7b260152011-06-20 15:33:18 +00002635 __ bind(&skip_parameter_map);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002636 // r0 = address of new object (tagged)
whesse@chromium.org7b260152011-06-20 15:33:18 +00002637 // r2 = argument count (tagged)
2638 // r3 = address of backing store (tagged)
2639 // r5 = scratch
2640 // Copy arguments header and remaining slots (if there are any).
2641 __ LoadRoot(r5, Heap::kFixedArrayMapRootIndex);
2642 __ str(r5, FieldMemOperand(r3, FixedArray::kMapOffset));
2643 __ str(r2, FieldMemOperand(r3, FixedArray::kLengthOffset));
2644
2645 Label arguments_loop, arguments_test;
2646 __ mov(r9, r1);
2647 __ ldr(r4, MemOperand(sp, 1 * kPointerSize));
2648 __ sub(r4, r4, Operand(r9, LSL, 1));
2649 __ jmp(&arguments_test);
2650
2651 __ bind(&arguments_loop);
2652 __ sub(r4, r4, Operand(kPointerSize));
2653 __ ldr(r6, MemOperand(r4, 0));
2654 __ add(r5, r3, Operand(r9, LSL, 1));
2655 __ str(r6, FieldMemOperand(r5, FixedArray::kHeaderSize));
2656 __ add(r9, r9, Operand(Smi::FromInt(1)));
2657
2658 __ bind(&arguments_test);
2659 __ cmp(r9, Operand(r2));
2660 __ b(lt, &arguments_loop);
2661
2662 // Return and remove the on-stack parameters.
2663 __ add(sp, sp, Operand(3 * kPointerSize));
2664 __ Ret();
2665
2666 // Do the runtime call to allocate the arguments object.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002667 // r0 = address of new object (tagged)
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002668 // r2 = argument count (tagged)
whesse@chromium.org7b260152011-06-20 15:33:18 +00002669 __ bind(&runtime);
2670 __ str(r2, MemOperand(sp, 0 * kPointerSize)); // Patch argument count.
2671 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
2672}
2673
2674
2675void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
2676 // sp[0] : number of parameters
2677 // sp[4] : receiver displacement
2678 // sp[8] : function
2679 // Check if the calling frame is an arguments adaptor frame.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002680 Label adaptor_frame, try_allocate, runtime;
2681 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2682 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
2683 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2684 __ b(eq, &adaptor_frame);
2685
2686 // Get the length from the frame.
2687 __ ldr(r1, MemOperand(sp, 0));
2688 __ b(&try_allocate);
2689
2690 // Patch the arguments.length and the parameters pointer.
2691 __ bind(&adaptor_frame);
2692 __ ldr(r1, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
2693 __ str(r1, MemOperand(sp, 0));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002694 __ add(r3, r2, Operand::PointerOffsetFromSmiKey(r1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002695 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
2696 __ str(r3, MemOperand(sp, 1 * kPointerSize));
2697
2698 // Try the new space allocation. Start out with computing the size
2699 // of the arguments object and the elements array in words.
2700 Label add_arguments_object;
2701 __ bind(&try_allocate);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002702 __ SmiUntag(r1, SetCC);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002703 __ b(eq, &add_arguments_object);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002704 __ add(r1, r1, Operand(FixedArray::kHeaderSize / kPointerSize));
2705 __ bind(&add_arguments_object);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002706 __ add(r1, r1, Operand(Heap::kArgumentsObjectSizeStrict / kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002707
2708 // Do the allocation of both objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002709 __ Allocate(r1, r0, r2, r3, &runtime,
2710 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002711
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002712 // Get the arguments boilerplate from the current native context.
2713 __ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2714 __ ldr(r4, FieldMemOperand(r4, GlobalObject::kNativeContextOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002715 __ ldr(r4, MemOperand(r4, Context::SlotOffset(
2716 Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002717
2718 // Copy the JS object part.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002719 __ CopyFields(r0, r4, d0, JSObject::kHeaderSize / kPointerSize);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002720
ricow@chromium.org65fae842010-08-25 15:26:24 +00002721 // Get the length (smi tagged) and set that as an in-object property too.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002722 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002723 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002724 __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize +
whesse@chromium.org7b260152011-06-20 15:33:18 +00002725 Heap::kArgumentsLengthIndex * kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002726
2727 // If there are no actual arguments, we're done.
2728 Label done;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002729 __ cmp(r1, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002730 __ b(eq, &done);
2731
2732 // Get the parameters pointer from the stack.
2733 __ ldr(r2, MemOperand(sp, 1 * kPointerSize));
2734
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002735 // Set up the elements pointer in the allocated arguments object and
ricow@chromium.org65fae842010-08-25 15:26:24 +00002736 // initialize the header in the elements fixed array.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002737 __ add(r4, r0, Operand(Heap::kArgumentsObjectSizeStrict));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002738 __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
2739 __ LoadRoot(r3, Heap::kFixedArrayMapRootIndex);
2740 __ str(r3, FieldMemOperand(r4, FixedArray::kMapOffset));
2741 __ str(r1, FieldMemOperand(r4, FixedArray::kLengthOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002742 __ SmiUntag(r1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002743
2744 // Copy the fixed array slots.
2745 Label loop;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002746 // Set up r4 to point to the first array slot.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002747 __ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
2748 __ bind(&loop);
2749 // Pre-decrement r2 with kPointerSize on each iteration.
2750 // Pre-decrement in order to skip receiver.
2751 __ ldr(r3, MemOperand(r2, kPointerSize, NegPreIndex));
2752 // Post-increment r4 with kPointerSize on each iteration.
2753 __ str(r3, MemOperand(r4, kPointerSize, PostIndex));
2754 __ sub(r1, r1, Operand(1));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002755 __ cmp(r1, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002756 __ b(ne, &loop);
2757
2758 // Return and remove the on-stack parameters.
2759 __ bind(&done);
2760 __ add(sp, sp, Operand(3 * kPointerSize));
2761 __ Ret();
2762
2763 // Do the runtime call to allocate the arguments object.
2764 __ bind(&runtime);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002765 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002766}
2767
2768
2769void RegExpExecStub::Generate(MacroAssembler* masm) {
2770 // Just jump directly to runtime if native RegExp is not selected at compile
2771 // time or if regexp entry in generated code is turned off runtime switch or
2772 // at compilation.
2773#ifdef V8_INTERPRETED_REGEXP
2774 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
2775#else // V8_INTERPRETED_REGEXP
ricow@chromium.org65fae842010-08-25 15:26:24 +00002776
2777 // Stack frame on entry.
2778 // sp[0]: last_match_info (expected JSArray)
2779 // sp[4]: previous index
2780 // sp[8]: subject string
2781 // sp[12]: JSRegExp object
2782
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002783 const int kLastMatchInfoOffset = 0 * kPointerSize;
2784 const int kPreviousIndexOffset = 1 * kPointerSize;
2785 const int kSubjectOffset = 2 * kPointerSize;
2786 const int kJSRegExpOffset = 3 * kPointerSize;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002787
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002788 Label runtime;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002789 // Allocation of registers for this function. These are in callee save
2790 // registers and will be preserved by the call to the native RegExp code, as
2791 // this code is called using the normal C calling convention. When calling
2792 // directly from generated code the native RegExp code will not do a GC and
2793 // therefore the content of these registers are safe to use after the call.
2794 Register subject = r4;
2795 Register regexp_data = r5;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002796 Register last_match_info_elements = no_reg; // will be r6;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002797
2798 // Ensure that a RegExp stack is allocated.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002799 Isolate* isolate = masm->isolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002800 ExternalReference address_of_regexp_stack_memory_address =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002801 ExternalReference::address_of_regexp_stack_memory_address(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002802 ExternalReference address_of_regexp_stack_memory_size =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002803 ExternalReference::address_of_regexp_stack_memory_size(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002804 __ mov(r0, Operand(address_of_regexp_stack_memory_size));
2805 __ ldr(r0, MemOperand(r0, 0));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002806 __ cmp(r0, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002807 __ b(eq, &runtime);
2808
2809 // Check that the first argument is a JSRegExp object.
2810 __ ldr(r0, MemOperand(sp, kJSRegExpOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002811 __ JumpIfSmi(r0, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002812 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
2813 __ b(ne, &runtime);
2814
2815 // Check that the RegExp has been compiled (data contains a fixed array).
2816 __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset));
2817 if (FLAG_debug_code) {
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002818 __ SmiTst(regexp_data);
danno@chromium.org59400602013-08-13 17:09:37 +00002819 __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002820 __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE);
danno@chromium.org59400602013-08-13 17:09:37 +00002821 __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002822 }
2823
2824 // regexp_data: RegExp data (FixedArray)
2825 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
2826 __ ldr(r0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset));
2827 __ cmp(r0, Operand(Smi::FromInt(JSRegExp::IRREGEXP)));
2828 __ b(ne, &runtime);
2829
2830 // regexp_data: RegExp data (FixedArray)
2831 // Check that the number of captures fit in the static offsets vector buffer.
2832 __ ldr(r2,
2833 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002834 // Check (number_of_captures + 1) * 2 <= offsets vector size
2835 // Or number_of_captures * 2 <= offsets vector size - 2
2836 // Multiplying by 2 comes for free since r2 is smi-tagged.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002837 STATIC_ASSERT(kSmiTag == 0);
2838 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002839 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
2840 __ cmp(r2, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize - 2));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002841 __ b(hi, &runtime);
2842
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002843 // Reset offset for possibly sliced string.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002844 __ mov(r9, Operand::Zero());
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002845 __ ldr(subject, MemOperand(sp, kSubjectOffset));
2846 __ JumpIfSmi(subject, &runtime);
2847 __ mov(r3, subject); // Make a copy of the original subject string.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002848 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset));
2849 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002850 // subject: subject string
2851 // r3: subject string
2852 // r0: subject string instance type
2853 // regexp_data: RegExp data (FixedArray)
2854 // Handle subject string according to its encoding and representation:
2855 // (1) Sequential string? If yes, go to (5).
2856 // (2) Anything but sequential or cons? If yes, go to (6).
2857 // (3) Cons string. If the string is flat, replace subject with first string.
2858 // Otherwise bailout.
2859 // (4) Is subject external? If yes, go to (7).
2860 // (5) Sequential string. Load regexp code according to encoding.
2861 // (E) Carry on.
2862 /// [...]
2863
2864 // Deferred code at the end of the stub:
2865 // (6) Not a long external string? If yes, go to (8).
2866 // (7) External string. Make it, offset-wise, look like a sequential string.
2867 // Go to (5).
2868 // (8) Short external string or not a string? If yes, bail out to runtime.
2869 // (9) Sliced string. Replace subject with parent. Go to (4).
2870
2871 Label seq_string /* 5 */, external_string /* 7 */,
2872 check_underlying /* 4 */, not_seq_nor_cons /* 6 */,
2873 not_long_external /* 8 */;
2874
2875 // (1) Sequential string? If yes, go to (5).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002876 __ and_(r1,
2877 r0,
2878 Operand(kIsNotStringMask |
2879 kStringRepresentationMask |
2880 kShortExternalStringMask),
2881 SetCC);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002882 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002883 __ b(eq, &seq_string); // Go to (5).
ricow@chromium.org65fae842010-08-25 15:26:24 +00002884
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002885 // (2) Anything but sequential or cons? If yes, go to (6).
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002886 STATIC_ASSERT(kConsStringTag < kExternalStringTag);
2887 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002888 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
2889 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002890 __ cmp(r1, Operand(kExternalStringTag));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002891 __ b(ge, &not_seq_nor_cons); // Go to (6).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002892
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002893 // (3) Cons string. Check that it's flat.
2894 // Replace subject with first string and reload instance type.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002895 __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002896 __ CompareRoot(r0, Heap::kempty_stringRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002897 __ b(ne, &runtime);
2898 __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002899
2900 // (4) Is subject external? If yes, go to (7).
2901 __ bind(&check_underlying);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002902 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset));
2903 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002904 STATIC_ASSERT(kSeqStringTag == 0);
2905 __ tst(r0, Operand(kStringRepresentationMask));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002906 // The underlying external string is never a short external string.
2907 STATIC_CHECK(ExternalString::kMaxShortLength < ConsString::kMinLength);
2908 STATIC_CHECK(ExternalString::kMaxShortLength < SlicedString::kMinLength);
2909 __ b(ne, &external_string); // Go to (7).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002910
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002911 // (5) Sequential string. Load regexp code according to encoding.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002912 __ bind(&seq_string);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002913 // subject: sequential subject string (or look-alike, external string)
2914 // r3: original subject string
2915 // Load previous index and check range before r3 is overwritten. We have to
2916 // use r3 instead of subject here because subject might have been only made
2917 // to look like a sequential string when it actually is an external string.
2918 __ ldr(r1, MemOperand(sp, kPreviousIndexOffset));
2919 __ JumpIfNotSmi(r1, &runtime);
2920 __ ldr(r3, FieldMemOperand(r3, String::kLengthOffset));
2921 __ cmp(r3, Operand(r1));
2922 __ b(ls, &runtime);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002923 __ SmiUntag(r1);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002924
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002925 STATIC_ASSERT(4 == kOneByteStringTag);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002926 STATIC_ASSERT(kTwoByteStringTag == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002927 __ and_(r0, r0, Operand(kStringEncodingMask));
2928 __ mov(r3, Operand(r0, ASR, 2), SetCC);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002929 __ ldr(r6, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne);
2930 __ ldr(r6, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002931
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002932 // (E) Carry on. String handling is done.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002933 // r6: irregexp code
ricow@chromium.org65fae842010-08-25 15:26:24 +00002934 // Check that the irregexp code has been generated for the actual string
2935 // encoding. If it has, the field contains a code object otherwise it contains
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002936 // a smi (code flushing support).
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002937 __ JumpIfSmi(r6, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002938
ricow@chromium.org65fae842010-08-25 15:26:24 +00002939 // r1: previous index
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002940 // r3: encoding of subject string (1 if ASCII, 0 if two_byte);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002941 // r6: code
ricow@chromium.org65fae842010-08-25 15:26:24 +00002942 // subject: Subject string
2943 // regexp_data: RegExp data (FixedArray)
2944 // All checks done. Now push arguments for native regexp code.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002945 __ IncrementCounter(isolate->counters()->regexp_entry_native(), 1, r0, r2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002947 // Isolates: note we add an additional parameter here (isolate pointer).
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002948 const int kRegExpExecuteArguments = 9;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002949 const int kParameterRegisters = 4;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002950 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002951
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002952 // Stack pointer now points to cell where return address is to be written.
2953 // Arguments are before that on the stack or in registers.
2954
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002955 // Argument 9 (sp[20]): Pass current isolate address.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002956 __ mov(r0, Operand(ExternalReference::isolate_address(isolate)));
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002957 __ str(r0, MemOperand(sp, 5 * kPointerSize));
2958
2959 // Argument 8 (sp[16]): Indicate that this is a direct call from JavaScript.
2960 __ mov(r0, Operand(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002961 __ str(r0, MemOperand(sp, 4 * kPointerSize));
2962
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002963 // Argument 7 (sp[12]): Start (high end) of backtracking stack memory area.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002964 __ mov(r0, Operand(address_of_regexp_stack_memory_address));
2965 __ ldr(r0, MemOperand(r0, 0));
2966 __ mov(r2, Operand(address_of_regexp_stack_memory_size));
2967 __ ldr(r2, MemOperand(r2, 0));
2968 __ add(r0, r0, Operand(r2));
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002969 __ str(r0, MemOperand(sp, 3 * kPointerSize));
2970
2971 // Argument 6: Set the number of capture registers to zero to force global
2972 // regexps to behave as non-global. This does not affect non-global regexps.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002973 __ mov(r0, Operand::Zero());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002974 __ str(r0, MemOperand(sp, 2 * kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002975
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002976 // Argument 5 (sp[4]): static offsets vector buffer.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002977 __ mov(r0,
2978 Operand(ExternalReference::address_of_static_offsets_vector(isolate)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002979 __ str(r0, MemOperand(sp, 1 * kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002980
2981 // For arguments 4 and 3 get string length, calculate start of string data and
2982 // calculate the shift of the index (0 for ASCII and 1 for two byte).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002983 __ add(r8, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002984 __ eor(r3, r3, Operand(1));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002985 // Load the length from the original subject string from the previous stack
2986 // frame. Therefore we have to use fp, which points exactly to two pointer
2987 // sizes below the previous sp. (Because creating a new stack frame pushes
2988 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.)
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002989 __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002990 // If slice offset is not 0, load the length from the original sliced string.
2991 // Argument 4, r3: End of string data
2992 // Argument 3, r2: Start of string data
2993 // Prepare start and end index of the input.
2994 __ add(r9, r8, Operand(r9, LSL, r3));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002995 __ add(r2, r9, Operand(r1, LSL, r3));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002996
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002997 __ ldr(r8, FieldMemOperand(subject, String::kLengthOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002998 __ SmiUntag(r8);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002999 __ add(r3, r9, Operand(r8, LSL, r3));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003000
3001 // Argument 2 (r1): Previous index.
3002 // Already there
3003
3004 // Argument 1 (r0): Subject string.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003005 __ mov(r0, subject);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003006
3007 // Locate the code entry and call it.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003008 __ add(r6, r6, Operand(Code::kHeaderSize - kHeapObjectTag));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003009 DirectCEntryStub stub;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003010 stub.GenerateCall(masm, r6);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003011
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003012 __ LeaveExitFrame(false, no_reg, true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003013
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003014 last_match_info_elements = r6;
3015
ricow@chromium.org65fae842010-08-25 15:26:24 +00003016 // r0: result
3017 // subject: subject string (callee saved)
3018 // regexp_data: RegExp data (callee saved)
3019 // last_match_info_elements: Last match info elements (callee saved)
ricow@chromium.org65fae842010-08-25 15:26:24 +00003020 // Check the result.
3021 Label success;
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00003022 __ cmp(r0, Operand(1));
3023 // We expect exactly one result since we force the called regexp to behave
3024 // as non-global.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003025 __ b(eq, &success);
3026 Label failure;
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003027 __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003028 __ b(eq, &failure);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003029 __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003030 // If not exception it can only be retry. Handle that in the runtime system.
3031 __ b(ne, &runtime);
3032 // Result must now be exception. If there is no pending exception already a
3033 // stack overflow (on the backtrack stack) was detected in RegExp code but
3034 // haven't created the exception yet. Handle that in the runtime system.
3035 // TODO(592): Rerunning the RegExp to get the stack overflow exception.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003036 __ mov(r1, Operand(isolate->factory()->the_hole_value()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003037 __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003038 isolate)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003039 __ ldr(r0, MemOperand(r2, 0));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003040 __ cmp(r0, r1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003041 __ b(eq, &runtime);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003042
3043 __ str(r1, MemOperand(r2, 0)); // Clear pending exception.
3044
3045 // Check if the exception is a termination. If so, throw as uncatchable.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003046 __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex);
3047
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003048 Label termination_exception;
3049 __ b(eq, &termination_exception);
3050
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003051 __ Throw(r0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003052
3053 __ bind(&termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003054 __ ThrowUncatchable(r0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003055
ricow@chromium.org65fae842010-08-25 15:26:24 +00003056 __ bind(&failure);
3057 // For failure and exception return null.
danno@chromium.org160a7b02011-04-18 15:51:38 +00003058 __ mov(r0, Operand(masm->isolate()->factory()->null_value()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003059 __ add(sp, sp, Operand(4 * kPointerSize));
3060 __ Ret();
3061
3062 // Process the result from the native regexp code.
3063 __ bind(&success);
3064 __ ldr(r1,
3065 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
3066 // Calculate number of capture registers (number_of_captures + 1) * 2.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003067 // Multiplying by 2 comes for free since r1 is smi-tagged.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003068 STATIC_ASSERT(kSmiTag == 0);
3069 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
3070 __ add(r1, r1, Operand(2)); // r1 was a smi.
3071
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003072 __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset));
3073 __ JumpIfSmi(r0, &runtime);
3074 __ CompareObjectType(r0, r2, r2, JS_ARRAY_TYPE);
3075 __ b(ne, &runtime);
3076 // Check that the JSArray is in fast case.
3077 __ ldr(last_match_info_elements,
3078 FieldMemOperand(r0, JSArray::kElementsOffset));
3079 __ ldr(r0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
3080 __ CompareRoot(r0, Heap::kFixedArrayMapRootIndex);
3081 __ b(ne, &runtime);
3082 // Check that the last match info has space for the capture registers and the
3083 // additional information.
3084 __ ldr(r0,
3085 FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset));
3086 __ add(r2, r1, Operand(RegExpImpl::kLastMatchOverhead));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003087 __ cmp(r2, Operand::SmiUntag(r0));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003088 __ b(gt, &runtime);
3089
ricow@chromium.org65fae842010-08-25 15:26:24 +00003090 // r1: number of capture registers
3091 // r4: subject string
3092 // Store the capture count.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003093 __ SmiTag(r2, r1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003094 __ str(r2, FieldMemOperand(last_match_info_elements,
3095 RegExpImpl::kLastCaptureCountOffset));
3096 // Store last subject and last input.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003097 __ str(subject,
3098 FieldMemOperand(last_match_info_elements,
3099 RegExpImpl::kLastSubjectOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003100 __ mov(r2, subject);
3101 __ RecordWriteField(last_match_info_elements,
3102 RegExpImpl::kLastSubjectOffset,
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003103 subject,
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003104 r3,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003105 kLRHasNotBeenSaved,
3106 kDontSaveFPRegs);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003107 __ mov(subject, r2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003108 __ str(subject,
3109 FieldMemOperand(last_match_info_elements,
3110 RegExpImpl::kLastInputOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003111 __ RecordWriteField(last_match_info_elements,
3112 RegExpImpl::kLastInputOffset,
3113 subject,
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003114 r3,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003115 kLRHasNotBeenSaved,
3116 kDontSaveFPRegs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003117
3118 // Get the static offsets vector filled by the native regexp code.
3119 ExternalReference address_of_static_offsets_vector =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003120 ExternalReference::address_of_static_offsets_vector(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003121 __ mov(r2, Operand(address_of_static_offsets_vector));
3122
3123 // r1: number of capture registers
3124 // r2: offsets vector
3125 Label next_capture, done;
3126 // Capture register counter starts from number of capture registers and
3127 // counts down until wraping after zero.
3128 __ add(r0,
3129 last_match_info_elements,
3130 Operand(RegExpImpl::kFirstCaptureOffset - kHeapObjectTag));
3131 __ bind(&next_capture);
3132 __ sub(r1, r1, Operand(1), SetCC);
3133 __ b(mi, &done);
3134 // Read the value from the static offsets vector buffer.
3135 __ ldr(r3, MemOperand(r2, kPointerSize, PostIndex));
3136 // Store the smi value in the last match info.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003137 __ SmiTag(r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003138 __ str(r3, MemOperand(r0, kPointerSize, PostIndex));
3139 __ jmp(&next_capture);
3140 __ bind(&done);
3141
3142 // Return last match info.
3143 __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset));
3144 __ add(sp, sp, Operand(4 * kPointerSize));
3145 __ Ret();
3146
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003147 // Do the runtime call to execute the regexp.
3148 __ bind(&runtime);
3149 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
3150
3151 // Deferred code for string handling.
3152 // (6) Not a long external string? If yes, go to (8).
3153 __ bind(&not_seq_nor_cons);
3154 // Compare flags are still set.
3155 __ b(gt, &not_long_external); // Go to (8).
3156
3157 // (7) External string. Make it, offset-wise, look like a sequential string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003158 __ bind(&external_string);
3159 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset));
3160 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
3161 if (FLAG_debug_code) {
3162 // Assert that we do not have a cons or slice (indirect strings) here.
3163 // Sequential strings have already been ruled out.
3164 __ tst(r0, Operand(kIsIndirectStringMask));
danno@chromium.org59400602013-08-13 17:09:37 +00003165 __ Assert(eq, kExternalStringExpectedButNotFound);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003166 }
3167 __ ldr(subject,
3168 FieldMemOperand(subject, ExternalString::kResourceDataOffset));
3169 // Move the pointer so that offset-wise, it looks like a sequential string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003170 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003171 __ sub(subject,
3172 subject,
3173 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003174 __ jmp(&seq_string); // Go to (5).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003175
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003176 // (8) Short external string or not a string? If yes, bail out to runtime.
3177 __ bind(&not_long_external);
3178 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
3179 __ tst(r1, Operand(kIsNotStringMask | kShortExternalStringMask));
3180 __ b(ne, &runtime);
3181
3182 // (9) Sliced string. Replace subject with parent. Go to (4).
3183 // Load offset into r9 and replace subject string with parent.
3184 __ ldr(r9, FieldMemOperand(subject, SlicedString::kOffsetOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003185 __ SmiUntag(r9);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00003186 __ ldr(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
3187 __ jmp(&check_underlying); // Go to (4).
ricow@chromium.org65fae842010-08-25 15:26:24 +00003188#endif // V8_INTERPRETED_REGEXP
3189}
3190
3191
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003192void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
3193 const int kMaxInlineLength = 100;
3194 Label slowcase;
3195 Label done;
danno@chromium.org160a7b02011-04-18 15:51:38 +00003196 Factory* factory = masm->isolate()->factory();
3197
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003198 __ ldr(r1, MemOperand(sp, kPointerSize * 2));
3199 STATIC_ASSERT(kSmiTag == 0);
3200 STATIC_ASSERT(kSmiTagSize == 1);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003201 __ JumpIfNotSmi(r1, &slowcase);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003202 __ cmp(r1, Operand(Smi::FromInt(kMaxInlineLength)));
3203 __ b(hi, &slowcase);
3204 // Smi-tagging is equivalent to multiplying by 2.
3205 // Allocate RegExpResult followed by FixedArray with size in ebx.
3206 // JSArray: [Map][empty properties][Elements][Length-smi][index][input]
3207 // Elements: [Map][Length][..elements..]
3208 // Size of JSArray with two in-object properties and the header of a
3209 // FixedArray.
3210 int objects_size =
3211 (JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize;
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003212 __ SmiUntag(r5, r1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003213 __ add(r2, r5, Operand(objects_size));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003214 __ Allocate(
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003215 r2, // In: Size, in words.
3216 r0, // Out: Start of allocation (tagged).
3217 r3, // Scratch register.
3218 r4, // Scratch register.
3219 &slowcase,
3220 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
3221 // r0: Start of allocated area, object-tagged.
3222 // r1: Number of elements in array, as smi.
3223 // r5: Number of elements, untagged.
3224
3225 // Set JSArray map to global.regexp_result_map().
3226 // Set empty properties FixedArray.
3227 // Set elements to point to FixedArray allocated right after the JSArray.
3228 // Interleave operations for better latency.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003229 __ ldr(r2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003230 __ add(r3, r0, Operand(JSRegExpResult::kSize));
danno@chromium.org160a7b02011-04-18 15:51:38 +00003231 __ mov(r4, Operand(factory->empty_fixed_array()));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003232 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kNativeContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003233 __ str(r3, FieldMemOperand(r0, JSObject::kElementsOffset));
3234 __ ldr(r2, ContextOperand(r2, Context::REGEXP_RESULT_MAP_INDEX));
3235 __ str(r4, FieldMemOperand(r0, JSObject::kPropertiesOffset));
3236 __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
3237
3238 // Set input, index and length fields from arguments.
3239 __ ldr(r1, MemOperand(sp, kPointerSize * 0));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003240 __ ldr(r2, MemOperand(sp, kPointerSize * 1));
3241 __ ldr(r6, MemOperand(sp, kPointerSize * 2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003242 __ str(r1, FieldMemOperand(r0, JSRegExpResult::kInputOffset));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003243 __ str(r2, FieldMemOperand(r0, JSRegExpResult::kIndexOffset));
3244 __ str(r6, FieldMemOperand(r0, JSArray::kLengthOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003245
3246 // Fill out the elements FixedArray.
3247 // r0: JSArray, tagged.
3248 // r3: FixedArray, tagged.
3249 // r5: Number of elements in array, untagged.
3250
3251 // Set map.
danno@chromium.org160a7b02011-04-18 15:51:38 +00003252 __ mov(r2, Operand(factory->fixed_array_map()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003253 __ str(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
3254 // Set FixedArray length.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003255 __ SmiTag(r6, r5);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003256 __ str(r6, FieldMemOperand(r3, FixedArray::kLengthOffset));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003257 // Fill contents of fixed-array with undefined.
3258 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003259 __ add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003260 // Fill fixed array elements with undefined.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003261 // r0: JSArray, tagged.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003262 // r2: undefined.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003263 // r3: Start of elements in FixedArray.
3264 // r5: Number of elements to fill.
3265 Label loop;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003266 __ cmp(r5, Operand::Zero());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003267 __ bind(&loop);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003268 __ b(le, &done); // Jump if r5 is negative or zero.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003269 __ sub(r5, r5, Operand(1), SetCC);
3270 __ str(r2, MemOperand(r3, r5, LSL, kPointerSizeLog2));
3271 __ jmp(&loop);
3272
3273 __ bind(&done);
3274 __ add(sp, sp, Operand(3 * kPointerSize));
3275 __ Ret();
3276
3277 __ bind(&slowcase);
3278 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1);
3279}
3280
3281
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003282static void GenerateRecordCallTarget(MacroAssembler* masm) {
3283 // Cache the called function in a global property cell. Cache states
3284 // are uninitialized, monomorphic (indicated by a JSFunction), and
3285 // megamorphic.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003286 // r0 : number of arguments to the construct function
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003287 // r1 : the function to call
3288 // r2 : cache cell for call target
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003289 Label initialize, done, miss, megamorphic, not_array_function;
3290
3291 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
3292 masm->isolate()->heap()->undefined_value());
3293 ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()),
3294 masm->isolate()->heap()->the_hole_value());
3295
3296 // Load the cache state into r3.
danno@chromium.org41728482013-06-12 22:31:22 +00003297 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003298
3299 // A monomorphic cache hit or an already megamorphic state: invoke the
3300 // function without changing the state.
3301 __ cmp(r3, r1);
3302 __ b(eq, &done);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003303
danno@chromium.orgbee51992013-07-10 14:57:15 +00003304 // If we came here, we need to see if we are the array function.
3305 // If we didn't have a matching function, and we didn't find the megamorph
3306 // sentinel, then we have in the cell either some other function or an
3307 // AllocationSite. Do a map check on the object in ecx.
danno@chromium.orgbee51992013-07-10 14:57:15 +00003308 __ ldr(r5, FieldMemOperand(r3, 0));
3309 __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
3310 __ b(ne, &miss);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003311
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003312 // Make sure the function is the Array() function
3313 __ LoadArrayFunction(r3);
3314 __ cmp(r1, r3);
3315 __ b(ne, &megamorphic);
3316 __ jmp(&done);
3317
3318 __ bind(&miss);
3319
3320 // A monomorphic miss (i.e, here the cache is not uninitialized) goes
3321 // megamorphic.
3322 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
3323 __ b(eq, &initialize);
3324 // MegamorphicSentinel is an immortal immovable object (undefined) so no
3325 // write-barrier is needed.
3326 __ bind(&megamorphic);
3327 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
danno@chromium.org41728482013-06-12 22:31:22 +00003328 __ str(ip, FieldMemOperand(r2, Cell::kValueOffset));
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003329 __ jmp(&done);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003330
3331 // An uninitialized cache is patched with the function or sentinel to
3332 // indicate the ElementsKind if function is the Array constructor.
3333 __ bind(&initialize);
3334 // Make sure the function is the Array() function
3335 __ LoadArrayFunction(r3);
3336 __ cmp(r1, r3);
3337 __ b(ne, &not_array_function);
3338
danno@chromium.orgbee51992013-07-10 14:57:15 +00003339 // The target function is the Array constructor,
3340 // Create an AllocationSite if we don't already have it, store it in the cell
3341 {
3342 FrameScope scope(masm, StackFrame::INTERNAL);
3343
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003344 // Arguments register must be smi-tagged to call out.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00003345 __ SmiTag(r0);
danno@chromium.orgbee51992013-07-10 14:57:15 +00003346 __ push(r0);
3347 __ push(r1);
3348 __ push(r2);
3349
3350 CreateAllocationSiteStub create_stub;
3351 __ CallStub(&create_stub);
3352
3353 __ pop(r2);
3354 __ pop(r1);
3355 __ pop(r0);
verwaest@chromium.org662436e2013-08-28 08:41:27 +00003356 __ SmiUntag(r0);
danno@chromium.orgbee51992013-07-10 14:57:15 +00003357 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003358 __ b(&done);
3359
3360 __ bind(&not_array_function);
danno@chromium.org41728482013-06-12 22:31:22 +00003361 __ str(r1, FieldMemOperand(r2, Cell::kValueOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003362 // No need for a write barrier here - cells are rescanned.
3363
3364 __ bind(&done);
3365}
3366
3367
ricow@chromium.org65fae842010-08-25 15:26:24 +00003368void CallFunctionStub::Generate(MacroAssembler* masm) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003369 // r1 : the function to call
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003370 // r2 : cache cell for call target
lrn@chromium.org34e60782011-09-15 07:25:40 +00003371 Label slow, non_function;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003372
danno@chromium.org40cb8782011-05-25 07:58:50 +00003373 // The receiver might implicitly be the global object. This is
3374 // indicated by passing the hole as the receiver to the call
3375 // function stub.
3376 if (ReceiverMightBeImplicit()) {
3377 Label call;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003378 // Get the receiver from the stack.
3379 // function, receiver [, arguments]
danno@chromium.org40cb8782011-05-25 07:58:50 +00003380 __ ldr(r4, MemOperand(sp, argc_ * kPointerSize));
3381 // Call as function is indicated with the hole.
3382 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
3383 __ b(ne, &call);
3384 // Patch the receiver on the stack with the global receiver object.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003385 __ ldr(r3,
3386 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003387 __ ldr(r3, FieldMemOperand(r3, GlobalObject::kGlobalReceiverOffset));
3388 __ str(r3, MemOperand(sp, argc_ * kPointerSize));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003389 __ bind(&call);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003390 }
3391
ricow@chromium.org65fae842010-08-25 15:26:24 +00003392 // Check that the function is really a JavaScript function.
3393 // r1: pushed function (to be verified)
lrn@chromium.org34e60782011-09-15 07:25:40 +00003394 __ JumpIfSmi(r1, &non_function);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003395 // Get the map of the function object.
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003396 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003397 __ b(ne, &slow);
3398
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003399 if (RecordCallTarget()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003400 GenerateRecordCallTarget(masm);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003401 }
3402
ricow@chromium.org65fae842010-08-25 15:26:24 +00003403 // Fast-case: Invoke the function now.
3404 // r1: pushed function
3405 ParameterCount actual(argc_);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003406
3407 if (ReceiverMightBeImplicit()) {
3408 Label call_as_function;
3409 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
3410 __ b(eq, &call_as_function);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003411 __ InvokeFunction(r1,
3412 actual,
3413 JUMP_FUNCTION,
3414 NullCallWrapper(),
3415 CALL_AS_METHOD);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003416 __ bind(&call_as_function);
3417 }
3418 __ InvokeFunction(r1,
3419 actual,
3420 JUMP_FUNCTION,
3421 NullCallWrapper(),
3422 CALL_AS_FUNCTION);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003423
3424 // Slow-case: Non-function called.
3425 __ bind(&slow);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003426 if (RecordCallTarget()) {
3427 // If there is a call target cache, mark it megamorphic in the
3428 // non-function case. MegamorphicSentinel is an immortal immovable
3429 // object (undefined) so no write barrier is needed.
3430 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
3431 masm->isolate()->heap()->undefined_value());
3432 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
danno@chromium.org41728482013-06-12 22:31:22 +00003433 __ str(ip, FieldMemOperand(r2, Cell::kValueOffset));
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003434 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00003435 // Check for function proxy.
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00003436 __ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE));
lrn@chromium.org34e60782011-09-15 07:25:40 +00003437 __ b(ne, &non_function);
3438 __ push(r1); // put proxy as additional argument
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003439 __ mov(r0, Operand(argc_ + 1, RelocInfo::NONE32));
3440 __ mov(r2, Operand::Zero());
lrn@chromium.org34e60782011-09-15 07:25:40 +00003441 __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003442 __ SetCallKind(r5, CALL_AS_METHOD);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003443 {
3444 Handle<Code> adaptor =
3445 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
3446 __ Jump(adaptor, RelocInfo::CODE_TARGET);
3447 }
3448
ricow@chromium.org65fae842010-08-25 15:26:24 +00003449 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
3450 // of the original receiver from the call site).
lrn@chromium.org34e60782011-09-15 07:25:40 +00003451 __ bind(&non_function);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003452 __ str(r1, MemOperand(sp, argc_ * kPointerSize));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003453 __ mov(r0, Operand(argc_)); // Set up the number of arguments.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003454 __ mov(r2, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003455 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003456 __ SetCallKind(r5, CALL_AS_METHOD);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003457 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
ricow@chromium.org65fae842010-08-25 15:26:24 +00003458 RelocInfo::CODE_TARGET);
3459}
3460
3461
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003462void CallConstructStub::Generate(MacroAssembler* masm) {
3463 // r0 : number of arguments
3464 // r1 : the function to call
3465 // r2 : cache cell for call target
3466 Label slow, non_function_call;
3467
3468 // Check that the function is not a smi.
3469 __ JumpIfSmi(r1, &non_function_call);
3470 // Check that the function is a JSFunction.
3471 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
3472 __ b(ne, &slow);
3473
3474 if (RecordCallTarget()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003475 GenerateRecordCallTarget(masm);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003476 }
3477
3478 // Jump to the function-specific construct stub.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003479 Register jmp_reg = r3;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003480 __ ldr(jmp_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
3481 __ ldr(jmp_reg, FieldMemOperand(jmp_reg,
3482 SharedFunctionInfo::kConstructStubOffset));
3483 __ add(pc, jmp_reg, Operand(Code::kHeaderSize - kHeapObjectTag));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003484
3485 // r0: number of arguments
3486 // r1: called object
3487 // r3: object type
3488 Label do_call;
3489 __ bind(&slow);
3490 __ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE));
3491 __ b(ne, &non_function_call);
3492 __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
3493 __ jmp(&do_call);
3494
3495 __ bind(&non_function_call);
3496 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
3497 __ bind(&do_call);
3498 // Set expected number of arguments to zero (not changing r0).
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003499 __ mov(r2, Operand::Zero());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003500 __ SetCallKind(r5, CALL_AS_METHOD);
3501 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
3502 RelocInfo::CODE_TARGET);
3503}
3504
3505
ricow@chromium.org65fae842010-08-25 15:26:24 +00003506// StringCharCodeAtGenerator
ricow@chromium.org65fae842010-08-25 15:26:24 +00003507void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
3508 Label flat_string;
3509 Label ascii_string;
3510 Label got_char_code;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003511 Label sliced_string;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003512
3513 // If the receiver is a smi trigger the non-string case.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003514 __ JumpIfSmi(object_, receiver_not_string_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003515
3516 // Fetch the instance type of the receiver into result register.
3517 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
3518 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
3519 // If the receiver is not a string trigger the non-string case.
3520 __ tst(result_, Operand(kIsNotStringMask));
3521 __ b(ne, receiver_not_string_);
3522
3523 // If the index is non-smi trigger the non-smi case.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003524 __ JumpIfNotSmi(index_, &index_not_smi_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003525 __ bind(&got_smi_index_);
3526
3527 // Check for index out of range.
3528 __ ldr(ip, FieldMemOperand(object_, String::kLengthOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003529 __ cmp(ip, Operand(index_));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003530 __ b(ls, index_out_of_range_);
3531
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003532 __ SmiUntag(index_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003533
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003534 StringCharLoadGenerator::Generate(masm,
3535 object_,
3536 index_,
3537 result_,
3538 &call_runtime_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003539
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003540 __ SmiTag(result_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003541 __ bind(&exit_);
3542}
3543
3544
3545void StringCharCodeAtGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003546 MacroAssembler* masm,
3547 const RuntimeCallHelper& call_helper) {
danno@chromium.org59400602013-08-13 17:09:37 +00003548 __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003549
3550 // Index is not a smi.
3551 __ bind(&index_not_smi_);
3552 // If index is a heap number, try converting it to an integer.
3553 __ CheckMap(index_,
danno@chromium.orgc612e022011-11-10 11:38:15 +00003554 result_,
ricow@chromium.org65fae842010-08-25 15:26:24 +00003555 Heap::kHeapNumberMapRootIndex,
3556 index_not_number_,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003557 DONT_DO_SMI_CHECK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003558 call_helper.BeforeCall(masm);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003559 __ push(object_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003560 __ push(index_); // Consumed by runtime conversion function.
3561 if (index_flags_ == STRING_INDEX_IS_NUMBER) {
3562 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
3563 } else {
3564 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
3565 // NumberToSmi discards numbers that are not exact integers.
3566 __ CallRuntime(Runtime::kNumberToSmi, 1);
3567 }
3568 // Save the conversion result before the pop instructions below
3569 // have a chance to overwrite it.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003570 __ Move(index_, r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003571 __ pop(object_);
3572 // Reload the instance type.
3573 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
3574 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
3575 call_helper.AfterCall(masm);
3576 // If index is still not a smi, it must be out of range.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003577 __ JumpIfNotSmi(index_, index_out_of_range_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003578 // Otherwise, return to the fast path.
3579 __ jmp(&got_smi_index_);
3580
3581 // Call runtime. We get here when the receiver is a string and the
3582 // index is a number, but the code of getting the actual character
3583 // is too complex (e.g., when the string needs to be flattened).
3584 __ bind(&call_runtime_);
3585 call_helper.BeforeCall(masm);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003586 __ SmiTag(index_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003587 __ Push(object_, index_);
3588 __ CallRuntime(Runtime::kStringCharCodeAt, 2);
3589 __ Move(result_, r0);
3590 call_helper.AfterCall(masm);
3591 __ jmp(&exit_);
3592
danno@chromium.org59400602013-08-13 17:09:37 +00003593 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003594}
3595
3596
3597// -------------------------------------------------------------------------
3598// StringCharFromCodeGenerator
3599
3600void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
3601 // Fast case of Heap::LookupSingleCharacterStringFromCode.
3602 STATIC_ASSERT(kSmiTag == 0);
3603 STATIC_ASSERT(kSmiShiftSize == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003604 ASSERT(IsPowerOf2(String::kMaxOneByteCharCode + 1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003605 __ tst(code_,
3606 Operand(kSmiTagMask |
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003607 ((~String::kMaxOneByteCharCode) << kSmiTagSize)));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003608 __ b(ne, &slow_case_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003609
3610 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003611 // At this point code register contains smi tagged ASCII char code.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003612 __ add(result_, result_, Operand::PointerOffsetFromSmiKey(code_));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003613 __ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003614 __ CompareRoot(result_, Heap::kUndefinedValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003615 __ b(eq, &slow_case_);
3616 __ bind(&exit_);
3617}
3618
3619
3620void StringCharFromCodeGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003621 MacroAssembler* masm,
3622 const RuntimeCallHelper& call_helper) {
danno@chromium.org59400602013-08-13 17:09:37 +00003623 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003624
3625 __ bind(&slow_case_);
3626 call_helper.BeforeCall(masm);
3627 __ push(code_);
3628 __ CallRuntime(Runtime::kCharFromCode, 1);
3629 __ Move(result_, r0);
3630 call_helper.AfterCall(masm);
3631 __ jmp(&exit_);
3632
danno@chromium.org59400602013-08-13 17:09:37 +00003633 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003634}
3635
3636
ricow@chromium.org65fae842010-08-25 15:26:24 +00003637void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
3638 Register dest,
3639 Register src,
3640 Register count,
3641 Register scratch,
3642 bool ascii) {
3643 Label loop;
3644 Label done;
3645 // This loop just copies one character at a time, as it is only used for very
3646 // short strings.
3647 if (!ascii) {
3648 __ add(count, count, Operand(count), SetCC);
3649 } else {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003650 __ cmp(count, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003651 }
3652 __ b(eq, &done);
3653
3654 __ bind(&loop);
3655 __ ldrb(scratch, MemOperand(src, 1, PostIndex));
3656 // Perform sub between load and dependent store to get the load time to
3657 // complete.
3658 __ sub(count, count, Operand(1), SetCC);
3659 __ strb(scratch, MemOperand(dest, 1, PostIndex));
3660 // last iteration.
3661 __ b(gt, &loop);
3662
3663 __ bind(&done);
3664}
3665
3666
3667enum CopyCharactersFlags {
3668 COPY_ASCII = 1,
3669 DEST_ALWAYS_ALIGNED = 2
3670};
3671
3672
3673void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm,
3674 Register dest,
3675 Register src,
3676 Register count,
3677 Register scratch1,
3678 Register scratch2,
3679 Register scratch3,
3680 Register scratch4,
ricow@chromium.org65fae842010-08-25 15:26:24 +00003681 int flags) {
3682 bool ascii = (flags & COPY_ASCII) != 0;
3683 bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0;
3684
3685 if (dest_always_aligned && FLAG_debug_code) {
3686 // Check that destination is actually word aligned if the flag says
3687 // that it is.
3688 __ tst(dest, Operand(kPointerAlignmentMask));
danno@chromium.org59400602013-08-13 17:09:37 +00003689 __ Check(eq, kDestinationOfCopyNotAligned);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003690 }
3691
3692 const int kReadAlignment = 4;
3693 const int kReadAlignmentMask = kReadAlignment - 1;
3694 // Ensure that reading an entire aligned word containing the last character
3695 // of a string will not read outside the allocated area (because we pad up
3696 // to kObjectAlignment).
3697 STATIC_ASSERT(kObjectAlignment >= kReadAlignment);
3698 // Assumes word reads and writes are little endian.
3699 // Nothing to do for zero characters.
3700 Label done;
3701 if (!ascii) {
3702 __ add(count, count, Operand(count), SetCC);
3703 } else {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003704 __ cmp(count, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003705 }
3706 __ b(eq, &done);
3707
3708 // Assume that you cannot read (or write) unaligned.
3709 Label byte_loop;
3710 // Must copy at least eight bytes, otherwise just do it one byte at a time.
3711 __ cmp(count, Operand(8));
3712 __ add(count, dest, Operand(count));
3713 Register limit = count; // Read until src equals this.
3714 __ b(lt, &byte_loop);
3715
3716 if (!dest_always_aligned) {
3717 // Align dest by byte copying. Copies between zero and three bytes.
3718 __ and_(scratch4, dest, Operand(kReadAlignmentMask), SetCC);
3719 Label dest_aligned;
3720 __ b(eq, &dest_aligned);
3721 __ cmp(scratch4, Operand(2));
3722 __ ldrb(scratch1, MemOperand(src, 1, PostIndex));
3723 __ ldrb(scratch2, MemOperand(src, 1, PostIndex), le);
3724 __ ldrb(scratch3, MemOperand(src, 1, PostIndex), lt);
3725 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
3726 __ strb(scratch2, MemOperand(dest, 1, PostIndex), le);
3727 __ strb(scratch3, MemOperand(dest, 1, PostIndex), lt);
3728 __ bind(&dest_aligned);
3729 }
3730
3731 Label simple_loop;
3732
3733 __ sub(scratch4, dest, Operand(src));
3734 __ and_(scratch4, scratch4, Operand(0x03), SetCC);
3735 __ b(eq, &simple_loop);
3736 // Shift register is number of bits in a source word that
3737 // must be combined with bits in the next source word in order
3738 // to create a destination word.
3739
3740 // Complex loop for src/dst that are not aligned the same way.
3741 {
3742 Label loop;
3743 __ mov(scratch4, Operand(scratch4, LSL, 3));
3744 Register left_shift = scratch4;
3745 __ and_(src, src, Operand(~3)); // Round down to load previous word.
3746 __ ldr(scratch1, MemOperand(src, 4, PostIndex));
3747 // Store the "shift" most significant bits of scratch in the least
3748 // signficant bits (i.e., shift down by (32-shift)).
3749 __ rsb(scratch2, left_shift, Operand(32));
3750 Register right_shift = scratch2;
3751 __ mov(scratch1, Operand(scratch1, LSR, right_shift));
3752
3753 __ bind(&loop);
3754 __ ldr(scratch3, MemOperand(src, 4, PostIndex));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003755 __ orr(scratch1, scratch1, Operand(scratch3, LSL, left_shift));
3756 __ str(scratch1, MemOperand(dest, 4, PostIndex));
3757 __ mov(scratch1, Operand(scratch3, LSR, right_shift));
3758 // Loop if four or more bytes left to copy.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003759 __ sub(scratch3, limit, Operand(dest));
3760 __ sub(scratch3, scratch3, Operand(4), SetCC);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003761 __ b(ge, &loop);
3762 }
3763 // There is now between zero and three bytes left to copy (negative that
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003764 // number is in scratch3), and between one and three bytes already read into
ricow@chromium.org65fae842010-08-25 15:26:24 +00003765 // scratch1 (eight times that number in scratch4). We may have read past
3766 // the end of the string, but because objects are aligned, we have not read
3767 // past the end of the object.
3768 // Find the minimum of remaining characters to move and preloaded characters
3769 // and write those as bytes.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003770 __ add(scratch3, scratch3, Operand(4), SetCC);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003771 __ b(eq, &done);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003772 __ cmp(scratch4, Operand(scratch3, LSL, 3), ne);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003773 // Move minimum of bytes read and bytes left to copy to scratch4.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003774 __ mov(scratch3, Operand(scratch4, LSR, 3), LeaveCC, lt);
3775 // Between one and three (value in scratch3) characters already read into
ricow@chromium.org65fae842010-08-25 15:26:24 +00003776 // scratch ready to write.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003777 __ cmp(scratch3, Operand(2));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003778 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
3779 __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, ge);
3780 __ strb(scratch1, MemOperand(dest, 1, PostIndex), ge);
3781 __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, gt);
3782 __ strb(scratch1, MemOperand(dest, 1, PostIndex), gt);
3783 // Copy any remaining bytes.
3784 __ b(&byte_loop);
3785
3786 // Simple loop.
3787 // Copy words from src to dst, until less than four bytes left.
3788 // Both src and dest are word aligned.
3789 __ bind(&simple_loop);
3790 {
3791 Label loop;
3792 __ bind(&loop);
3793 __ ldr(scratch1, MemOperand(src, 4, PostIndex));
3794 __ sub(scratch3, limit, Operand(dest));
3795 __ str(scratch1, MemOperand(dest, 4, PostIndex));
3796 // Compare to 8, not 4, because we do the substraction before increasing
3797 // dest.
3798 __ cmp(scratch3, Operand(8));
3799 __ b(ge, &loop);
3800 }
3801
3802 // Copy bytes from src to dst until dst hits limit.
3803 __ bind(&byte_loop);
3804 __ cmp(dest, Operand(limit));
3805 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt);
3806 __ b(ge, &done);
3807 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
3808 __ b(&byte_loop);
3809
3810 __ bind(&done);
3811}
3812
3813
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003814void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
ricow@chromium.org65fae842010-08-25 15:26:24 +00003815 Register c1,
3816 Register c2,
3817 Register scratch1,
3818 Register scratch2,
3819 Register scratch3,
3820 Register scratch4,
3821 Register scratch5,
3822 Label* not_found) {
3823 // Register scratch3 is the general scratch register in this function.
3824 Register scratch = scratch3;
3825
3826 // Make sure that both characters are not digits as such strings has a
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003827 // different hash algorithm. Don't try to look for these in the string table.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003828 Label not_array_index;
3829 __ sub(scratch, c1, Operand(static_cast<int>('0')));
3830 __ cmp(scratch, Operand(static_cast<int>('9' - '0')));
3831 __ b(hi, &not_array_index);
3832 __ sub(scratch, c2, Operand(static_cast<int>('0')));
3833 __ cmp(scratch, Operand(static_cast<int>('9' - '0')));
3834
3835 // If check failed combine both characters into single halfword.
3836 // This is required by the contract of the method: code at the
3837 // not_found branch expects this combination in c1 register
3838 __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls);
3839 __ b(ls, not_found);
3840
3841 __ bind(&not_array_index);
3842 // Calculate the two character string hash.
3843 Register hash = scratch1;
3844 StringHelper::GenerateHashInit(masm, hash, c1);
3845 StringHelper::GenerateHashAddCharacter(masm, hash, c2);
3846 StringHelper::GenerateHashGetHash(masm, hash);
3847
3848 // Collect the two characters in a register.
3849 Register chars = c1;
3850 __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte));
3851
3852 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
3853 // hash: hash of two character string.
3854
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003855 // Load string table
3856 // Load address of first element of the string table.
3857 Register string_table = c2;
3858 __ LoadRoot(string_table, Heap::kStringTableRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003859
ricow@chromium.org65fae842010-08-25 15:26:24 +00003860 Register undefined = scratch4;
3861 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
3862
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003863 // Calculate capacity mask from the string table capacity.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003864 Register mask = scratch2;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003865 __ ldr(mask, FieldMemOperand(string_table, StringTable::kCapacityOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003866 __ mov(mask, Operand(mask, ASR, 1));
3867 __ sub(mask, mask, Operand(1));
3868
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003869 // Calculate untagged address of the first element of the string table.
3870 Register first_string_table_element = string_table;
3871 __ add(first_string_table_element, string_table,
3872 Operand(StringTable::kElementsStartOffset - kHeapObjectTag));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003873
3874 // Registers
3875 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
3876 // hash: hash of two character string
3877 // mask: capacity mask
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003878 // first_string_table_element: address of the first element of
3879 // the string table
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003880 // undefined: the undefined object
ricow@chromium.org65fae842010-08-25 15:26:24 +00003881 // scratch: -
3882
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003883 // Perform a number of probes in the string table.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00003884 const int kProbes = 4;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003885 Label found_in_string_table;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003886 Label next_probe[kProbes];
danno@chromium.org2c456792011-11-11 12:00:53 +00003887 Register candidate = scratch5; // Scratch register contains candidate.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003888 for (int i = 0; i < kProbes; i++) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003889 // Calculate entry in string table.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003890 if (i > 0) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003891 __ add(candidate, hash, Operand(StringTable::GetProbeOffset(i)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003892 } else {
3893 __ mov(candidate, hash);
3894 }
3895
3896 __ and_(candidate, candidate, Operand(mask));
3897
3898 // Load the entry from the symble table.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003899 STATIC_ASSERT(StringTable::kEntrySize == 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003900 __ ldr(candidate,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003901 MemOperand(first_string_table_element,
ricow@chromium.org65fae842010-08-25 15:26:24 +00003902 candidate,
3903 LSL,
3904 kPointerSizeLog2));
3905
3906 // If entry is undefined no string with this hash can be found.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003907 Label is_string;
3908 __ CompareObjectType(candidate, scratch, scratch, ODDBALL_TYPE);
3909 __ b(ne, &is_string);
3910
3911 __ cmp(undefined, candidate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003912 __ b(eq, not_found);
danno@chromium.org2c456792011-11-11 12:00:53 +00003913 // Must be the hole (deleted entry).
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003914 if (FLAG_debug_code) {
danno@chromium.org2c456792011-11-11 12:00:53 +00003915 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003916 __ cmp(ip, candidate);
danno@chromium.org59400602013-08-13 17:09:37 +00003917 __ Assert(eq, kOddballInStringTableIsNotUndefinedOrTheHole);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003918 }
3919 __ jmp(&next_probe[i]);
3920
3921 __ bind(&is_string);
3922
3923 // Check that the candidate is a non-external ASCII string. The instance
3924 // type is still in the scratch register from the CompareObjectType
3925 // operation.
3926 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &next_probe[i]);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003927
3928 // If length is not 2 the string is not a candidate.
3929 __ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset));
3930 __ cmp(scratch, Operand(Smi::FromInt(2)));
3931 __ b(ne, &next_probe[i]);
3932
ricow@chromium.org65fae842010-08-25 15:26:24 +00003933 // Check if the two characters match.
3934 // Assumes that word load is little endian.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003935 __ ldrh(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003936 __ cmp(chars, scratch);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003937 __ b(eq, &found_in_string_table);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003938 __ bind(&next_probe[i]);
3939 }
3940
3941 // No matching 2 character string found by probing.
3942 __ jmp(not_found);
3943
3944 // Scratch register contains result when we fall through to here.
danno@chromium.org2c456792011-11-11 12:00:53 +00003945 Register result = candidate;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003946 __ bind(&found_in_string_table);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003947 __ Move(r0, result);
3948}
3949
3950
3951void StringHelper::GenerateHashInit(MacroAssembler* masm,
3952 Register hash,
3953 Register character) {
3954 // hash = character + (character << 10);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003955 __ LoadRoot(hash, Heap::kHashSeedRootIndex);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003956 // Untag smi seed and add the character.
3957 __ add(hash, character, Operand(hash, LSR, kSmiTagSize));
3958 // hash += hash << 10;
3959 __ add(hash, hash, Operand(hash, LSL, 10));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003960 // hash ^= hash >> 6;
danno@chromium.org2c456792011-11-11 12:00:53 +00003961 __ eor(hash, hash, Operand(hash, LSR, 6));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003962}
3963
3964
3965void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
3966 Register hash,
3967 Register character) {
3968 // hash += character;
3969 __ add(hash, hash, Operand(character));
3970 // hash += hash << 10;
3971 __ add(hash, hash, Operand(hash, LSL, 10));
3972 // hash ^= hash >> 6;
danno@chromium.org2c456792011-11-11 12:00:53 +00003973 __ eor(hash, hash, Operand(hash, LSR, 6));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003974}
3975
3976
3977void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
3978 Register hash) {
3979 // hash += hash << 3;
3980 __ add(hash, hash, Operand(hash, LSL, 3));
3981 // hash ^= hash >> 11;
danno@chromium.org2c456792011-11-11 12:00:53 +00003982 __ eor(hash, hash, Operand(hash, LSR, 11));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003983 // hash += hash << 15;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003984 __ add(hash, hash, Operand(hash, LSL, 15));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003985
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003986 __ and_(hash, hash, Operand(String::kHashBitMask), SetCC);
danno@chromium.org2c456792011-11-11 12:00:53 +00003987
ricow@chromium.org65fae842010-08-25 15:26:24 +00003988 // if (hash == 0) hash = 27;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003989 __ mov(hash, Operand(StringHasher::kZeroHash), LeaveCC, eq);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003990}
3991
3992
3993void SubStringStub::Generate(MacroAssembler* masm) {
3994 Label runtime;
3995
3996 // Stack frame on entry.
3997 // lr: return address
3998 // sp[0]: to
3999 // sp[4]: from
4000 // sp[8]: string
4001
4002 // This stub is called from the native-call %_SubString(...), so
4003 // nothing can be assumed about the arguments. It is tested that:
4004 // "string" is a sequential string,
4005 // both "from" and "to" are smis, and
4006 // 0 <= from <= to <= string.length.
4007 // If any of these assumptions fail, we call the runtime system.
4008
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004009 const int kToOffset = 0 * kPointerSize;
4010 const int kFromOffset = 1 * kPointerSize;
4011 const int kStringOffset = 2 * kPointerSize;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004012
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004013 __ Ldrd(r2, r3, MemOperand(sp, kToOffset));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004014 STATIC_ASSERT(kFromOffset == kToOffset + 4);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004015 STATIC_ASSERT(kSmiTag == 0);
4016 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004017
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004018 // Arithmetic shift right by one un-smi-tags. In this case we rotate right
4019 // instead because we bail out on non-smi values: ROR and ASR are equivalent
4020 // for smis but they set the flags in a way that's easier to optimize.
4021 __ mov(r2, Operand(r2, ROR, 1), SetCC);
4022 __ mov(r3, Operand(r3, ROR, 1), SetCC, cc);
4023 // If either to or from had the smi tag bit set, then C is set now, and N
4024 // 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 +00004025 // We want to bailout to runtime here if From is negative. In that case, the
4026 // next instruction is not executed and we fall through to bailing out to
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004027 // runtime.
4028 // Executed if both r2 and r3 are untagged integers.
4029 __ sub(r2, r2, Operand(r3), SetCC, cc);
4030 // One of the above un-smis or the above SUB could have set N==1.
4031 __ b(mi, &runtime); // Either "from" or "to" is not an smi, or from > to.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004032
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004033 // Make sure first argument is a string.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004034 __ ldr(r0, MemOperand(sp, kStringOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004035 // Do a JumpIfSmi, but fold its jump into the subsequent string test.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004036 __ SmiTst(r0);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004037 Condition is_string = masm->IsObjectStringType(r0, r1, ne);
4038 ASSERT(is_string == eq);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004039 __ b(NegateCondition(is_string), &runtime);
4040
ulan@chromium.org2e04b582013-02-21 14:06:02 +00004041 Label single_char;
4042 __ cmp(r2, Operand(1));
4043 __ b(eq, &single_char);
4044
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004045 // Short-cut for the case of trivial substring.
4046 Label return_r0;
4047 // r0: original string
4048 // r2: result string length
4049 __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset));
4050 __ cmp(r2, Operand(r4, ASR, 1));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004051 // Return original string.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004052 __ b(eq, &return_r0);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004053 // Longer than original string's length or negative: unsafe arguments.
4054 __ b(hi, &runtime);
4055 // Shorter than original string's length: an actual substring.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004056
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004057 // Deal with different string types: update the index if necessary
4058 // and put the underlying string into r5.
4059 // r0: original string
4060 // r1: instance type
4061 // r2: length
4062 // r3: from index (untagged)
4063 Label underlying_unpacked, sliced_string, seq_or_external_string;
4064 // If the string is not indirect, it can only be sequential or external.
4065 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
4066 STATIC_ASSERT(kIsIndirectStringMask != 0);
4067 __ tst(r1, Operand(kIsIndirectStringMask));
4068 __ b(eq, &seq_or_external_string);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004069
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004070 __ tst(r1, Operand(kSlicedNotConsMask));
4071 __ b(ne, &sliced_string);
4072 // Cons string. Check whether it is flat, then fetch first part.
4073 __ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004074 __ CompareRoot(r5, Heap::kempty_stringRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004075 __ b(ne, &runtime);
4076 __ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset));
4077 // Update instance type.
4078 __ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset));
4079 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
4080 __ jmp(&underlying_unpacked);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004081
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004082 __ bind(&sliced_string);
4083 // Sliced string. Fetch parent and correct start index by offset.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004084 __ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004085 __ ldr(r4, FieldMemOperand(r0, SlicedString::kOffsetOffset));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004086 __ add(r3, r3, Operand(r4, ASR, 1)); // Add offset to index.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004087 // Update instance type.
4088 __ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset));
4089 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
4090 __ jmp(&underlying_unpacked);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004091
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004092 __ bind(&seq_or_external_string);
4093 // Sequential or external string. Just move string to the expected register.
4094 __ mov(r5, r0);
4095
4096 __ bind(&underlying_unpacked);
4097
4098 if (FLAG_string_slices) {
4099 Label copy_routine;
4100 // r5: underlying subject string
4101 // r1: instance type of underlying subject string
4102 // r2: length
4103 // r3: adjusted start index (untagged)
4104 __ cmp(r2, Operand(SlicedString::kMinLength));
4105 // Short slice. Copy instead of slicing.
4106 __ b(lt, &copy_routine);
4107 // Allocate new sliced string. At this point we do not reload the instance
4108 // type including the string encoding because we simply rely on the info
4109 // provided by the original string. It does not matter if the original
4110 // string's encoding is wrong because we always have to recheck encoding of
4111 // the newly created string's parent anyways due to externalized strings.
4112 Label two_byte_slice, set_slice_header;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004113 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004114 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
4115 __ tst(r1, Operand(kStringEncodingMask));
4116 __ b(eq, &two_byte_slice);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004117 __ AllocateAsciiSlicedString(r0, r2, r6, r4, &runtime);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004118 __ jmp(&set_slice_header);
4119 __ bind(&two_byte_slice);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004120 __ AllocateTwoByteSlicedString(r0, r2, r6, r4, &runtime);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004121 __ bind(&set_slice_header);
4122 __ mov(r3, Operand(r3, LSL, 1));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004123 __ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004124 __ str(r3, FieldMemOperand(r0, SlicedString::kOffsetOffset));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004125 __ jmp(&return_r0);
4126
4127 __ bind(&copy_routine);
4128 }
4129
4130 // r5: underlying subject string
4131 // r1: instance type of underlying subject string
4132 // r2: length
4133 // r3: adjusted start index (untagged)
4134 Label two_byte_sequential, sequential_string, allocate_result;
4135 STATIC_ASSERT(kExternalStringTag != 0);
4136 STATIC_ASSERT(kSeqStringTag == 0);
4137 __ tst(r1, Operand(kExternalStringTag));
4138 __ b(eq, &sequential_string);
4139
4140 // Handle external string.
4141 // Rule out short external strings.
4142 STATIC_CHECK(kShortExternalStringTag != 0);
4143 __ tst(r1, Operand(kShortExternalStringTag));
4144 __ b(ne, &runtime);
4145 __ ldr(r5, FieldMemOperand(r5, ExternalString::kResourceDataOffset));
4146 // r5 already points to the first character of underlying string.
4147 __ jmp(&allocate_result);
4148
4149 __ bind(&sequential_string);
4150 // Locate first character of underlying subject string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004151 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
4152 __ add(r5, r5, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004153
4154 __ bind(&allocate_result);
4155 // Sequential acii string. Allocate the result.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004156 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004157 __ tst(r1, Operand(kStringEncodingMask));
4158 __ b(eq, &two_byte_sequential);
4159
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004160 // Allocate and copy the resulting ASCII string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004161 __ AllocateAsciiString(r0, r2, r4, r6, r1, &runtime);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004162
4163 // Locate first character of substring to copy.
4164 __ add(r5, r5, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004165 // Locate first character of result.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004166 __ add(r1, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004167
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004168 // r0: result string
4169 // r1: first character of result string
4170 // r2: result string length
4171 // r5: first character of substring to copy
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004172 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004173 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r9,
ricow@chromium.org65fae842010-08-25 15:26:24 +00004174 COPY_ASCII | DEST_ALWAYS_ALIGNED);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004175 __ jmp(&return_r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004176
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004177 // Allocate and copy the resulting two-byte string.
4178 __ bind(&two_byte_sequential);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004179 __ AllocateTwoByteString(r0, r2, r4, r6, r1, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004180
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004181 // Locate first character of substring to copy.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004182 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004183 __ add(r5, r5, Operand(r3, LSL, 1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004184 // Locate first character of result.
4185 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004186
ricow@chromium.org65fae842010-08-25 15:26:24 +00004187 // r0: result string.
4188 // r1: first character of result.
4189 // r2: result length.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004190 // r5: first character of substring to copy.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004191 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004192 StringHelper::GenerateCopyCharactersLong(
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004193 masm, r1, r5, r2, r3, r4, r6, r9, DEST_ALWAYS_ALIGNED);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004194
4195 __ bind(&return_r0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004196 Counters* counters = masm->isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004197 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00004198 __ Drop(3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004199 __ Ret();
4200
4201 // Just jump to runtime to create the sub string.
4202 __ bind(&runtime);
4203 __ TailCallRuntime(Runtime::kSubString, 3, 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00004204
4205 __ bind(&single_char);
4206 // r0: original string
4207 // r1: instance type
4208 // r2: length
4209 // r3: from index (untagged)
4210 __ SmiTag(r3, r3);
4211 StringCharAtGenerator generator(
4212 r0, r3, r2, r0, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
4213 generator.GenerateFast(masm);
4214 __ Drop(3);
4215 __ Ret();
4216 generator.SkipSlow(masm, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004217}
4218
4219
lrn@chromium.org1c092762011-05-09 09:42:16 +00004220void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
4221 Register left,
4222 Register right,
4223 Register scratch1,
4224 Register scratch2,
4225 Register scratch3) {
4226 Register length = scratch1;
4227
4228 // Compare lengths.
4229 Label strings_not_equal, check_zero_length;
4230 __ ldr(length, FieldMemOperand(left, String::kLengthOffset));
4231 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset));
4232 __ cmp(length, scratch2);
4233 __ b(eq, &check_zero_length);
4234 __ bind(&strings_not_equal);
4235 __ mov(r0, Operand(Smi::FromInt(NOT_EQUAL)));
4236 __ Ret();
4237
4238 // Check if the length is zero.
4239 Label compare_chars;
4240 __ bind(&check_zero_length);
4241 STATIC_ASSERT(kSmiTag == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004242 __ cmp(length, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00004243 __ b(ne, &compare_chars);
4244 __ mov(r0, Operand(Smi::FromInt(EQUAL)));
4245 __ Ret();
4246
4247 // Compare characters.
4248 __ bind(&compare_chars);
4249 GenerateAsciiCharsCompareLoop(masm,
4250 left, right, length, scratch2, scratch3,
4251 &strings_not_equal);
4252
4253 // Characters are equal.
4254 __ mov(r0, Operand(Smi::FromInt(EQUAL)));
4255 __ Ret();
4256}
4257
4258
ricow@chromium.org65fae842010-08-25 15:26:24 +00004259void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
4260 Register left,
4261 Register right,
4262 Register scratch1,
4263 Register scratch2,
4264 Register scratch3,
4265 Register scratch4) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00004266 Label result_not_equal, compare_lengths;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004267 // Find minimum length and length difference.
4268 __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset));
4269 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset));
4270 __ sub(scratch3, scratch1, Operand(scratch2), SetCC);
4271 Register length_delta = scratch3;
4272 __ mov(scratch1, scratch2, LeaveCC, gt);
4273 Register min_length = scratch1;
4274 STATIC_ASSERT(kSmiTag == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004275 __ cmp(min_length, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004276 __ b(eq, &compare_lengths);
4277
lrn@chromium.org1c092762011-05-09 09:42:16 +00004278 // Compare loop.
4279 GenerateAsciiCharsCompareLoop(masm,
4280 left, right, min_length, scratch2, scratch4,
4281 &result_not_equal);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004282
lrn@chromium.org1c092762011-05-09 09:42:16 +00004283 // Compare lengths - strings up to min-length are equal.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004284 __ bind(&compare_lengths);
4285 ASSERT(Smi::FromInt(EQUAL) == static_cast<Smi*>(0));
lrn@chromium.org1c092762011-05-09 09:42:16 +00004286 // Use length_delta as result if it's zero.
4287 __ mov(r0, Operand(length_delta), SetCC);
4288 __ bind(&result_not_equal);
4289 // Conditionally update the result based either on length_delta or
4290 // the last comparion performed in the loop above.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004291 __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt);
4292 __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt);
4293 __ Ret();
4294}
4295
4296
lrn@chromium.org1c092762011-05-09 09:42:16 +00004297void StringCompareStub::GenerateAsciiCharsCompareLoop(
4298 MacroAssembler* masm,
4299 Register left,
4300 Register right,
4301 Register length,
4302 Register scratch1,
4303 Register scratch2,
4304 Label* chars_not_equal) {
4305 // Change index to run from -length to -1 by adding length to string
4306 // start. This means that loop ends when index reaches zero, which
4307 // doesn't need an additional compare.
4308 __ SmiUntag(length);
4309 __ add(scratch1, length,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004310 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
lrn@chromium.org1c092762011-05-09 09:42:16 +00004311 __ add(left, left, Operand(scratch1));
4312 __ add(right, right, Operand(scratch1));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004313 __ rsb(length, length, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00004314 Register index = length; // index = -length;
4315
4316 // Compare loop.
4317 Label loop;
4318 __ bind(&loop);
4319 __ ldrb(scratch1, MemOperand(left, index));
4320 __ ldrb(scratch2, MemOperand(right, index));
4321 __ cmp(scratch1, scratch2);
4322 __ b(ne, chars_not_equal);
4323 __ add(index, index, Operand(1), SetCC);
4324 __ b(ne, &loop);
4325}
4326
4327
ricow@chromium.org65fae842010-08-25 15:26:24 +00004328void StringCompareStub::Generate(MacroAssembler* masm) {
4329 Label runtime;
4330
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004331 Counters* counters = masm->isolate()->counters();
4332
ricow@chromium.org65fae842010-08-25 15:26:24 +00004333 // Stack frame on entry.
4334 // sp[0]: right string
4335 // sp[4]: left string
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004336 __ Ldrd(r0 , r1, MemOperand(sp)); // Load right in r0, left in r1.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004337
4338 Label not_same;
4339 __ cmp(r0, r1);
4340 __ b(ne, &not_same);
4341 STATIC_ASSERT(EQUAL == 0);
4342 STATIC_ASSERT(kSmiTag == 0);
4343 __ mov(r0, Operand(Smi::FromInt(EQUAL)));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004344 __ IncrementCounter(counters->string_compare_native(), 1, r1, r2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004345 __ add(sp, sp, Operand(2 * kPointerSize));
4346 __ Ret();
4347
4348 __ bind(&not_same);
4349
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004350 // Check that both objects are sequential ASCII strings.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004351 __ JumpIfNotBothSequentialAsciiStrings(r1, r0, r2, r3, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004352
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004353 // Compare flat ASCII strings natively. Remove arguments from stack first.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004354 __ IncrementCounter(counters->string_compare_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004355 __ add(sp, sp, Operand(2 * kPointerSize));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004356 GenerateCompareFlatAsciiStrings(masm, r1, r0, r2, r3, r4, r5);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004357
4358 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
4359 // tagged as a small integer.
4360 __ bind(&runtime);
4361 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
4362}
4363
4364
4365void StringAddStub::Generate(MacroAssembler* masm) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004366 Label call_runtime, call_builtin;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004367 Builtins::JavaScript builtin_id = Builtins::ADD;
4368
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004369 Counters* counters = masm->isolate()->counters();
4370
ricow@chromium.org65fae842010-08-25 15:26:24 +00004371 // Stack on entry:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004372 // sp[0]: second argument (right).
4373 // sp[4]: first argument (left).
ricow@chromium.org65fae842010-08-25 15:26:24 +00004374
4375 // Load the two arguments.
4376 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument.
4377 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument.
4378
4379 // Make sure that both arguments are strings if not known in advance.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004380 // Otherwise, at least one of the arguments is definitely a string,
4381 // and we convert the one that is not known to be a string.
4382 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
4383 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT);
4384 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004385 __ JumpIfEitherSmi(r0, r1, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004386 // Load instance types.
4387 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4388 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4389 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4390 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4391 STATIC_ASSERT(kStringTag == 0);
4392 // If either is not a string, go to runtime.
4393 __ tst(r4, Operand(kIsNotStringMask));
4394 __ tst(r5, Operand(kIsNotStringMask), eq);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004395 __ b(ne, &call_runtime);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004396 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
4397 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0);
4398 GenerateConvertArgument(
4399 masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &call_builtin);
4400 builtin_id = Builtins::STRING_ADD_RIGHT;
4401 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
4402 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0);
4403 GenerateConvertArgument(
4404 masm, 0 * kPointerSize, r1, r2, r3, r4, r5, &call_builtin);
4405 builtin_id = Builtins::STRING_ADD_LEFT;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004406 }
4407
4408 // Both arguments are strings.
4409 // r0: first string
4410 // r1: second string
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004411 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4412 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
ricow@chromium.org65fae842010-08-25 15:26:24 +00004413 {
4414 Label strings_not_empty;
4415 // Check if either of the strings are empty. In that case return the other.
4416 __ ldr(r2, FieldMemOperand(r0, String::kLengthOffset));
4417 __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset));
4418 STATIC_ASSERT(kSmiTag == 0);
4419 __ cmp(r2, Operand(Smi::FromInt(0))); // Test if first string is empty.
4420 __ mov(r0, Operand(r1), LeaveCC, eq); // If first is empty, return second.
4421 STATIC_ASSERT(kSmiTag == 0);
4422 // Else test if second string is empty.
4423 __ cmp(r3, Operand(Smi::FromInt(0)), ne);
4424 __ b(ne, &strings_not_empty); // If either string was empty, return r0.
4425
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004426 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004427 __ add(sp, sp, Operand(2 * kPointerSize));
4428 __ Ret();
4429
4430 __ bind(&strings_not_empty);
4431 }
4432
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004433 __ SmiUntag(r2);
4434 __ SmiUntag(r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004435 // Both strings are non-empty.
4436 // r0: first string
4437 // r1: second string
4438 // r2: length of first string
4439 // r3: length of second string
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004440 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4441 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
ricow@chromium.org65fae842010-08-25 15:26:24 +00004442 // Look at the length of the result of adding the two strings.
4443 Label string_add_flat_result, longer_than_two;
4444 // Adding two lengths can't overflow.
4445 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2);
4446 __ add(r6, r2, Operand(r3));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004447 // Use the string table when adding two one character strings, as it
4448 // helps later optimizations to return a string here.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004449 __ cmp(r6, Operand(2));
4450 __ b(ne, &longer_than_two);
4451
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004452 // Check that both strings are non-external ASCII strings.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004453 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004454 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4455 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4456 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4457 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4458 }
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004459 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r3,
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004460 &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004461
4462 // Get the two characters forming the sub string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004463 __ ldrb(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize));
4464 __ ldrb(r3, FieldMemOperand(r1, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004465
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004466 // Try to lookup two character string in string table. If it is not found
ricow@chromium.org65fae842010-08-25 15:26:24 +00004467 // just allocate a new one.
4468 Label make_two_character_string;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004469 StringHelper::GenerateTwoCharacterStringTableProbe(
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004470 masm, r2, r3, r6, r0, r4, r5, r9, &make_two_character_string);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004471 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004472 __ add(sp, sp, Operand(2 * kPointerSize));
4473 __ Ret();
4474
4475 __ bind(&make_two_character_string);
4476 // Resulting string has length 2 and first chars of two strings
4477 // are combined into single halfword in r2 register.
4478 // So we can fill resulting string without two loops by a single
4479 // halfword store instruction (which assumes that processor is
4480 // in a little endian mode)
4481 __ mov(r6, Operand(2));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004482 __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004483 __ strh(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004484 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004485 __ add(sp, sp, Operand(2 * kPointerSize));
4486 __ Ret();
4487
4488 __ bind(&longer_than_two);
4489 // Check if resulting string will be flat.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004490 __ cmp(r6, Operand(ConsString::kMinLength));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004491 __ b(lt, &string_add_flat_result);
4492 // Handle exceptionally long strings in the runtime system.
4493 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
4494 ASSERT(IsPowerOf2(String::kMaxLength + 1));
4495 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not.
4496 __ cmp(r6, Operand(String::kMaxLength + 1));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004497 __ b(hs, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004498
4499 // If result is not supposed to be flat, allocate a cons string object.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004500 // If both strings are ASCII the result is an ASCII cons string.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004501 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004502 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4503 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4504 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4505 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4506 }
4507 Label non_ascii, allocated, ascii_data;
4508 STATIC_ASSERT(kTwoByteStringTag == 0);
4509 __ tst(r4, Operand(kStringEncodingMask));
4510 __ tst(r5, Operand(kStringEncodingMask), ne);
4511 __ b(eq, &non_ascii);
4512
4513 // Allocate an ASCII cons string.
4514 __ bind(&ascii_data);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004515 __ AllocateAsciiConsString(r3, r6, r4, r5, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004516 __ bind(&allocated);
4517 // Fill the fields of the cons string.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004518 Label skip_write_barrier, after_writing;
4519 ExternalReference high_promotion_mode = ExternalReference::
4520 new_space_high_promotion_mode_active_address(masm->isolate());
4521 __ mov(r4, Operand(high_promotion_mode));
4522 __ ldr(r4, MemOperand(r4, 0));
4523 __ cmp(r4, Operand::Zero());
4524 __ b(eq, &skip_write_barrier);
4525
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004526 __ str(r0, FieldMemOperand(r3, ConsString::kFirstOffset));
4527 __ RecordWriteField(r3,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004528 ConsString::kFirstOffset,
4529 r0,
4530 r4,
4531 kLRHasNotBeenSaved,
4532 kDontSaveFPRegs);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004533 __ str(r1, FieldMemOperand(r3, ConsString::kSecondOffset));
4534 __ RecordWriteField(r3,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004535 ConsString::kSecondOffset,
4536 r1,
4537 r4,
4538 kLRHasNotBeenSaved,
4539 kDontSaveFPRegs);
4540 __ jmp(&after_writing);
4541
4542 __ bind(&skip_write_barrier);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004543 __ str(r0, FieldMemOperand(r3, ConsString::kFirstOffset));
4544 __ str(r1, FieldMemOperand(r3, ConsString::kSecondOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004545
4546 __ bind(&after_writing);
4547
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004548 __ mov(r0, Operand(r3));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004549 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004550 __ add(sp, sp, Operand(2 * kPointerSize));
4551 __ Ret();
4552
4553 __ bind(&non_ascii);
4554 // At least one of the strings is two-byte. Check whether it happens
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004555 // to contain only one byte characters.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004556 // r4: first instance type.
4557 // r5: second instance type.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004558 __ tst(r4, Operand(kOneByteDataHintMask));
4559 __ tst(r5, Operand(kOneByteDataHintMask), ne);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004560 __ b(ne, &ascii_data);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00004561 __ eor(r4, r4, Operand(r5));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004562 STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0);
4563 __ and_(r4, r4, Operand(kOneByteStringTag | kOneByteDataHintTag));
4564 __ cmp(r4, Operand(kOneByteStringTag | kOneByteDataHintTag));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00004565 __ b(eq, &ascii_data);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004566
4567 // Allocate a two byte cons string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004568 __ AllocateTwoByteConsString(r3, r6, r4, r5, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004569 __ jmp(&allocated);
4570
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004571 // We cannot encounter sliced strings or cons strings here since:
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004572 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004573 // Handle creating a flat result from either external or sequential strings.
4574 // Locate the first characters' locations.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004575 // r0: first string
4576 // r1: second string
4577 // r2: length of first string
4578 // r3: length of second string
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004579 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4580 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
ricow@chromium.org65fae842010-08-25 15:26:24 +00004581 // r6: sum of lengths.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004582 Label first_prepared, second_prepared;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004583 __ bind(&string_add_flat_result);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004584 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004585 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4586 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4587 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4588 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4589 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004590
4591 // Check whether both strings have same encoding
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004592 __ eor(ip, r4, Operand(r5));
4593 ASSERT(__ ImmediateFitsAddrMode1Instruction(kStringEncodingMask));
4594 __ tst(ip, Operand(kStringEncodingMask));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004595 __ b(ne, &call_runtime);
4596
4597 STATIC_ASSERT(kSeqStringTag == 0);
4598 __ tst(r4, Operand(kStringRepresentationMask));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004599 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004600 __ add(r6,
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004601 r0,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004602 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag),
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004603 LeaveCC,
4604 eq);
4605 __ b(eq, &first_prepared);
4606 // External string: rule out short external string and load string resource.
4607 STATIC_ASSERT(kShortExternalStringTag != 0);
4608 __ tst(r4, Operand(kShortExternalStringMask));
4609 __ b(ne, &call_runtime);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004610 __ ldr(r6, FieldMemOperand(r0, ExternalString::kResourceDataOffset));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004611 __ bind(&first_prepared);
4612
4613 STATIC_ASSERT(kSeqStringTag == 0);
4614 __ tst(r5, Operand(kStringRepresentationMask));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004615 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004616 __ add(r1,
4617 r1,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004618 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag),
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004619 LeaveCC,
4620 eq);
4621 __ b(eq, &second_prepared);
4622 // External string: rule out short external string and load string resource.
4623 STATIC_ASSERT(kShortExternalStringTag != 0);
4624 __ tst(r5, Operand(kShortExternalStringMask));
4625 __ b(ne, &call_runtime);
4626 __ ldr(r1, FieldMemOperand(r1, ExternalString::kResourceDataOffset));
4627 __ bind(&second_prepared);
4628
4629 Label non_ascii_string_add_flat_result;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004630 // r6: first character of first string
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004631 // r1: first character of second string
4632 // r2: length of first string.
4633 // r3: length of second string.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004634 // Both strings have the same encoding.
4635 STATIC_ASSERT(kTwoByteStringTag == 0);
4636 __ tst(r5, Operand(kStringEncodingMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004637 __ b(eq, &non_ascii_string_add_flat_result);
4638
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004639 __ add(r2, r2, Operand(r3));
4640 __ AllocateAsciiString(r0, r2, r4, r5, r9, &call_runtime);
4641 __ sub(r2, r2, Operand(r3));
4642 __ add(r5, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004643 // r0: result string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004644 // r6: first character of first string.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004645 // r1: first character of second string.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004646 // r2: length of first string.
4647 // r3: length of second string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004648 // r5: first character of result.
4649 StringHelper::GenerateCopyCharacters(masm, r5, r6, r2, r4, true);
4650 // r5: next character of result.
4651 StringHelper::GenerateCopyCharacters(masm, r5, r1, r3, r4, true);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004652 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004653 __ add(sp, sp, Operand(2 * kPointerSize));
4654 __ Ret();
4655
4656 __ bind(&non_ascii_string_add_flat_result);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004657 __ add(r2, r2, Operand(r3));
4658 __ AllocateTwoByteString(r0, r2, r4, r5, r9, &call_runtime);
4659 __ sub(r2, r2, Operand(r3));
4660 __ add(r5, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004661 // r0: result string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004662 // r6: first character of first string.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004663 // r1: first character of second string.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004664 // r2: length of first string.
4665 // r3: length of second string.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004666 // r5: first character of result.
4667 StringHelper::GenerateCopyCharacters(masm, r5, r6, r2, r4, false);
4668 // r5: next character of result.
4669 StringHelper::GenerateCopyCharacters(masm, r5, r1, r3, r4, false);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004670 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004671 __ add(sp, sp, Operand(2 * kPointerSize));
4672 __ Ret();
4673
4674 // Just jump to runtime to add the two strings.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004675 __ bind(&call_runtime);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004676 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00004677 GenerateRegisterArgsPop(masm);
4678 // Build a frame
4679 {
4680 FrameScope scope(masm, StackFrame::INTERNAL);
4681 GenerateRegisterArgsPush(masm);
4682 __ CallRuntime(Runtime::kStringAdd, 2);
4683 }
4684 __ Ret();
4685 } else {
4686 __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
4687 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004688
4689 if (call_builtin.is_linked()) {
4690 __ bind(&call_builtin);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004691 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00004692 GenerateRegisterArgsPop(masm);
4693 // Build a frame
4694 {
4695 FrameScope scope(masm, StackFrame::INTERNAL);
4696 GenerateRegisterArgsPush(masm);
4697 __ InvokeBuiltin(builtin_id, CALL_FUNCTION);
4698 }
4699 __ Ret();
4700 } else {
4701 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
4702 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004703 }
4704}
4705
4706
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00004707void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
4708 __ push(r0);
4709 __ push(r1);
4710}
4711
4712
4713void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm) {
4714 __ pop(r1);
4715 __ pop(r0);
4716}
4717
4718
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004719void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
4720 int stack_offset,
4721 Register arg,
4722 Register scratch1,
4723 Register scratch2,
4724 Register scratch3,
4725 Register scratch4,
4726 Label* slow) {
4727 // First check if the argument is already a string.
4728 Label not_string, done;
4729 __ JumpIfSmi(arg, &not_string);
4730 __ CompareObjectType(arg, scratch1, scratch1, FIRST_NONSTRING_TYPE);
4731 __ b(lt, &done);
4732
4733 // Check the number to string cache.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004734 __ bind(&not_string);
4735 // Puts the cached result into scratch1.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004736 __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, scratch4, slow);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004737 __ mov(arg, scratch1);
4738 __ str(arg, MemOperand(sp, stack_offset));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004739 __ bind(&done);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004740}
4741
4742
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004743void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004744 ASSERT(state_ == CompareIC::SMI);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004745 Label miss;
4746 __ orr(r2, r1, r0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004747 __ JumpIfNotSmi(r2, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004748
4749 if (GetCondition() == eq) {
4750 // For equality we do not care about the sign of the result.
4751 __ sub(r0, r0, r1, SetCC);
4752 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004753 // Untag before subtracting to avoid handling overflow.
4754 __ SmiUntag(r1);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004755 __ sub(r0, r1, Operand::SmiUntag(r0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004756 }
4757 __ Ret();
4758
4759 __ bind(&miss);
4760 GenerateMiss(masm);
4761}
4762
4763
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004764void ICCompareStub::GenerateNumbers(MacroAssembler* masm) {
4765 ASSERT(state_ == CompareIC::NUMBER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004766
4767 Label generic_stub;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004768 Label unordered, maybe_undefined1, maybe_undefined2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004769 Label miss;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004770
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004771 if (left_ == CompareIC::SMI) {
4772 __ JumpIfNotSmi(r1, &miss);
4773 }
4774 if (right_ == CompareIC::SMI) {
4775 __ JumpIfNotSmi(r0, &miss);
4776 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004777
4778 // Inlining the double comparison and falling back to the general compare
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004779 // stub if NaN is involved.
4780 // Load left and right operand.
4781 Label done, left, left_smi, right_smi;
4782 __ JumpIfSmi(r0, &right_smi);
4783 __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
4784 DONT_DO_SMI_CHECK);
4785 __ sub(r2, r0, Operand(kHeapObjectTag));
4786 __ vldr(d1, r2, HeapNumber::kValueOffset);
4787 __ b(&left);
4788 __ bind(&right_smi);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004789 __ SmiToDouble(d1, r0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004790
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004791 __ bind(&left);
4792 __ JumpIfSmi(r1, &left_smi);
4793 __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
4794 DONT_DO_SMI_CHECK);
4795 __ sub(r2, r1, Operand(kHeapObjectTag));
4796 __ vldr(d0, r2, HeapNumber::kValueOffset);
4797 __ b(&done);
4798 __ bind(&left_smi);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004799 __ SmiToDouble(d0, r1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004800
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004801 __ bind(&done);
4802 // Compare operands.
4803 __ VFPCompareAndSetFlags(d0, d1);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004804
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004805 // Don't base result on status bits when a NaN is involved.
4806 __ b(vs, &unordered);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004807
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004808 // Return a result of -1, 0, or 1, based on status bits.
4809 __ mov(r0, Operand(EQUAL), LeaveCC, eq);
4810 __ mov(r0, Operand(LESS), LeaveCC, lt);
4811 __ mov(r0, Operand(GREATER), LeaveCC, gt);
4812 __ Ret();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004813
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004814 __ bind(&unordered);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004815 __ bind(&generic_stub);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004816 ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
4817 CompareIC::GENERIC);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004818 __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004819
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004820 __ bind(&maybe_undefined1);
4821 if (Token::IsOrderedRelationalCompareOp(op_)) {
4822 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
4823 __ b(ne, &miss);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004824 __ JumpIfSmi(r1, &unordered);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004825 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
4826 __ b(ne, &maybe_undefined2);
4827 __ jmp(&unordered);
4828 }
4829
4830 __ bind(&maybe_undefined2);
4831 if (Token::IsOrderedRelationalCompareOp(op_)) {
4832 __ CompareRoot(r1, Heap::kUndefinedValueRootIndex);
4833 __ b(eq, &unordered);
4834 }
4835
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004836 __ bind(&miss);
4837 GenerateMiss(masm);
4838}
4839
4840
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004841void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) {
4842 ASSERT(state_ == CompareIC::INTERNALIZED_STRING);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004843 Label miss;
4844
4845 // Registers containing left and right operands respectively.
4846 Register left = r1;
4847 Register right = r0;
4848 Register tmp1 = r2;
4849 Register tmp2 = r3;
4850
4851 // Check that both operands are heap objects.
4852 __ JumpIfEitherSmi(left, right, &miss);
4853
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004854 // Check that both operands are internalized strings.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004855 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
4856 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
4857 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
4858 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004859 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
4860 __ orr(tmp1, tmp1, Operand(tmp2));
4861 __ tst(tmp1, Operand(kIsNotStringMask | kIsNotInternalizedMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004862 __ b(ne, &miss);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004863
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004864 // Internalized strings are compared by identity.
4865 __ cmp(left, right);
4866 // Make sure r0 is non-zero. At this point input operands are
4867 // guaranteed to be non-zero.
4868 ASSERT(right.is(r0));
4869 STATIC_ASSERT(EQUAL == 0);
4870 STATIC_ASSERT(kSmiTag == 0);
4871 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
4872 __ Ret();
4873
4874 __ bind(&miss);
4875 GenerateMiss(masm);
4876}
4877
4878
4879void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) {
4880 ASSERT(state_ == CompareIC::UNIQUE_NAME);
4881 ASSERT(GetCondition() == eq);
4882 Label miss;
4883
4884 // Registers containing left and right operands respectively.
4885 Register left = r1;
4886 Register right = r0;
4887 Register tmp1 = r2;
4888 Register tmp2 = r3;
4889
4890 // Check that both operands are heap objects.
4891 __ JumpIfEitherSmi(left, right, &miss);
4892
4893 // Check that both operands are unique names. This leaves the instance
4894 // types loaded in tmp1 and tmp2.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004895 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
4896 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
4897 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
4898 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
4899
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004900 __ JumpIfNotUniqueName(tmp1, &miss);
4901 __ JumpIfNotUniqueName(tmp2, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004902
4903 // Unique names are compared by identity.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004904 __ cmp(left, right);
4905 // Make sure r0 is non-zero. At this point input operands are
4906 // guaranteed to be non-zero.
4907 ASSERT(right.is(r0));
4908 STATIC_ASSERT(EQUAL == 0);
4909 STATIC_ASSERT(kSmiTag == 0);
4910 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
4911 __ Ret();
4912
4913 __ bind(&miss);
4914 GenerateMiss(masm);
4915}
4916
4917
lrn@chromium.org1c092762011-05-09 09:42:16 +00004918void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004919 ASSERT(state_ == CompareIC::STRING);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004920 Label miss;
4921
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004922 bool equality = Token::IsEqualityOp(op_);
4923
lrn@chromium.org1c092762011-05-09 09:42:16 +00004924 // Registers containing left and right operands respectively.
4925 Register left = r1;
4926 Register right = r0;
4927 Register tmp1 = r2;
4928 Register tmp2 = r3;
4929 Register tmp3 = r4;
4930 Register tmp4 = r5;
4931
4932 // Check that both operands are heap objects.
4933 __ JumpIfEitherSmi(left, right, &miss);
4934
4935 // Check that both operands are strings. This leaves the instance
4936 // types loaded in tmp1 and tmp2.
4937 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
4938 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
4939 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
4940 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
4941 STATIC_ASSERT(kNotStringTag != 0);
4942 __ orr(tmp3, tmp1, tmp2);
4943 __ tst(tmp3, Operand(kIsNotStringMask));
4944 __ b(ne, &miss);
4945
4946 // Fast check for identical strings.
4947 __ cmp(left, right);
4948 STATIC_ASSERT(EQUAL == 0);
4949 STATIC_ASSERT(kSmiTag == 0);
4950 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
4951 __ Ret(eq);
4952
4953 // Handle not identical strings.
4954
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004955 // Check that both strings are internalized strings. If they are, we're done
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004956 // because we already know they are not identical. We know they are both
4957 // strings.
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004958 if (equality) {
4959 ASSERT(GetCondition() == eq);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004960 STATIC_ASSERT(kInternalizedTag == 0);
4961 __ orr(tmp3, tmp1, Operand(tmp2));
4962 __ tst(tmp3, Operand(kIsNotInternalizedMask));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004963 // Make sure r0 is non-zero. At this point input operands are
4964 // guaranteed to be non-zero.
4965 ASSERT(right.is(r0));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004966 __ Ret(eq);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004967 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004968
4969 // Check that both strings are sequential ASCII.
4970 Label runtime;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004971 __ JumpIfBothInstanceTypesAreNotSequentialAscii(
4972 tmp1, tmp2, tmp3, tmp4, &runtime);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004973
4974 // Compare flat ASCII strings. Returns when done.
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004975 if (equality) {
4976 StringCompareStub::GenerateFlatAsciiStringEquals(
4977 masm, left, right, tmp1, tmp2, tmp3);
4978 } else {
4979 StringCompareStub::GenerateCompareFlatAsciiStrings(
4980 masm, left, right, tmp1, tmp2, tmp3, tmp4);
4981 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004982
4983 // Handle more complex cases in runtime.
4984 __ bind(&runtime);
4985 __ Push(left, right);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004986 if (equality) {
4987 __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
4988 } else {
4989 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
4990 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004991
4992 __ bind(&miss);
4993 GenerateMiss(masm);
4994}
4995
4996
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004997void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004998 ASSERT(state_ == CompareIC::OBJECT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004999 Label miss;
5000 __ and_(r2, r1, Operand(r0));
whesse@chromium.org7b260152011-06-20 15:33:18 +00005001 __ JumpIfSmi(r2, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005002
5003 __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE);
5004 __ b(ne, &miss);
5005 __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE);
5006 __ b(ne, &miss);
5007
5008 ASSERT(GetCondition() == eq);
5009 __ sub(r0, r0, Operand(r1));
5010 __ Ret();
5011
5012 __ bind(&miss);
5013 GenerateMiss(masm);
5014}
5015
5016
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005017void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
5018 Label miss;
5019 __ and_(r2, r1, Operand(r0));
5020 __ JumpIfSmi(r2, &miss);
5021 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
5022 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
5023 __ cmp(r2, Operand(known_map_));
5024 __ b(ne, &miss);
5025 __ cmp(r3, Operand(known_map_));
5026 __ b(ne, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005027
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005028 __ sub(r0, r0, Operand(r1));
5029 __ Ret();
5030
5031 __ bind(&miss);
5032 GenerateMiss(masm);
5033}
5034
5035
5036
5037void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005038 {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005039 // Call the runtime system in a fresh internal frame.
5040 ExternalReference miss =
5041 ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
5042
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005043 FrameScope scope(masm, StackFrame::INTERNAL);
5044 __ Push(r1, r0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005045 __ push(lr);
5046 __ Push(r1, r0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005047 __ mov(ip, Operand(Smi::FromInt(op_)));
5048 __ push(ip);
5049 __ CallExternalReference(miss, 3);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005050 // Compute the entry point of the rewritten stub.
5051 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
5052 // Restore registers.
5053 __ pop(lr);
5054 __ pop(r0);
5055 __ pop(r1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005056 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005057
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005058 __ Jump(r2);
5059}
5060
5061
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005062void DirectCEntryStub::Generate(MacroAssembler* masm) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00005063 // Place the return address on the stack, making the call
5064 // GC safe. The RegExp backend also relies on this.
5065 __ str(lr, MemOperand(sp, 0));
5066 __ blx(ip); // Call the C++ function.
5067 __ VFPEnsureFPSCRState(r2);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005068 __ ldr(pc, MemOperand(sp, 0));
5069}
5070
5071
5072void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005073 Register target) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005074 intptr_t code =
5075 reinterpret_cast<intptr_t>(GetCode(masm->isolate()).location());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00005076 __ Move(ip, target);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005077 __ mov(lr, Operand(code, RelocInfo::CODE_TARGET));
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00005078 __ blx(lr); // Call the stub.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005079}
5080
5081
ulan@chromium.org750145a2013-03-07 15:14:13 +00005082void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
5083 Label* miss,
5084 Label* done,
5085 Register receiver,
5086 Register properties,
5087 Handle<Name> name,
5088 Register scratch0) {
5089 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005090 // If names of slots in range from 1 to kProbes - 1 for the hash value are
5091 // not equal to the name and kProbes-th slot is not used (its name is the
5092 // undefined value), it guarantees the hash table doesn't contain the
5093 // property. It's true even if some slots represent deleted properties
ulan@chromium.org967e2702012-02-28 09:49:15 +00005094 // (their names are the hole value).
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005095 for (int i = 0; i < kInlinedProbes; i++) {
5096 // scratch0 points to properties hash.
5097 // Compute the masked index: (hash + i + i * i) & mask.
5098 Register index = scratch0;
5099 // Capacity is smi 2^n.
5100 __ ldr(index, FieldMemOperand(properties, kCapacityOffset));
5101 __ sub(index, index, Operand(1));
5102 __ and_(index, index, Operand(
ulan@chromium.org750145a2013-03-07 15:14:13 +00005103 Smi::FromInt(name->Hash() + NameDictionary::GetProbeOffset(i))));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005104
5105 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005106 ASSERT(NameDictionary::kEntrySize == 3);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005107 __ add(index, index, Operand(index, LSL, 1)); // index *= 3.
5108
5109 Register entity_name = scratch0;
5110 // Having undefined at this place means the name is not contained.
5111 ASSERT_EQ(kSmiTagSize, 1);
5112 Register tmp = properties;
5113 __ add(tmp, properties, Operand(index, LSL, 1));
5114 __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
5115
5116 ASSERT(!tmp.is(entity_name));
5117 __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
5118 __ cmp(entity_name, tmp);
5119 __ b(eq, done);
5120
ulan@chromium.org77802e82013-03-26 11:54:42 +00005121 // Load the hole ready for use below:
5122 __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex);
ulan@chromium.org967e2702012-02-28 09:49:15 +00005123
ulan@chromium.org77802e82013-03-26 11:54:42 +00005124 // Stop if found the property.
5125 __ cmp(entity_name, Operand(Handle<Name>(name)));
5126 __ b(eq, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005127
ulan@chromium.org77802e82013-03-26 11:54:42 +00005128 Label good;
5129 __ cmp(entity_name, tmp);
5130 __ b(eq, &good);
ulan@chromium.org967e2702012-02-28 09:49:15 +00005131
ulan@chromium.org77802e82013-03-26 11:54:42 +00005132 // Check if the entry name is not a unique name.
5133 __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
5134 __ ldrb(entity_name,
5135 FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005136 __ JumpIfNotUniqueName(entity_name, miss);
ulan@chromium.org77802e82013-03-26 11:54:42 +00005137 __ bind(&good);
ulan@chromium.org967e2702012-02-28 09:49:15 +00005138
ulan@chromium.org77802e82013-03-26 11:54:42 +00005139 // Restore the properties.
5140 __ ldr(properties,
5141 FieldMemOperand(receiver, JSObject::kPropertiesOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005142 }
5143
5144 const int spill_mask =
5145 (lr.bit() | r6.bit() | r5.bit() | r4.bit() | r3.bit() |
5146 r2.bit() | r1.bit() | r0.bit());
5147
5148 __ stm(db_w, sp, spill_mask);
5149 __ ldr(r0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +00005150 __ mov(r1, Operand(Handle<Name>(name)));
5151 NameDictionaryLookupStub stub(NEGATIVE_LOOKUP);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005152 __ CallStub(&stub);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005153 __ cmp(r0, Operand::Zero());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005154 __ ldm(ia_w, sp, spill_mask);
5155
5156 __ b(eq, done);
5157 __ b(ne, miss);
5158}
5159
5160
ulan@chromium.org750145a2013-03-07 15:14:13 +00005161// Probe the name dictionary in the |elements| register. Jump to the
lrn@chromium.org1c092762011-05-09 09:42:16 +00005162// |done| label if a property with the given name is found. Jump to
5163// the |miss| label otherwise.
5164// If lookup was successful |scratch2| will be equal to elements + 4 * index.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005165void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
5166 Label* miss,
5167 Label* done,
5168 Register elements,
5169 Register name,
5170 Register scratch1,
5171 Register scratch2) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00005172 ASSERT(!elements.is(scratch1));
5173 ASSERT(!elements.is(scratch2));
5174 ASSERT(!name.is(scratch1));
5175 ASSERT(!name.is(scratch2));
5176
ulan@chromium.org750145a2013-03-07 15:14:13 +00005177 __ AssertName(name);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005178
5179 // Compute the capacity mask.
5180 __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00005181 __ SmiUntag(scratch1);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005182 __ sub(scratch1, scratch1, Operand(1));
5183
5184 // Generate an unrolled loop that performs a few probes before
5185 // giving up. Measurements done on Gmail indicate that 2 probes
5186 // cover ~93% of loads from dictionaries.
5187 for (int i = 0; i < kInlinedProbes; i++) {
5188 // Compute the masked index: (hash + i + i * i) & mask.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005189 __ ldr(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005190 if (i > 0) {
5191 // Add the probe offset (i + i * i) left shifted to avoid right shifting
5192 // the hash in a separate instruction. The value hash + i + i * i is right
5193 // shifted in the following and instruction.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005194 ASSERT(NameDictionary::GetProbeOffset(i) <
5195 1 << (32 - Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005196 __ add(scratch2, scratch2, Operand(
ulan@chromium.org750145a2013-03-07 15:14:13 +00005197 NameDictionary::GetProbeOffset(i) << Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005198 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00005199 __ and_(scratch2, scratch1, Operand(scratch2, LSR, Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005200
5201 // Scale the index by multiplying by the element size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005202 ASSERT(NameDictionary::kEntrySize == 3);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005203 // scratch2 = scratch2 * 3.
5204 __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
5205
5206 // Check if the key is identical to the name.
5207 __ add(scratch2, elements, Operand(scratch2, LSL, 2));
5208 __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
5209 __ cmp(name, Operand(ip));
5210 __ b(eq, done);
5211 }
5212
5213 const int spill_mask =
5214 (lr.bit() | r6.bit() | r5.bit() | r4.bit() |
5215 r3.bit() | r2.bit() | r1.bit() | r0.bit()) &
5216 ~(scratch1.bit() | scratch2.bit());
5217
5218 __ stm(db_w, sp, spill_mask);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00005219 if (name.is(r0)) {
5220 ASSERT(!elements.is(r1));
5221 __ Move(r1, name);
5222 __ Move(r0, elements);
5223 } else {
5224 __ Move(r0, elements);
5225 __ Move(r1, name);
5226 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00005227 NameDictionaryLookupStub stub(POSITIVE_LOOKUP);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005228 __ CallStub(&stub);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005229 __ cmp(r0, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00005230 __ mov(scratch2, Operand(r2));
5231 __ ldm(ia_w, sp, spill_mask);
5232
5233 __ b(ne, done);
5234 __ b(eq, miss);
5235}
5236
5237
ulan@chromium.org750145a2013-03-07 15:14:13 +00005238void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005239 // This stub overrides SometimesSetsUpAFrame() to return false. That means
5240 // we cannot call anything that could cause a GC from this stub.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005241 // Registers:
ulan@chromium.org750145a2013-03-07 15:14:13 +00005242 // result: NameDictionary to probe
lrn@chromium.org1c092762011-05-09 09:42:16 +00005243 // r1: key
ulan@chromium.org750145a2013-03-07 15:14:13 +00005244 // dictionary: NameDictionary to probe.
5245 // index: will hold an index of entry if lookup is successful.
5246 // might alias with result_.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005247 // Returns:
5248 // result_ is zero if lookup failed, non zero otherwise.
5249
5250 Register result = r0;
5251 Register dictionary = r0;
5252 Register key = r1;
5253 Register index = r2;
5254 Register mask = r3;
5255 Register hash = r4;
5256 Register undefined = r5;
5257 Register entry_key = r6;
5258
5259 Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
5260
5261 __ ldr(mask, FieldMemOperand(dictionary, kCapacityOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00005262 __ SmiUntag(mask);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005263 __ sub(mask, mask, Operand(1));
5264
ulan@chromium.org750145a2013-03-07 15:14:13 +00005265 __ ldr(hash, FieldMemOperand(key, Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005266
5267 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
5268
5269 for (int i = kInlinedProbes; i < kTotalProbes; i++) {
5270 // Compute the masked index: (hash + i + i * i) & mask.
5271 // Capacity is smi 2^n.
5272 if (i > 0) {
5273 // Add the probe offset (i + i * i) left shifted to avoid right shifting
5274 // the hash in a separate instruction. The value hash + i + i * i is right
5275 // shifted in the following and instruction.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005276 ASSERT(NameDictionary::GetProbeOffset(i) <
5277 1 << (32 - Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005278 __ add(index, hash, Operand(
ulan@chromium.org750145a2013-03-07 15:14:13 +00005279 NameDictionary::GetProbeOffset(i) << Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005280 } else {
5281 __ mov(index, Operand(hash));
5282 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00005283 __ and_(index, mask, Operand(index, LSR, Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005284
5285 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005286 ASSERT(NameDictionary::kEntrySize == 3);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005287 __ add(index, index, Operand(index, LSL, 1)); // index *= 3.
5288
5289 ASSERT_EQ(kSmiTagSize, 1);
5290 __ add(index, dictionary, Operand(index, LSL, 2));
5291 __ ldr(entry_key, FieldMemOperand(index, kElementsStartOffset));
5292
5293 // Having undefined at this place means the name is not contained.
5294 __ cmp(entry_key, Operand(undefined));
5295 __ b(eq, &not_in_dictionary);
5296
5297 // Stop if found the property.
5298 __ cmp(entry_key, Operand(key));
5299 __ b(eq, &in_dictionary);
5300
5301 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005302 // Check if the entry name is not a unique name.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005303 __ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
5304 __ ldrb(entry_key,
5305 FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005306 __ JumpIfNotUniqueName(entry_key, &maybe_in_dictionary);
lrn@chromium.org1c092762011-05-09 09:42:16 +00005307 }
5308 }
5309
5310 __ bind(&maybe_in_dictionary);
5311 // If we are doing negative lookup then probing failure should be
5312 // treated as a lookup success. For positive lookup probing failure
5313 // should be treated as lookup failure.
5314 if (mode_ == POSITIVE_LOOKUP) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005315 __ mov(result, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00005316 __ Ret();
5317 }
5318
5319 __ bind(&in_dictionary);
5320 __ mov(result, Operand(1));
5321 __ Ret();
5322
5323 __ bind(&not_in_dictionary);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005324 __ mov(result, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00005325 __ Ret();
5326}
5327
5328
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005329struct AheadOfTimeWriteBarrierStubList {
5330 Register object, value, address;
5331 RememberedSetAction action;
5332};
5333
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00005334
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005335#define REG(Name) { kRegister_ ## Name ## _Code }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005336
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005337static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005338 // Used in RegExpExecStub.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00005339 { REG(r6), REG(r4), REG(r3), EMIT_REMEMBERED_SET },
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005340 // Used in CompileArrayPushCall.
5341 // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore.
5342 // Also used in KeyedStoreIC::GenerateGeneric.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005343 { REG(r3), REG(r4), REG(r5), EMIT_REMEMBERED_SET },
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005344 // Used in StoreStubCompiler::CompileStoreField via GenerateStoreField.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005345 { REG(r1), REG(r2), REG(r3), EMIT_REMEMBERED_SET },
5346 { REG(r3), REG(r2), REG(r1), EMIT_REMEMBERED_SET },
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005347 // Used in KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005348 { REG(r2), REG(r1), REG(r3), EMIT_REMEMBERED_SET },
5349 { REG(r3), REG(r1), REG(r2), EMIT_REMEMBERED_SET },
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005350 // KeyedStoreStubCompiler::GenerateStoreFastElement.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005351 { REG(r3), REG(r2), REG(r4), EMIT_REMEMBERED_SET },
5352 { REG(r2), REG(r3), REG(r4), EMIT_REMEMBERED_SET },
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005353 // ElementsTransitionGenerator::GenerateMapChangeElementTransition
5354 // and ElementsTransitionGenerator::GenerateSmiToDouble
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005355 // and ElementsTransitionGenerator::GenerateDoubleToObject
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005356 { REG(r2), REG(r3), REG(r9), EMIT_REMEMBERED_SET },
5357 { REG(r2), REG(r3), REG(r9), OMIT_REMEMBERED_SET },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005358 // ElementsTransitionGenerator::GenerateDoubleToObject
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005359 { REG(r6), REG(r2), REG(r0), EMIT_REMEMBERED_SET },
5360 { REG(r2), REG(r6), REG(r9), EMIT_REMEMBERED_SET },
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005361 // StoreArrayLiteralElementStub::Generate
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005362 { REG(r5), REG(r0), REG(r6), EMIT_REMEMBERED_SET },
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005363 // FastNewClosureStub::Generate
5364 { REG(r2), REG(r4), REG(r1), EMIT_REMEMBERED_SET },
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005365 // StringAddStub::Generate
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00005366 { REG(r3), REG(r1), REG(r4), EMIT_REMEMBERED_SET },
5367 { REG(r3), REG(r0), REG(r4), EMIT_REMEMBERED_SET },
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005368 // Null termination.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005369 { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET}
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005370};
5371
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005372#undef REG
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005373
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005374
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00005375bool RecordWriteStub::IsPregenerated(Isolate* isolate) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005376 for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005377 !entry->object.is(no_reg);
5378 entry++) {
5379 if (object_.is(entry->object) &&
5380 value_.is(entry->value) &&
5381 address_.is(entry->address) &&
5382 remembered_set_action_ == entry->action &&
5383 save_fp_regs_mode_ == kDontSaveFPRegs) {
5384 return true;
5385 }
5386 }
5387 return false;
5388}
5389
5390
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005391void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
5392 Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005393 StoreBufferOverflowStub stub1(kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005394 stub1.GetCode(isolate)->set_is_pregenerated(true);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00005395 // Hydrogen code stubs need stub2 at snapshot time.
5396 StoreBufferOverflowStub stub2(kSaveFPRegs);
5397 stub2.GetCode(isolate)->set_is_pregenerated(true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005398}
5399
5400
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005401void RecordWriteStub::GenerateFixedRegStubsAheadOfTime(Isolate* isolate) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005402 for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005403 !entry->object.is(no_reg);
5404 entry++) {
5405 RecordWriteStub stub(entry->object,
5406 entry->value,
5407 entry->address,
5408 entry->action,
5409 kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005410 stub.GetCode(isolate)->set_is_pregenerated(true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005411 }
5412}
5413
5414
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005415bool CodeStub::CanUseFPRegisters() {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005416 return true; // VFP2 is a base requirement for V8
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005417}
5418
5419
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005420// Takes the input in 3 registers: address_ value_ and object_. A pointer to
5421// the value has just been written into the object, now this stub makes sure
5422// we keep the GC informed. The word in the object where the value has been
5423// written is in the address register.
5424void RecordWriteStub::Generate(MacroAssembler* masm) {
5425 Label skip_to_incremental_noncompacting;
5426 Label skip_to_incremental_compacting;
5427
5428 // The first two instructions are generated with labels so as to get the
5429 // offset fixed up correctly by the bind(Label*) call. We patch it back and
5430 // forth between a compare instructions (a nop in this position) and the
5431 // real branch when we start and stop incremental heap marking.
5432 // See RecordWriteStub::Patch for details.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005433 {
5434 // Block literal pool emission, as the position of these two instructions
5435 // is assumed by the patching code.
5436 Assembler::BlockConstPoolScope block_const_pool(masm);
5437 __ b(&skip_to_incremental_noncompacting);
5438 __ b(&skip_to_incremental_compacting);
5439 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005440
5441 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
5442 __ RememberedSetHelper(object_,
5443 address_,
5444 value_,
5445 save_fp_regs_mode_,
5446 MacroAssembler::kReturnAtEnd);
5447 }
5448 __ Ret();
5449
5450 __ bind(&skip_to_incremental_noncompacting);
5451 GenerateIncremental(masm, INCREMENTAL);
5452
5453 __ bind(&skip_to_incremental_compacting);
5454 GenerateIncremental(masm, INCREMENTAL_COMPACTION);
5455
5456 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
5457 // Will be checked in IncrementalMarking::ActivateGeneratedStub.
5458 ASSERT(Assembler::GetBranchOffset(masm->instr_at(0)) < (1 << 12));
5459 ASSERT(Assembler::GetBranchOffset(masm->instr_at(4)) < (1 << 12));
5460 PatchBranchIntoNop(masm, 0);
5461 PatchBranchIntoNop(masm, Assembler::kInstrSize);
5462}
5463
5464
5465void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
5466 regs_.Save(masm);
5467
5468 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
5469 Label dont_need_remembered_set;
5470
5471 __ ldr(regs_.scratch0(), MemOperand(regs_.address(), 0));
5472 __ JumpIfNotInNewSpace(regs_.scratch0(), // Value.
5473 regs_.scratch0(),
5474 &dont_need_remembered_set);
5475
5476 __ CheckPageFlag(regs_.object(),
5477 regs_.scratch0(),
5478 1 << MemoryChunk::SCAN_ON_SCAVENGE,
5479 ne,
5480 &dont_need_remembered_set);
5481
5482 // First notify the incremental marker if necessary, then update the
5483 // remembered set.
5484 CheckNeedsToInformIncrementalMarker(
5485 masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
5486 InformIncrementalMarker(masm, mode);
5487 regs_.Restore(masm);
5488 __ RememberedSetHelper(object_,
5489 address_,
5490 value_,
5491 save_fp_regs_mode_,
5492 MacroAssembler::kReturnAtEnd);
5493
5494 __ bind(&dont_need_remembered_set);
5495 }
5496
5497 CheckNeedsToInformIncrementalMarker(
5498 masm, kReturnOnNoNeedToInformIncrementalMarker, mode);
5499 InformIncrementalMarker(masm, mode);
5500 regs_.Restore(masm);
5501 __ Ret();
5502}
5503
5504
5505void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) {
5506 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_);
5507 int argument_count = 3;
5508 __ PrepareCallCFunction(argument_count, regs_.scratch0());
5509 Register address =
5510 r0.is(regs_.address()) ? regs_.scratch0() : regs_.address();
5511 ASSERT(!address.is(regs_.object()));
5512 ASSERT(!address.is(r0));
5513 __ Move(address, regs_.address());
5514 __ Move(r0, regs_.object());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005515 __ Move(r1, address);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005516 __ mov(r2, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005517
5518 AllowExternalCallThatCantCauseGC scope(masm);
5519 if (mode == INCREMENTAL_COMPACTION) {
5520 __ CallCFunction(
5521 ExternalReference::incremental_evacuation_record_write_function(
5522 masm->isolate()),
5523 argument_count);
5524 } else {
5525 ASSERT(mode == INCREMENTAL);
5526 __ CallCFunction(
5527 ExternalReference::incremental_marking_record_write_function(
5528 masm->isolate()),
5529 argument_count);
5530 }
5531 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_);
5532}
5533
5534
5535void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
5536 MacroAssembler* masm,
5537 OnNoNeedToInformIncrementalMarker on_no_need,
5538 Mode mode) {
5539 Label on_black;
5540 Label need_incremental;
5541 Label need_incremental_pop_scratch;
5542
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005543 __ and_(regs_.scratch0(), regs_.object(), Operand(~Page::kPageAlignmentMask));
5544 __ ldr(regs_.scratch1(),
5545 MemOperand(regs_.scratch0(),
5546 MemoryChunk::kWriteBarrierCounterOffset));
5547 __ sub(regs_.scratch1(), regs_.scratch1(), Operand(1), SetCC);
5548 __ str(regs_.scratch1(),
5549 MemOperand(regs_.scratch0(),
5550 MemoryChunk::kWriteBarrierCounterOffset));
5551 __ b(mi, &need_incremental);
5552
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005553 // Let's look at the color of the object: If it is not black we don't have
5554 // to inform the incremental marker.
5555 __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black);
5556
5557 regs_.Restore(masm);
5558 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
5559 __ RememberedSetHelper(object_,
5560 address_,
5561 value_,
5562 save_fp_regs_mode_,
5563 MacroAssembler::kReturnAtEnd);
5564 } else {
5565 __ Ret();
5566 }
5567
5568 __ bind(&on_black);
5569
5570 // Get the value from the slot.
5571 __ ldr(regs_.scratch0(), MemOperand(regs_.address(), 0));
5572
5573 if (mode == INCREMENTAL_COMPACTION) {
5574 Label ensure_not_white;
5575
5576 __ CheckPageFlag(regs_.scratch0(), // Contains value.
5577 regs_.scratch1(), // Scratch.
5578 MemoryChunk::kEvacuationCandidateMask,
5579 eq,
5580 &ensure_not_white);
5581
5582 __ CheckPageFlag(regs_.object(),
5583 regs_.scratch1(), // Scratch.
5584 MemoryChunk::kSkipEvacuationSlotsRecordingMask,
5585 eq,
5586 &need_incremental);
5587
5588 __ bind(&ensure_not_white);
5589 }
5590
5591 // We need extra registers for this, so we push the object and the address
5592 // register temporarily.
5593 __ Push(regs_.object(), regs_.address());
5594 __ EnsureNotWhite(regs_.scratch0(), // The value.
5595 regs_.scratch1(), // Scratch.
5596 regs_.object(), // Scratch.
5597 regs_.address(), // Scratch.
5598 &need_incremental_pop_scratch);
5599 __ Pop(regs_.object(), regs_.address());
5600
5601 regs_.Restore(masm);
5602 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
5603 __ RememberedSetHelper(object_,
5604 address_,
5605 value_,
5606 save_fp_regs_mode_,
5607 MacroAssembler::kReturnAtEnd);
5608 } else {
5609 __ Ret();
5610 }
5611
5612 __ bind(&need_incremental_pop_scratch);
5613 __ Pop(regs_.object(), regs_.address());
5614
5615 __ bind(&need_incremental);
5616
5617 // Fall through when we need to inform the incremental marker.
5618}
5619
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005620
5621void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
5622 // ----------- S t a t e -------------
5623 // -- r0 : element value to store
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005624 // -- r3 : element index as smi
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005625 // -- sp[0] : array literal index in function as smi
5626 // -- sp[4] : array literal
5627 // clobbers r1, r2, r4
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005628 // -----------------------------------
5629
5630 Label element_done;
5631 Label double_elements;
5632 Label smi_element;
5633 Label slow_elements;
5634 Label fast_elements;
5635
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005636 // Get array literal index, array literal and its map.
5637 __ ldr(r4, MemOperand(sp, 0 * kPointerSize));
5638 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
5639 __ ldr(r2, FieldMemOperand(r1, JSObject::kMapOffset));
5640
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005641 __ CheckFastElements(r2, r5, &double_elements);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005642 // FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005643 __ JumpIfSmi(r0, &smi_element);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005644 __ CheckFastSmiElements(r2, r5, &fast_elements);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005645
5646 // Store into the array literal requires a elements transition. Call into
5647 // the runtime.
5648 __ bind(&slow_elements);
5649 // call.
5650 __ Push(r1, r3, r0);
5651 __ ldr(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
5652 __ ldr(r5, FieldMemOperand(r5, JSFunction::kLiteralsOffset));
5653 __ Push(r5, r4);
5654 __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
5655
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005656 // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005657 __ bind(&fast_elements);
5658 __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00005659 __ add(r6, r5, Operand::PointerOffsetFromSmiKey(r3));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005660 __ add(r6, r6, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
5661 __ str(r0, MemOperand(r6, 0));
5662 // Update the write barrier for the array store.
5663 __ RecordWrite(r5, r6, r0, kLRHasNotBeenSaved, kDontSaveFPRegs,
5664 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
5665 __ Ret();
5666
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005667 // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
5668 // and value is Smi.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005669 __ bind(&smi_element);
5670 __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00005671 __ add(r6, r5, Operand::PointerOffsetFromSmiKey(r3));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005672 __ str(r0, FieldMemOperand(r6, FixedArray::kHeaderSize));
5673 __ Ret();
5674
5675 // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
5676 __ bind(&double_elements);
5677 __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00005678 __ StoreNumberToDoubleElements(r0, r3, r5, r6, d0, &slow_elements);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00005679 __ Ret();
5680}
5681
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005682
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00005683void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005684 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005685 __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00005686 int parameter_count_offset =
5687 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
5688 __ ldr(r1, MemOperand(fp, parameter_count_offset));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005689 if (function_mode_ == JS_FUNCTION_STUB_MODE) {
5690 __ add(r1, r1, Operand(1));
5691 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00005692 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00005693 __ mov(r1, Operand(r1, LSL, kPointerSizeLog2));
5694 __ add(sp, sp, r1);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00005695 __ Ret();
5696}
5697
5698
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005699void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005700 if (masm->isolate()->function_entry_hook() != NULL) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005701 PredictableCodeSizeScope predictable(masm, 4 * Assembler::kInstrSize);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005702 AllowStubCallsScope allow_stub_calls(masm, true);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005703 ProfileEntryHookStub stub;
5704 __ push(lr);
5705 __ CallStub(&stub);
5706 __ pop(lr);
5707 }
5708}
5709
5710
5711void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
5712 // The entry hook is a "push lr" instruction, followed by a call.
5713 const int32_t kReturnAddressDistanceFromFunctionStart =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005714 3 * Assembler::kInstrSize;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005715
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005716 // This should contain all kCallerSaved registers.
5717 const RegList kSavedRegs =
5718 1 << 0 | // r0
5719 1 << 1 | // r1
5720 1 << 2 | // r2
5721 1 << 3 | // r3
5722 1 << 5 | // r5
5723 1 << 9; // r9
5724 // We also save lr, so the count here is one higher than the mask indicates.
5725 const int32_t kNumSavedRegs = 7;
5726
5727 ASSERT((kCallerSaved & kSavedRegs) == kCallerSaved);
5728
5729 // Save all caller-save registers as this may be called from anywhere.
5730 __ stm(db_w, sp, kSavedRegs | lr.bit());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005731
5732 // Compute the function's address for the first argument.
5733 __ sub(r0, lr, Operand(kReturnAddressDistanceFromFunctionStart));
5734
5735 // The caller's return address is above the saved temporaries.
5736 // Grab that for the second argument to the hook.
5737 __ add(r1, sp, Operand(kNumSavedRegs * kPointerSize));
5738
5739 // Align the stack if necessary.
5740 int frame_alignment = masm->ActivationFrameAlignment();
5741 if (frame_alignment > kPointerSize) {
5742 __ mov(r5, sp);
5743 ASSERT(IsPowerOf2(frame_alignment));
5744 __ and_(sp, sp, Operand(-frame_alignment));
5745 }
5746
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00005747#if V8_HOST_ARCH_ARM
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005748 int32_t entry_hook =
5749 reinterpret_cast<int32_t>(masm->isolate()->function_entry_hook());
5750 __ mov(ip, Operand(entry_hook));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005751#else
5752 // Under the simulator we need to indirect the entry hook through a
5753 // trampoline function at a known address.
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00005754 // It additionally takes an isolate as a third parameter
5755 __ mov(r2, Operand(ExternalReference::isolate_address(masm->isolate())));
5756
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005757 ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005758 __ mov(ip, Operand(ExternalReference(&dispatcher,
5759 ExternalReference::BUILTIN_CALL,
5760 masm->isolate())));
5761#endif
5762 __ Call(ip);
5763
5764 // Restore the stack pointer if needed.
5765 if (frame_alignment > kPointerSize) {
5766 __ mov(sp, r5);
5767 }
5768
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005769 // Also pop pc to get Ret(0).
5770 __ ldm(ia_w, sp, kSavedRegs | pc.bit());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005771}
5772
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005773
5774template<class T>
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005775static void CreateArrayDispatch(MacroAssembler* masm,
5776 AllocationSiteOverrideMode mode) {
5777 if (mode == DISABLE_ALLOCATION_SITES) {
5778 T stub(GetInitialFastElementsKind(),
5779 CONTEXT_CHECK_REQUIRED,
5780 mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005781 __ TailCallStub(&stub);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005782 } else if (mode == DONT_OVERRIDE) {
5783 int last_index = GetSequenceIndexFromFastElementsKind(
5784 TERMINAL_FAST_ELEMENTS_KIND);
5785 for (int i = 0; i <= last_index; ++i) {
5786 Label next;
5787 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
5788 __ cmp(r3, Operand(kind));
5789 __ b(ne, &next);
5790 T stub(kind);
5791 __ TailCallStub(&stub);
5792 __ bind(&next);
5793 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005794
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005795 // If we reached this point there is a problem.
5796 __ Abort(kUnexpectedElementsKindInArrayConstructor);
5797 } else {
5798 UNREACHABLE();
5799 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005800}
5801
5802
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005803static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
5804 AllocationSiteOverrideMode mode) {
5805 // r2 - type info cell (if mode != DISABLE_ALLOCATION_SITES)
5806 // r3 - kind (if mode != DISABLE_ALLOCATION_SITES)
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005807 // r0 - number of arguments
5808 // r1 - constructor?
5809 // sp[0] - last argument
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005810 Label normal_sequence;
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005811 if (mode == DONT_OVERRIDE) {
5812 ASSERT(FAST_SMI_ELEMENTS == 0);
5813 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
5814 ASSERT(FAST_ELEMENTS == 2);
5815 ASSERT(FAST_HOLEY_ELEMENTS == 3);
5816 ASSERT(FAST_DOUBLE_ELEMENTS == 4);
5817 ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
5818
5819 // is the low bit set? If so, we are holey and that is good.
5820 __ tst(r3, Operand(1));
5821 __ b(ne, &normal_sequence);
5822 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005823
5824 // look at the first argument
5825 __ ldr(r5, MemOperand(sp, 0));
5826 __ cmp(r5, Operand::Zero());
5827 __ b(eq, &normal_sequence);
5828
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005829 if (mode == DISABLE_ALLOCATION_SITES) {
5830 ElementsKind initial = GetInitialFastElementsKind();
5831 ElementsKind holey_initial = GetHoleyElementsKind(initial);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005832
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005833 ArraySingleArgumentConstructorStub stub_holey(holey_initial,
5834 CONTEXT_CHECK_REQUIRED,
5835 DISABLE_ALLOCATION_SITES);
5836 __ TailCallStub(&stub_holey);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005837
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005838 __ bind(&normal_sequence);
5839 ArraySingleArgumentConstructorStub stub(initial,
5840 CONTEXT_CHECK_REQUIRED,
5841 DISABLE_ALLOCATION_SITES);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005842 __ TailCallStub(&stub);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005843 } else if (mode == DONT_OVERRIDE) {
5844 // We are going to create a holey array, but our kind is non-holey.
5845 // Fix kind and retry (only if we have an allocation site in the cell).
5846 __ add(r3, r3, Operand(1));
5847 __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005848
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005849 if (FLAG_debug_code) {
5850 __ ldr(r5, FieldMemOperand(r5, 0));
5851 __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
5852 __ Assert(eq, kExpectedAllocationSiteInCell);
5853 __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
5854 }
5855
5856 // Save the resulting elements kind in type info
5857 __ SmiTag(r3);
5858 __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
5859 __ str(r3, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset));
5860 __ SmiUntag(r3);
5861
5862 __ bind(&normal_sequence);
5863 int last_index = GetSequenceIndexFromFastElementsKind(
5864 TERMINAL_FAST_ELEMENTS_KIND);
5865 for (int i = 0; i <= last_index; ++i) {
5866 Label next;
5867 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
5868 __ cmp(r3, Operand(kind));
5869 __ b(ne, &next);
5870 ArraySingleArgumentConstructorStub stub(kind);
5871 __ TailCallStub(&stub);
5872 __ bind(&next);
5873 }
5874
5875 // If we reached this point there is a problem.
5876 __ Abort(kUnexpectedElementsKindInArrayConstructor);
5877 } else {
5878 UNREACHABLE();
5879 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005880}
5881
5882
5883template<class T>
5884static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005885 ElementsKind initial_kind = GetInitialFastElementsKind();
5886 ElementsKind initial_holey_kind = GetHoleyElementsKind(initial_kind);
5887
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005888 int to_index = GetSequenceIndexFromFastElementsKind(
5889 TERMINAL_FAST_ELEMENTS_KIND);
5890 for (int i = 0; i <= to_index; ++i) {
5891 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
5892 T stub(kind);
5893 stub.GetCode(isolate)->set_is_pregenerated(true);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005894 if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE ||
5895 (!FLAG_track_allocation_sites &&
5896 (kind == initial_kind || kind == initial_holey_kind))) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005897 T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005898 stub1.GetCode(isolate)->set_is_pregenerated(true);
5899 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005900 }
5901}
5902
5903
5904void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) {
5905 ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
5906 isolate);
5907 ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
5908 isolate);
5909 ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
5910 isolate);
5911}
5912
5913
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005914void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(
5915 Isolate* isolate) {
5916 ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS };
5917 for (int i = 0; i < 2; i++) {
5918 // For internal arrays we only need a few things
5919 InternalArrayNoArgumentConstructorStub stubh1(kinds[i]);
5920 stubh1.GetCode(isolate)->set_is_pregenerated(true);
5921 InternalArraySingleArgumentConstructorStub stubh2(kinds[i]);
5922 stubh2.GetCode(isolate)->set_is_pregenerated(true);
5923 InternalArrayNArgumentsConstructorStub stubh3(kinds[i]);
5924 stubh3.GetCode(isolate)->set_is_pregenerated(true);
5925 }
5926}
5927
5928
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005929void ArrayConstructorStub::GenerateDispatchToArrayStub(
5930 MacroAssembler* masm,
5931 AllocationSiteOverrideMode mode) {
5932 if (argument_count_ == ANY) {
5933 Label not_zero_case, not_one_case;
5934 __ tst(r0, r0);
5935 __ b(ne, &not_zero_case);
5936 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
5937
5938 __ bind(&not_zero_case);
5939 __ cmp(r0, Operand(1));
5940 __ b(gt, &not_one_case);
5941 CreateArrayDispatchOneArgument(masm, mode);
5942
5943 __ bind(&not_one_case);
5944 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
5945 } else if (argument_count_ == NONE) {
5946 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
5947 } else if (argument_count_ == ONE) {
5948 CreateArrayDispatchOneArgument(masm, mode);
5949 } else if (argument_count_ == MORE_THAN_ONE) {
5950 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
5951 } else {
5952 UNREACHABLE();
5953 }
5954}
5955
5956
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005957void ArrayConstructorStub::Generate(MacroAssembler* masm) {
5958 // ----------- S t a t e -------------
5959 // -- r0 : argc (only if argument_count_ == ANY)
5960 // -- r1 : constructor
5961 // -- r2 : type info cell
5962 // -- sp[0] : return address
5963 // -- sp[4] : last argument
5964 // -----------------------------------
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005965 if (FLAG_debug_code) {
5966 // The array construct code is only set for the global and natives
5967 // builtin Array functions which always have maps.
5968
5969 // Initial map for the builtin Array function should be a map.
5970 __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
5971 // Will both indicate a NULL and a Smi.
5972 __ tst(r3, Operand(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00005973 __ Assert(ne, kUnexpectedInitialMapForArrayFunction);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005974 __ CompareObjectType(r3, r3, r4, MAP_TYPE);
danno@chromium.org59400602013-08-13 17:09:37 +00005975 __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005976
danno@chromium.org41728482013-06-12 22:31:22 +00005977 // We should either have undefined in ebx or a valid cell
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005978 Label okay_here;
danno@chromium.org41728482013-06-12 22:31:22 +00005979 Handle<Map> cell_map = masm->isolate()->factory()->cell_map();
danno@chromium.orgbee51992013-07-10 14:57:15 +00005980 __ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005981 __ b(eq, &okay_here);
5982 __ ldr(r3, FieldMemOperand(r2, 0));
danno@chromium.org41728482013-06-12 22:31:22 +00005983 __ cmp(r3, Operand(cell_map));
danno@chromium.org59400602013-08-13 17:09:37 +00005984 __ Assert(eq, kExpectedPropertyCellInRegisterEbx);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005985 __ bind(&okay_here);
5986 }
5987
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005988 Label no_info;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005989 // Get the elements kind and case on that.
danno@chromium.orgbee51992013-07-10 14:57:15 +00005990 __ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005991 __ b(eq, &no_info);
5992 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset));
danno@chromium.orgbee51992013-07-10 14:57:15 +00005993
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005994 // If the type cell is undefined, or contains anything other than an
5995 // AllocationSite, call an array constructor that doesn't use AllocationSites.
danno@chromium.orgbee51992013-07-10 14:57:15 +00005996 __ ldr(r4, FieldMemOperand(r3, 0));
5997 __ CompareRoot(r4, Heap::kAllocationSiteMapRootIndex);
5998 __ b(ne, &no_info);
5999
6000 __ ldr(r3, FieldMemOperand(r3, AllocationSite::kTransitionInfoOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006001 __ SmiUntag(r3);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00006002 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
6003
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006004 __ bind(&no_info);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00006005 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00006006}
6007
6008
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00006009void InternalArrayConstructorStub::GenerateCase(
6010 MacroAssembler* masm, ElementsKind kind) {
6011 Label not_zero_case, not_one_case;
6012 Label normal_sequence;
6013
6014 __ tst(r0, r0);
6015 __ b(ne, &not_zero_case);
6016 InternalArrayNoArgumentConstructorStub stub0(kind);
6017 __ TailCallStub(&stub0);
6018
6019 __ bind(&not_zero_case);
6020 __ cmp(r0, Operand(1));
6021 __ b(gt, &not_one_case);
6022
6023 if (IsFastPackedElementsKind(kind)) {
6024 // We might need to create a holey array
6025 // look at the first argument
6026 __ ldr(r3, MemOperand(sp, 0));
6027 __ cmp(r3, Operand::Zero());
6028 __ b(eq, &normal_sequence);
6029
6030 InternalArraySingleArgumentConstructorStub
6031 stub1_holey(GetHoleyElementsKind(kind));
6032 __ TailCallStub(&stub1_holey);
6033 }
6034
6035 __ bind(&normal_sequence);
6036 InternalArraySingleArgumentConstructorStub stub1(kind);
6037 __ TailCallStub(&stub1);
6038
6039 __ bind(&not_one_case);
6040 InternalArrayNArgumentsConstructorStub stubN(kind);
6041 __ TailCallStub(&stubN);
6042}
6043
6044
6045void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
6046 // ----------- S t a t e -------------
6047 // -- r0 : argc
6048 // -- r1 : constructor
6049 // -- sp[0] : return address
6050 // -- sp[4] : last argument
6051 // -----------------------------------
6052
6053 if (FLAG_debug_code) {
6054 // The array construct code is only set for the global and natives
6055 // builtin Array functions which always have maps.
6056
6057 // Initial map for the builtin Array function should be a map.
6058 __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
6059 // Will both indicate a NULL and a Smi.
6060 __ tst(r3, Operand(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00006061 __ Assert(ne, kUnexpectedInitialMapForArrayFunction);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00006062 __ CompareObjectType(r3, r3, r4, MAP_TYPE);
danno@chromium.org59400602013-08-13 17:09:37 +00006063 __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00006064 }
6065
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006066 // Figure out the right elements kind
6067 __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
6068 // Load the map's "bit field 2" into |result|. We only need the first byte,
6069 // but the following bit field extraction takes care of that anyway.
6070 __ ldr(r3, FieldMemOperand(r3, Map::kBitField2Offset));
6071 // Retrieve elements_kind from bit field 2.
6072 __ Ubfx(r3, r3, Map::kElementsKindShift, Map::kElementsKindBitCount);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00006073
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006074 if (FLAG_debug_code) {
6075 Label done;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00006076 __ cmp(r3, Operand(FAST_ELEMENTS));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006077 __ b(eq, &done);
6078 __ cmp(r3, Operand(FAST_HOLEY_ELEMENTS));
6079 __ Assert(eq,
danno@chromium.org59400602013-08-13 17:09:37 +00006080 kInvalidElementsKindForInternalArrayOrInternalPackedArray);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006081 __ bind(&done);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00006082 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006083
6084 Label fast_elements_case;
6085 __ cmp(r3, Operand(FAST_ELEMENTS));
6086 __ b(eq, &fast_elements_case);
6087 GenerateCase(masm, FAST_HOLEY_ELEMENTS);
6088
6089 __ bind(&fast_elements_case);
6090 GenerateCase(masm, FAST_ELEMENTS);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00006091}
6092
6093
ricow@chromium.org65fae842010-08-25 15:26:24 +00006094#undef __
6095
6096} } // namespace v8::internal
6097
6098#endif // V8_TARGET_ARCH_ARM