blob: 86da76ac3ca053dc14c5152e2e65eb8082e49767 [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
30#if defined(V8_TARGET_ARCH_ARM)
31
32#include "bootstrapper.h"
danno@chromium.orgf005df62013-04-30 16:36:45 +000033#include "builtins-decls.h"
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000034#include "code-stubs.h"
ricow@chromium.org65fae842010-08-25 15:26:24 +000035#include "regexp-macro-assembler.h"
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +000036#include "stub-cache.h"
ricow@chromium.org65fae842010-08-25 15:26:24 +000037
38namespace v8 {
39namespace internal {
40
41
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000042void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
43 Isolate* isolate,
44 CodeStubInterfaceDescriptor* descriptor) {
45 static Register registers[] = { r3, r2, r1 };
46 descriptor->register_param_count_ = 3;
47 descriptor->register_params_ = registers;
48 descriptor->stack_parameter_count_ = NULL;
49 descriptor->deoptimization_handler_ =
50 Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
51}
52
53
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000054void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
55 Isolate* isolate,
56 CodeStubInterfaceDescriptor* descriptor) {
57 static Register registers[] = { r3, r2, r1, r0 };
58 descriptor->register_param_count_ = 4;
59 descriptor->register_params_ = registers;
60 descriptor->stack_parameter_count_ = NULL;
61 descriptor->deoptimization_handler_ =
62 Runtime::FunctionForId(Runtime::kCreateObjectLiteralShallow)->entry;
63}
64
65
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000066void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
67 Isolate* isolate,
68 CodeStubInterfaceDescriptor* descriptor) {
69 static Register registers[] = { r1, r0 };
70 descriptor->register_param_count_ = 2;
71 descriptor->register_params_ = registers;
72 descriptor->deoptimization_handler_ =
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000073 FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000074}
75
76
ulan@chromium.org57ff8812013-05-10 08:16:55 +000077void LoadFieldStub::InitializeInterfaceDescriptor(
78 Isolate* isolate,
79 CodeStubInterfaceDescriptor* descriptor) {
80 static Register registers[] = { r0 };
81 descriptor->register_param_count_ = 1;
82 descriptor->register_params_ = registers;
83 descriptor->stack_parameter_count_ = NULL;
84 descriptor->deoptimization_handler_ = NULL;
85}
86
87
88void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
89 Isolate* isolate,
90 CodeStubInterfaceDescriptor* descriptor) {
91 static Register registers[] = { r1 };
92 descriptor->register_param_count_ = 1;
93 descriptor->register_params_ = registers;
94 descriptor->stack_parameter_count_ = NULL;
95 descriptor->deoptimization_handler_ = NULL;
96}
97
98
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +000099void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
100 Isolate* isolate,
101 CodeStubInterfaceDescriptor* descriptor) {
102 static Register registers[] = { r2, r1, r0 };
103 descriptor->register_param_count_ = 3;
104 descriptor->register_params_ = registers;
105 descriptor->deoptimization_handler_ =
106 FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure);
107}
108
109
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000110void TransitionElementsKindStub::InitializeInterfaceDescriptor(
111 Isolate* isolate,
112 CodeStubInterfaceDescriptor* descriptor) {
113 static Register registers[] = { r0, r1 };
114 descriptor->register_param_count_ = 2;
115 descriptor->register_params_ = registers;
116 Address entry =
117 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry;
118 descriptor->deoptimization_handler_ = FUNCTION_ADDR(entry);
119}
120
121
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000122void CompareNilICStub::InitializeInterfaceDescriptor(
123 Isolate* isolate,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000124 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000125 static Register registers[] = { r0 };
126 descriptor->register_param_count_ = 1;
127 descriptor->register_params_ = registers;
128 descriptor->deoptimization_handler_ =
129 FUNCTION_ADDR(CompareNilIC_Miss);
130 descriptor->miss_handler_ =
131 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate);
132}
133
134
135static void InitializeArrayConstructorDescriptor(
136 Isolate* isolate,
137 CodeStubInterfaceDescriptor* descriptor,
138 int constant_stack_parameter_count) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000139 // register state
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000140 // r0 -- number of arguments
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000141 // r1 -- function
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000142 // r2 -- type info cell with elements kind
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000143 static Register registers[] = { r1, r2 };
144 descriptor->register_param_count_ = 2;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000145 if (constant_stack_parameter_count != 0) {
146 // stack param count needs (constructor pointer, and single argument)
147 descriptor->stack_parameter_count_ = &r0;
148 }
149 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000150 descriptor->register_params_ = registers;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000151 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000152 descriptor->deoptimization_handler_ =
153 FUNCTION_ADDR(ArrayConstructor_StubFailure);
154}
155
156
157void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
158 Isolate* isolate,
159 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000160 InitializeArrayConstructorDescriptor(isolate, descriptor, 0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000161}
162
163
164void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
165 Isolate* isolate,
166 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000167 InitializeArrayConstructorDescriptor(isolate, descriptor, 1);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000168}
169
170
171void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
172 Isolate* isolate,
173 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000174 InitializeArrayConstructorDescriptor(isolate, descriptor, -1);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000175}
176
177
ricow@chromium.org65fae842010-08-25 15:26:24 +0000178#define __ ACCESS_MASM(masm)
179
180static void EmitIdenticalObjectComparison(MacroAssembler* masm,
181 Label* slow,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000182 Condition cond);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000183static void EmitSmiNonsmiComparison(MacroAssembler* masm,
184 Register lhs,
185 Register rhs,
186 Label* lhs_not_nan,
187 Label* slow,
188 bool strict);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000189static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
190 Register lhs,
191 Register rhs);
192
193
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000194// Check if the operand is a heap number.
195static void EmitCheckForHeapNumber(MacroAssembler* masm, Register operand,
196 Register scratch1, Register scratch2,
197 Label* not_a_heap_number) {
198 __ ldr(scratch1, FieldMemOperand(operand, HeapObject::kMapOffset));
199 __ LoadRoot(scratch2, Heap::kHeapNumberMapRootIndex);
200 __ cmp(scratch1, scratch2);
201 __ b(ne, not_a_heap_number);
202}
203
204
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000205void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) {
206 // Update the static counter each time a new code stub is generated.
207 Isolate* isolate = masm->isolate();
208 isolate->counters()->code_stubs()->Increment();
209
210 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate);
211 int param_count = descriptor->register_param_count_;
212 {
213 // Call the runtime system in a fresh internal frame.
214 FrameScope scope(masm, StackFrame::INTERNAL);
215 ASSERT(descriptor->register_param_count_ == 0 ||
216 r0.is(descriptor->register_params_[param_count - 1]));
217 // Push arguments
218 for (int i = 0; i < param_count; ++i) {
219 __ push(descriptor->register_params_[i]);
220 }
221 ExternalReference miss = descriptor->miss_handler_;
222 __ CallExternalReference(miss, descriptor->register_param_count_);
223 }
224
225 __ Ret();
226}
227
228
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000229void ToNumberStub::Generate(MacroAssembler* masm) {
230 // The ToNumber stub takes one argument in eax.
231 Label check_heap_number, call_builtin;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000232 __ JumpIfNotSmi(r0, &check_heap_number);
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000233 __ Ret();
234
235 __ bind(&check_heap_number);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000236 EmitCheckForHeapNumber(masm, r0, r1, ip, &call_builtin);
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000237 __ Ret();
238
239 __ bind(&call_builtin);
240 __ push(r0);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000241 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000242}
243
244
ricow@chromium.org65fae842010-08-25 15:26:24 +0000245void FastNewClosureStub::Generate(MacroAssembler* masm) {
246 // Create a new closure from the given function info in new
247 // space. Set the context to the current context in cp.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000248 Counters* counters = masm->isolate()->counters();
249
ricow@chromium.org65fae842010-08-25 15:26:24 +0000250 Label gc;
251
252 // Pop the function info from the stack.
253 __ pop(r3);
254
255 // Attempt to allocate new JSFunction in new space.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000256 __ Allocate(JSFunction::kSize, r0, r1, r2, &gc, TAG_OBJECT);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000257
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000258 __ IncrementCounter(counters->fast_new_closure_total(), 1, r6, r7);
259
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000260 int map_index = Context::FunctionMapIndex(language_mode_, is_generator_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000261
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000262 // Compute the function map in the current native context and set that
ricow@chromium.org65fae842010-08-25 15:26:24 +0000263 // as the map of the allocated object.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000264 __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
265 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kNativeContextOffset));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000266 __ ldr(r5, MemOperand(r2, Context::SlotOffset(map_index)));
267 __ str(r5, FieldMemOperand(r0, HeapObject::kMapOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000268
269 // Initialize the rest of the function. We don't have to update the
270 // write barrier because the allocated object is in new space.
271 __ LoadRoot(r1, Heap::kEmptyFixedArrayRootIndex);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000272 __ LoadRoot(r5, Heap::kTheHoleValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000273 __ str(r1, FieldMemOperand(r0, JSObject::kPropertiesOffset));
274 __ str(r1, FieldMemOperand(r0, JSObject::kElementsOffset));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000275 __ str(r5, FieldMemOperand(r0, JSFunction::kPrototypeOrInitialMapOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000276 __ str(r3, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
277 __ str(cp, FieldMemOperand(r0, JSFunction::kContextOffset));
278 __ str(r1, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000279
ricow@chromium.org65fae842010-08-25 15:26:24 +0000280 // Initialize the code pointer in the function to be the one
281 // found in the shared function info object.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000282 // But first check if there is an optimized version for our context.
283 Label check_optimized;
284 Label install_unoptimized;
285 if (FLAG_cache_optimized_code) {
286 __ ldr(r1,
287 FieldMemOperand(r3, SharedFunctionInfo::kOptimizedCodeMapOffset));
288 __ tst(r1, r1);
289 __ b(ne, &check_optimized);
290 }
291 __ bind(&install_unoptimized);
292 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
293 __ str(r4, FieldMemOperand(r0, JSFunction::kNextFunctionLinkOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000294 __ ldr(r3, FieldMemOperand(r3, SharedFunctionInfo::kCodeOffset));
295 __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
296 __ str(r3, FieldMemOperand(r0, JSFunction::kCodeEntryOffset));
297
298 // Return result. The argument function info has been popped already.
299 __ Ret();
300
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000301 __ bind(&check_optimized);
302
303 __ IncrementCounter(counters->fast_new_closure_try_optimized(), 1, r6, r7);
304
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000305 // r2 holds native context, r1 points to fixed array of 3-element entries
306 // (native context, optimized code, literals).
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000307 // The optimized code map must never be empty, so check the first elements.
308 Label install_optimized;
309 // Speculatively move code object into r4.
310 __ ldr(r4, FieldMemOperand(r1, FixedArray::kHeaderSize + kPointerSize));
311 __ ldr(r5, FieldMemOperand(r1, FixedArray::kHeaderSize));
312 __ cmp(r2, r5);
313 __ b(eq, &install_optimized);
314
315 // Iterate through the rest of map backwards. r4 holds an index as a Smi.
316 Label loop;
317 __ ldr(r4, FieldMemOperand(r1, FixedArray::kLengthOffset));
318 __ bind(&loop);
319 // Do not double check first entry.
320
321 __ cmp(r4, Operand(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
322 __ b(eq, &install_unoptimized);
323 __ sub(r4, r4, Operand(
324 Smi::FromInt(SharedFunctionInfo::kEntryLength))); // Skip an entry.
325 __ add(r5, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
326 __ add(r5, r5, Operand(r4, LSL, kPointerSizeLog2 - kSmiTagSize));
327 __ ldr(r5, MemOperand(r5));
328 __ cmp(r2, r5);
329 __ b(ne, &loop);
330 // Hit: fetch the optimized code.
331 __ add(r5, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
332 __ add(r5, r5, Operand(r4, LSL, kPointerSizeLog2 - kSmiTagSize));
333 __ add(r5, r5, Operand(kPointerSize));
334 __ ldr(r4, MemOperand(r5));
335
336 __ bind(&install_optimized);
337 __ IncrementCounter(counters->fast_new_closure_install_optimized(),
338 1, r6, r7);
339
340 // TODO(fschneider): Idea: store proper code pointers in the map and either
341 // unmangle them on marking or do nothing as the whole map is discarded on
342 // major GC anyway.
343 __ add(r4, r4, Operand(Code::kHeaderSize - kHeapObjectTag));
344 __ str(r4, FieldMemOperand(r0, JSFunction::kCodeEntryOffset));
345
346 // Now link a function into a list of optimized functions.
347 __ ldr(r4, ContextOperand(r2, Context::OPTIMIZED_FUNCTIONS_LIST));
348
349 __ str(r4, FieldMemOperand(r0, JSFunction::kNextFunctionLinkOffset));
350 // No need for write barrier as JSFunction (eax) is in the new space.
351
352 __ str(r0, ContextOperand(r2, Context::OPTIMIZED_FUNCTIONS_LIST));
353 // Store JSFunction (eax) into edx before issuing write barrier as
354 // it clobbers all the registers passed.
355 __ mov(r4, r0);
356 __ RecordWriteContextSlot(
357 r2,
358 Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST),
359 r4,
360 r1,
361 kLRHasNotBeenSaved,
362 kDontSaveFPRegs);
363
364 // Return result. The argument function info has been popped already.
365 __ Ret();
366
ricow@chromium.org65fae842010-08-25 15:26:24 +0000367 // Create a new closure through the slower runtime call.
368 __ bind(&gc);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000369 __ LoadRoot(r4, Heap::kFalseValueRootIndex);
370 __ Push(cp, r3, r4);
371 __ TailCallRuntime(Runtime::kNewClosure, 3, 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000372}
373
374
375void FastNewContextStub::Generate(MacroAssembler* masm) {
376 // Try to allocate the context in new space.
377 Label gc;
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000378 int length = slots_ + Context::MIN_CONTEXT_SLOTS;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000379
380 // Attempt to allocate the context in new space.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000381 __ Allocate(FixedArray::SizeFor(length), r0, r1, r2, &gc, TAG_OBJECT);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000382
383 // Load the function from the stack.
384 __ ldr(r3, MemOperand(sp, 0));
385
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000386 // Set up the object header.
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000387 __ LoadRoot(r1, Heap::kFunctionContextMapRootIndex);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000388 __ mov(r2, Operand(Smi::FromInt(length)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000389 __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000390 __ str(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000391
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000392 // Set up the fixed slots, copy the global object from the previous context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000393 __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000394 __ mov(r1, Operand(Smi::FromInt(0)));
395 __ str(r3, MemOperand(r0, Context::SlotOffset(Context::CLOSURE_INDEX)));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000396 __ str(cp, MemOperand(r0, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000397 __ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX)));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000398 __ str(r2, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000399
400 // Initialize the rest of the slots to undefined.
401 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000402 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000403 __ str(r1, MemOperand(r0, Context::SlotOffset(i)));
404 }
405
406 // Remove the on-stack argument and return.
407 __ mov(cp, r0);
408 __ pop();
409 __ Ret();
410
411 // Need to collect. Call into runtime system.
412 __ bind(&gc);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000413 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000414}
415
416
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000417void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
418 // Stack layout on entry:
419 //
420 // [sp]: function.
421 // [sp + kPointerSize]: serialized scope info
422
423 // Try to allocate the context in new space.
424 Label gc;
425 int length = slots_ + Context::MIN_CONTEXT_SLOTS;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000426 __ Allocate(FixedArray::SizeFor(length), r0, r1, r2, &gc, TAG_OBJECT);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000427
428 // Load the function from the stack.
429 __ ldr(r3, MemOperand(sp, 0));
430
431 // Load the serialized scope info from the stack.
432 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
433
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000434 // Set up the object header.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000435 __ LoadRoot(r2, Heap::kBlockContextMapRootIndex);
436 __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
437 __ mov(r2, Operand(Smi::FromInt(length)));
438 __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset));
439
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000440 // If this block context is nested in the native context we get a smi
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000441 // sentinel instead of a function. The block context should get the
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000442 // canonical empty function of the native context as its closure which
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000443 // we still have to look up.
444 Label after_sentinel;
445 __ JumpIfNotSmi(r3, &after_sentinel);
446 if (FLAG_debug_code) {
447 const char* message = "Expected 0 as a Smi sentinel";
448 __ cmp(r3, Operand::Zero());
449 __ Assert(eq, message);
450 }
451 __ ldr(r3, GlobalObjectOperand());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000452 __ ldr(r3, FieldMemOperand(r3, GlobalObject::kNativeContextOffset));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000453 __ ldr(r3, ContextOperand(r3, Context::CLOSURE_INDEX));
454 __ bind(&after_sentinel);
455
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000456 // Set up the fixed slots, copy the global object from the previous context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000457 __ ldr(r2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000458 __ str(r3, ContextOperand(r0, Context::CLOSURE_INDEX));
459 __ str(cp, ContextOperand(r0, Context::PREVIOUS_INDEX));
460 __ str(r1, ContextOperand(r0, Context::EXTENSION_INDEX));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000461 __ str(r2, ContextOperand(r0, Context::GLOBAL_OBJECT_INDEX));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000462
463 // Initialize the rest of the slots to the hole value.
464 __ LoadRoot(r1, Heap::kTheHoleValueRootIndex);
465 for (int i = 0; i < slots_; i++) {
466 __ str(r1, ContextOperand(r0, i + Context::MIN_CONTEXT_SLOTS));
467 }
468
469 // Remove the on-stack argument and return.
470 __ mov(cp, r0);
471 __ add(sp, sp, Operand(2 * kPointerSize));
472 __ Ret();
473
474 // Need to collect. Call into runtime system.
475 __ bind(&gc);
476 __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1);
477}
478
479
ricow@chromium.org65fae842010-08-25 15:26:24 +0000480// Takes a Smi and converts to an IEEE 64 bit floating point value in two
481// registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and
482// 52 fraction bits (20 in the first word, 32 in the second). Zeros is a
483// scratch register. Destroys the source register. No GC occurs during this
484// stub so you don't have to set up the frame.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000485class ConvertToDoubleStub : public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000486 public:
487 ConvertToDoubleStub(Register result_reg_1,
488 Register result_reg_2,
489 Register source_reg,
490 Register scratch_reg)
491 : result1_(result_reg_1),
492 result2_(result_reg_2),
493 source_(source_reg),
494 zeros_(scratch_reg) { }
495
496 private:
497 Register result1_;
498 Register result2_;
499 Register source_;
500 Register zeros_;
501
502 // Minor key encoding in 16 bits.
503 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
504 class OpBits: public BitField<Token::Value, 2, 14> {};
505
506 Major MajorKey() { return ConvertToDouble; }
507 int MinorKey() {
508 // Encode the parameters in a unique 16 bit value.
509 return result1_.code() +
510 (result2_.code() << 4) +
511 (source_.code() << 8) +
512 (zeros_.code() << 12);
513 }
514
515 void Generate(MacroAssembler* masm);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000516};
517
518
519void ConvertToDoubleStub::Generate(MacroAssembler* masm) {
danno@chromium.org160a7b02011-04-18 15:51:38 +0000520 Register exponent = result1_;
521 Register mantissa = result2_;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000522
ricow@chromium.org65fae842010-08-25 15:26:24 +0000523 Label not_special;
524 // Convert from Smi to integer.
525 __ mov(source_, Operand(source_, ASR, kSmiTagSize));
526 // Move sign bit from source to destination. This works because the sign bit
527 // in the exponent word of the double has the same position and polarity as
528 // the 2's complement sign bit in a Smi.
529 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
530 __ and_(exponent, source_, Operand(HeapNumber::kSignMask), SetCC);
531 // Subtract from 0 if source was negative.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000532 __ rsb(source_, source_, Operand::Zero(), LeaveCC, ne);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000533
534 // We have -1, 0 or 1, which we treat specially. Register source_ contains
535 // absolute value: it is either equal to 1 (special case of -1 and 1),
536 // greater than 1 (not a special case) or less than 1 (special case of 0).
537 __ cmp(source_, Operand(1));
538 __ b(gt, &not_special);
539
540 // For 1 or -1 we need to or in the 0 exponent (biased to 1023).
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000541 const uint32_t exponent_word_for_1 =
ricow@chromium.org65fae842010-08-25 15:26:24 +0000542 HeapNumber::kExponentBias << HeapNumber::kExponentShift;
543 __ orr(exponent, exponent, Operand(exponent_word_for_1), LeaveCC, eq);
544 // 1, 0 and -1 all have 0 for the second word.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000545 __ mov(mantissa, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000546 __ Ret();
547
548 __ bind(&not_special);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000549 __ clz(zeros_, source_);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000550 // Compute exponent and or it into the exponent register.
551 // We use mantissa as a scratch register here. Use a fudge factor to
552 // divide the constant 31 + HeapNumber::kExponentBias, 0x41d, into two parts
553 // that fit in the ARM's constant field.
554 int fudge = 0x400;
555 __ rsb(mantissa, zeros_, Operand(31 + HeapNumber::kExponentBias - fudge));
556 __ add(mantissa, mantissa, Operand(fudge));
557 __ orr(exponent,
558 exponent,
559 Operand(mantissa, LSL, HeapNumber::kExponentShift));
560 // Shift up the source chopping the top bit off.
561 __ add(zeros_, zeros_, Operand(1));
562 // This wouldn't work for 1.0 or -1.0 as the shift would be 32 which means 0.
563 __ mov(source_, Operand(source_, LSL, zeros_));
564 // Compute lower part of fraction (last 12 bits).
565 __ mov(mantissa, Operand(source_, LSL, HeapNumber::kMantissaBitsInTopWord));
566 // And the top (top 20 bits).
567 __ orr(exponent,
568 exponent,
569 Operand(source_, LSR, 32 - HeapNumber::kMantissaBitsInTopWord));
570 __ Ret();
571}
572
573
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000574bool WriteInt32ToHeapNumberStub::IsPregenerated() {
575 // These variants are compiled ahead of time. See next method.
576 if (the_int_.is(r1) && the_heap_number_.is(r0) && scratch_.is(r2)) {
577 return true;
578 }
579 if (the_int_.is(r2) && the_heap_number_.is(r0) && scratch_.is(r3)) {
580 return true;
581 }
582 // Other register combinations are generated as and when they are needed,
583 // so it is unsafe to call them from stubs (we can't generate a stub while
584 // we are generating a stub).
585 return false;
586}
587
588
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000589void WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(
590 Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000591 WriteInt32ToHeapNumberStub stub1(r1, r0, r2);
592 WriteInt32ToHeapNumberStub stub2(r2, r0, r3);
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000593 stub1.GetCode(isolate)->set_is_pregenerated(true);
594 stub2.GetCode(isolate)->set_is_pregenerated(true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000595}
596
597
ricow@chromium.org65fae842010-08-25 15:26:24 +0000598// See comment for class.
599void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
600 Label max_negative_int;
601 // the_int_ has the answer which is a signed int32 but not a Smi.
602 // We test for the special value that has a different exponent. This test
603 // has the neat side effect of setting the flags according to the sign.
604 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
605 __ cmp(the_int_, Operand(0x80000000u));
606 __ b(eq, &max_negative_int);
607 // Set up the correct exponent in scratch_. All non-Smi int32s have the same.
608 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased).
609 uint32_t non_smi_exponent =
610 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
611 __ mov(scratch_, Operand(non_smi_exponent));
612 // Set the sign bit in scratch_ if the value was negative.
613 __ orr(scratch_, scratch_, Operand(HeapNumber::kSignMask), LeaveCC, cs);
614 // Subtract from 0 if the value was negative.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000615 __ rsb(the_int_, the_int_, Operand::Zero(), LeaveCC, cs);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000616 // We should be masking the implict first digit of the mantissa away here,
617 // but it just ends up combining harmlessly with the last digit of the
618 // exponent that happens to be 1. The sign bit is 0 so we shift 10 to get
619 // the most significant 1 to hit the last bit of the 12 bit sign and exponent.
620 ASSERT(((1 << HeapNumber::kExponentShift) & non_smi_exponent) != 0);
621 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
622 __ orr(scratch_, scratch_, Operand(the_int_, LSR, shift_distance));
623 __ str(scratch_, FieldMemOperand(the_heap_number_,
624 HeapNumber::kExponentOffset));
625 __ mov(scratch_, Operand(the_int_, LSL, 32 - shift_distance));
626 __ str(scratch_, FieldMemOperand(the_heap_number_,
627 HeapNumber::kMantissaOffset));
628 __ Ret();
629
630 __ bind(&max_negative_int);
631 // The max negative int32 is stored as a positive number in the mantissa of
632 // a double because it uses a sign bit instead of using two's complement.
633 // The actual mantissa bits stored are all 0 because the implicit most
634 // significant 1 bit is not stored.
635 non_smi_exponent += 1 << HeapNumber::kExponentShift;
636 __ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent));
637 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000638 __ mov(ip, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000639 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset));
640 __ Ret();
641}
642
643
644// Handle the case where the lhs and rhs are the same object.
645// Equality is almost reflexive (everything but NaN), so this is a test
646// for "identity and not NaN".
647static void EmitIdenticalObjectComparison(MacroAssembler* masm,
648 Label* slow,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000649 Condition cond) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000650 Label not_identical;
651 Label heap_number, return_equal;
652 __ cmp(r0, r1);
653 __ b(ne, &not_identical);
654
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000655 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(),
656 // so we do the second best thing - test it ourselves.
657 // They are both equal and they are not both Smis so both of them are not
658 // Smis. If it's not a heap number, then return equal.
659 if (cond == lt || cond == gt) {
660 __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE);
661 __ b(ge, slow);
662 } else {
663 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
664 __ b(eq, &heap_number);
665 // Comparing JS objects with <=, >= is complicated.
666 if (cond != eq) {
667 __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000668 __ b(ge, slow);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000669 // Normally here we fall through to return_equal, but undefined is
670 // special: (undefined == undefined) == true, but
671 // (undefined <= undefined) == false! See ECMAScript 11.8.5.
672 if (cond == le || cond == ge) {
673 __ cmp(r4, Operand(ODDBALL_TYPE));
674 __ b(ne, &return_equal);
675 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
676 __ cmp(r0, r2);
677 __ b(ne, &return_equal);
678 if (cond == le) {
679 // undefined <= undefined should fail.
680 __ mov(r0, Operand(GREATER));
681 } else {
682 // undefined >= undefined should fail.
683 __ mov(r0, Operand(LESS));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000684 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000685 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000686 }
687 }
688 }
689
690 __ bind(&return_equal);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000691 if (cond == lt) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000692 __ mov(r0, Operand(GREATER)); // Things aren't less than themselves.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000693 } else if (cond == gt) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000694 __ mov(r0, Operand(LESS)); // Things aren't greater than themselves.
695 } else {
696 __ mov(r0, Operand(EQUAL)); // Things are <=, >=, ==, === themselves.
697 }
698 __ Ret();
699
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000700 // For less and greater we don't have to check for NaN since the result of
701 // x < x is false regardless. For the others here is some code to check
702 // for NaN.
703 if (cond != lt && cond != gt) {
704 __ bind(&heap_number);
705 // It is a heap number, so return non-equal if it's NaN and equal if it's
706 // not NaN.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000707
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000708 // The representation of NaN values has all exponent bits (52..62) set,
709 // and not all mantissa bits (0..51) clear.
710 // Read top bits of double representation (second word of value).
711 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
712 // Test that exponent bits are all set.
713 __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
714 // NaNs have all-one exponents so they sign extend to -1.
715 __ cmp(r3, Operand(-1));
716 __ b(ne, &return_equal);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000717
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000718 // Shift out flag and all exponent bits, retaining only mantissa.
719 __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord));
720 // Or with all low-bits of mantissa.
721 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
722 __ orr(r0, r3, Operand(r2), SetCC);
723 // For equal we already have the right value in r0: Return zero (equal)
724 // if all bits in mantissa are zero (it's an Infinity) and non-zero if
725 // not (it's a NaN). For <= and >= we need to load r0 with the failing
726 // value if it's a NaN.
727 if (cond != eq) {
728 // All-zero means Infinity means equal.
729 __ Ret(eq);
730 if (cond == le) {
731 __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail.
732 } else {
733 __ mov(r0, Operand(LESS)); // NaN >= NaN should fail.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000734 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000735 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000736 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000737 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000738 // No fall through here.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000739
740 __ bind(&not_identical);
741}
742
743
744// See comment at call site.
745static void EmitSmiNonsmiComparison(MacroAssembler* masm,
746 Register lhs,
747 Register rhs,
748 Label* lhs_not_nan,
749 Label* slow,
750 bool strict) {
751 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
752 (lhs.is(r1) && rhs.is(r0)));
753
754 Label rhs_is_smi;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000755 __ JumpIfSmi(rhs, &rhs_is_smi);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000756
757 // Lhs is a Smi. Check whether the rhs is a heap number.
758 __ CompareObjectType(rhs, r4, r4, HEAP_NUMBER_TYPE);
759 if (strict) {
760 // If rhs is not a number and lhs is a Smi then strict equality cannot
761 // succeed. Return non-equal
762 // If rhs is r0 then there is already a non zero value in it.
763 if (!rhs.is(r0)) {
764 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne);
765 }
766 __ Ret(ne);
767 } else {
768 // Smi compared non-strictly with a non-Smi non-heap-number. Call
769 // the runtime.
770 __ b(ne, slow);
771 }
772
773 // Lhs is a smi, rhs is a number.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000774 // Convert lhs to a double in d7.
775 __ SmiToDoubleVFPRegister(lhs, d7, r7, s15);
776 // Load the double from rhs, tagged HeapNumber r0, to d6.
777 __ sub(r7, rhs, Operand(kHeapObjectTag));
778 __ vldr(d6, r7, HeapNumber::kValueOffset);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000779
780 // We now have both loaded as doubles but we can skip the lhs nan check
781 // since it's a smi.
782 __ jmp(lhs_not_nan);
783
784 __ bind(&rhs_is_smi);
785 // Rhs is a smi. Check whether the non-smi lhs is a heap number.
786 __ CompareObjectType(lhs, r4, r4, HEAP_NUMBER_TYPE);
787 if (strict) {
788 // If lhs is not a number and rhs is a smi then strict equality cannot
789 // succeed. Return non-equal.
790 // If lhs is r0 then there is already a non zero value in it.
791 if (!lhs.is(r0)) {
792 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne);
793 }
794 __ Ret(ne);
795 } else {
796 // Smi compared non-strictly with a non-smi non-heap-number. Call
797 // the runtime.
798 __ b(ne, slow);
799 }
800
801 // Rhs is a smi, lhs is a heap number.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000802 // Load the double from lhs, tagged HeapNumber r1, to d7.
803 __ sub(r7, lhs, Operand(kHeapObjectTag));
804 __ vldr(d7, r7, HeapNumber::kValueOffset);
805 // Convert rhs to a double in d6 .
806 __ SmiToDoubleVFPRegister(rhs, d6, r7, s13);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000807 // Fall through to both_loaded_as_doubles.
808}
809
810
ricow@chromium.org65fae842010-08-25 15:26:24 +0000811// See comment at call site.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000812static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
813 Register lhs,
814 Register rhs) {
815 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
816 (lhs.is(r1) && rhs.is(r0)));
817
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000818 // If either operand is a JS object or an oddball value, then they are
ricow@chromium.org65fae842010-08-25 15:26:24 +0000819 // not equal since their pointers are different.
820 // There is no test for undetectability in strict equality.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000821 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000822 Label first_non_object;
823 // Get the type of the first operand into r2 and compare it with
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000824 // FIRST_SPEC_OBJECT_TYPE.
825 __ CompareObjectType(rhs, r2, r2, FIRST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000826 __ b(lt, &first_non_object);
827
828 // Return non-zero (r0 is not zero)
829 Label return_not_equal;
830 __ bind(&return_not_equal);
831 __ Ret();
832
833 __ bind(&first_non_object);
834 // Check for oddballs: true, false, null, undefined.
835 __ cmp(r2, Operand(ODDBALL_TYPE));
836 __ b(eq, &return_not_equal);
837
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000838 __ CompareObjectType(lhs, r3, r3, FIRST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000839 __ b(ge, &return_not_equal);
840
841 // Check for oddballs: true, false, null, undefined.
842 __ cmp(r3, Operand(ODDBALL_TYPE));
843 __ b(eq, &return_not_equal);
844
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000845 // Now that we have the types we might as well check for
846 // internalized-internalized.
847 // Ensure that no non-strings have the internalized bit set.
848 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsInternalizedMask);
849 STATIC_ASSERT(kInternalizedTag != 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000850 __ and_(r2, r2, Operand(r3));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000851 __ tst(r2, Operand(kIsInternalizedMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000852 __ b(ne, &return_not_equal);
853}
854
855
856// See comment at call site.
857static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
858 Register lhs,
859 Register rhs,
860 Label* both_loaded_as_doubles,
861 Label* not_heap_numbers,
862 Label* slow) {
863 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
864 (lhs.is(r1) && rhs.is(r0)));
865
866 __ CompareObjectType(rhs, r3, r2, HEAP_NUMBER_TYPE);
867 __ b(ne, not_heap_numbers);
868 __ ldr(r2, FieldMemOperand(lhs, HeapObject::kMapOffset));
869 __ cmp(r2, r3);
870 __ b(ne, slow); // First was a heap number, second wasn't. Go slow case.
871
872 // Both are heap numbers. Load them up then jump to the code we have
873 // for that.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000874 __ sub(r7, rhs, Operand(kHeapObjectTag));
875 __ vldr(d6, r7, HeapNumber::kValueOffset);
876 __ sub(r7, lhs, Operand(kHeapObjectTag));
877 __ vldr(d7, r7, HeapNumber::kValueOffset);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000878 __ jmp(both_loaded_as_doubles);
879}
880
881
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000882// Fast negative check for internalized-to-internalized equality.
883static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
884 Register lhs,
885 Register rhs,
886 Label* possible_strings,
887 Label* not_both_strings) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000888 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
889 (lhs.is(r1) && rhs.is(r0)));
890
891 // r2 is object type of rhs.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000892 // Ensure that no non-strings have the internalized bit set.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000893 Label object_test;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000894 STATIC_ASSERT(kInternalizedTag != 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000895 __ tst(r2, Operand(kIsNotStringMask));
896 __ b(ne, &object_test);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000897 __ tst(r2, Operand(kIsInternalizedMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000898 __ b(eq, possible_strings);
899 __ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE);
900 __ b(ge, not_both_strings);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000901 __ tst(r3, Operand(kIsInternalizedMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000902 __ b(eq, possible_strings);
903
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000904 // Both are internalized. We already checked they weren't the same pointer
ricow@chromium.org65fae842010-08-25 15:26:24 +0000905 // so they are not equal.
906 __ mov(r0, Operand(NOT_EQUAL));
907 __ Ret();
908
909 __ bind(&object_test);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000910 __ cmp(r2, Operand(FIRST_SPEC_OBJECT_TYPE));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000911 __ b(lt, not_both_strings);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000912 __ CompareObjectType(lhs, r2, r3, FIRST_SPEC_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000913 __ b(lt, not_both_strings);
914 // If both objects are undetectable, they are equal. Otherwise, they
915 // are not equal, since they are different objects and an object is not
916 // equal to undefined.
917 __ ldr(r3, FieldMemOperand(rhs, HeapObject::kMapOffset));
918 __ ldrb(r2, FieldMemOperand(r2, Map::kBitFieldOffset));
919 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
920 __ and_(r0, r2, Operand(r3));
921 __ and_(r0, r0, Operand(1 << Map::kIsUndetectable));
922 __ eor(r0, r0, Operand(1 << Map::kIsUndetectable));
923 __ Ret();
924}
925
926
927void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
928 Register object,
929 Register result,
930 Register scratch1,
931 Register scratch2,
932 Register scratch3,
933 bool object_is_smi,
934 Label* not_found) {
935 // Use of registers. Register result is used as a temporary.
936 Register number_string_cache = result;
937 Register mask = scratch3;
938
939 // Load the number string cache.
940 __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
941
942 // Make the hash mask from the length of the number string cache. It
943 // contains two elements (number and string) for each cache entry.
944 __ ldr(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset));
945 // Divide length by two (length is a smi).
946 __ mov(mask, Operand(mask, ASR, kSmiTagSize + 1));
947 __ sub(mask, mask, Operand(1)); // Make mask.
948
949 // Calculate the entry in the number string cache. The hash value in the
950 // number string cache for smis is just the smi value, and the hash for
951 // doubles is the xor of the upper and lower words. See
952 // Heap::GetNumberStringCache.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000953 Isolate* isolate = masm->isolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000954 Label is_smi;
955 Label load_result_from_cache;
956 if (!object_is_smi) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000957 __ JumpIfSmi(object, &is_smi);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000958 __ CheckMap(object,
959 scratch1,
960 Heap::kHeapNumberMapRootIndex,
961 not_found,
962 DONT_DO_SMI_CHECK);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000963
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000964 STATIC_ASSERT(8 == kDoubleSize);
965 __ add(scratch1,
966 object,
967 Operand(HeapNumber::kValueOffset - kHeapObjectTag));
968 __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit());
969 __ eor(scratch1, scratch1, Operand(scratch2));
970 __ and_(scratch1, scratch1, Operand(mask));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000971
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000972 // Calculate address of entry in string cache: each entry consists
973 // of two pointer sized fields.
974 __ add(scratch1,
975 number_string_cache,
976 Operand(scratch1, LSL, kPointerSizeLog2 + 1));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000977
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000978 Register probe = mask;
979 __ ldr(probe,
980 FieldMemOperand(scratch1, FixedArray::kHeaderSize));
981 __ JumpIfSmi(probe, not_found);
982 __ sub(scratch2, object, Operand(kHeapObjectTag));
983 __ vldr(d0, scratch2, HeapNumber::kValueOffset);
984 __ sub(probe, probe, Operand(kHeapObjectTag));
985 __ vldr(d1, probe, HeapNumber::kValueOffset);
986 __ VFPCompareAndSetFlags(d0, d1);
987 __ b(ne, not_found); // The cache did not contain this value.
988 __ b(&load_result_from_cache);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000989 }
990
991 __ bind(&is_smi);
992 Register scratch = scratch1;
993 __ and_(scratch, mask, Operand(object, ASR, 1));
994 // Calculate address of entry in string cache: each entry consists
995 // of two pointer sized fields.
996 __ add(scratch,
997 number_string_cache,
998 Operand(scratch, LSL, kPointerSizeLog2 + 1));
999
1000 // Check if the entry is the smi we are looking for.
1001 Register probe = mask;
1002 __ ldr(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize));
1003 __ cmp(object, probe);
1004 __ b(ne, not_found);
1005
1006 // Get the result from the cache.
1007 __ bind(&load_result_from_cache);
1008 __ ldr(result,
1009 FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001010 __ IncrementCounter(isolate->counters()->number_to_string_native(),
ricow@chromium.org65fae842010-08-25 15:26:24 +00001011 1,
1012 scratch1,
1013 scratch2);
1014}
1015
1016
1017void NumberToStringStub::Generate(MacroAssembler* masm) {
1018 Label runtime;
1019
1020 __ ldr(r1, MemOperand(sp, 0));
1021
1022 // Generate code to lookup number in the number string cache.
1023 GenerateLookupNumberStringCache(masm, r1, r0, r2, r3, r4, false, &runtime);
1024 __ add(sp, sp, Operand(1 * kPointerSize));
1025 __ Ret();
1026
1027 __ bind(&runtime);
1028 // Handle number to string in the runtime system if not found in the cache.
1029 __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1);
1030}
1031
1032
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001033static void ICCompareStub_CheckInputType(MacroAssembler* masm,
1034 Register input,
1035 Register scratch,
1036 CompareIC::State expected,
1037 Label* fail) {
1038 Label ok;
1039 if (expected == CompareIC::SMI) {
1040 __ JumpIfNotSmi(input, fail);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001041 } else if (expected == CompareIC::NUMBER) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001042 __ JumpIfSmi(input, &ok);
1043 __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail,
1044 DONT_DO_SMI_CHECK);
1045 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001046 // We could be strict about internalized/non-internalized here, but as long as
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001047 // hydrogen doesn't care, the stub doesn't have to care either.
1048 __ bind(&ok);
1049}
1050
1051
1052// On entry r1 and r2 are the values to be compared.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001053// On exit r0 is 0, positive or negative to indicate the result of
1054// the comparison.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001055void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
1056 Register lhs = r1;
1057 Register rhs = r0;
1058 Condition cc = GetCondition();
1059
1060 Label miss;
1061 ICCompareStub_CheckInputType(masm, lhs, r2, left_, &miss);
1062 ICCompareStub_CheckInputType(masm, rhs, r3, right_, &miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001063
1064 Label slow; // Call builtin.
1065 Label not_smis, both_loaded_as_doubles, lhs_not_nan;
1066
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001067 Label not_two_smis, smi_done;
1068 __ orr(r2, r1, r0);
1069 __ JumpIfNotSmi(r2, &not_two_smis);
1070 __ mov(r1, Operand(r1, ASR, 1));
1071 __ sub(r0, r1, Operand(r0, ASR, 1));
1072 __ Ret();
1073 __ bind(&not_two_smis);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001074
ricow@chromium.org65fae842010-08-25 15:26:24 +00001075 // NOTICE! This code is only reached after a smi-fast-case check, so
1076 // it is certain that at least one operand isn't a smi.
1077
1078 // Handle the case where the objects are identical. Either returns the answer
1079 // or goes to slow. Only falls through if the objects were not identical.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001080 EmitIdenticalObjectComparison(masm, &slow, cc);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001081
1082 // If either is a Smi (we know that not both are), then they can only
1083 // be strictly equal if the other is a HeapNumber.
1084 STATIC_ASSERT(kSmiTag == 0);
1085 ASSERT_EQ(0, Smi::FromInt(0));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001086 __ and_(r2, lhs, Operand(rhs));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001087 __ JumpIfNotSmi(r2, &not_smis);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001088 // One operand is a smi. EmitSmiNonsmiComparison generates code that can:
1089 // 1) Return the answer.
1090 // 2) Go to slow.
1091 // 3) Fall through to both_loaded_as_doubles.
1092 // 4) Jump to lhs_not_nan.
1093 // In cases 3 and 4 we have found out we were dealing with a number-number
1094 // comparison. If VFP3 is supported the double values of the numbers have
1095 // been loaded into d7 and d6. Otherwise, the double values have been loaded
1096 // into r0, r1, r2, and r3.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001097 EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001098
1099 __ bind(&both_loaded_as_doubles);
1100 // The arguments have been converted to doubles and stored in d6 and d7, if
1101 // VFP3 is supported, or in r0, r1, r2, and r3.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001102 Isolate* isolate = masm->isolate();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001103 __ bind(&lhs_not_nan);
1104 Label no_nan;
1105 // ARMv7 VFP3 instructions to implement double precision comparison.
1106 __ VFPCompareAndSetFlags(d7, d6);
1107 Label nan;
1108 __ b(vs, &nan);
1109 __ mov(r0, Operand(EQUAL), LeaveCC, eq);
1110 __ mov(r0, Operand(LESS), LeaveCC, lt);
1111 __ mov(r0, Operand(GREATER), LeaveCC, gt);
1112 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001113
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001114 __ bind(&nan);
1115 // If one of the sides was a NaN then the v flag is set. Load r0 with
1116 // whatever it takes to make the comparison fail, since comparisons with NaN
1117 // always fail.
1118 if (cc == lt || cc == le) {
1119 __ mov(r0, Operand(GREATER));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001120 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001121 __ mov(r0, Operand(LESS));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001122 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001123 __ Ret();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001124
1125 __ bind(&not_smis);
1126 // At this point we know we are dealing with two different objects,
1127 // and neither of them is a Smi. The objects are in rhs_ and lhs_.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001128 if (strict()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001129 // This returns non-equal for some object types, or falls through if it
1130 // was not lucky.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001131 EmitStrictTwoHeapObjectCompare(masm, lhs, rhs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001132 }
1133
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001134 Label check_for_internalized_strings;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001135 Label flat_string_check;
1136 // Check for heap-number-heap-number comparison. Can jump to slow case,
1137 // or load both doubles into r0, r1, r2, r3 and jump to the code that handles
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001138 // that case. If the inputs are not doubles then jumps to
1139 // check_for_internalized_strings.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001140 // In this case r2 will contain the type of rhs_. Never falls through.
1141 EmitCheckForTwoHeapNumbers(masm,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001142 lhs,
1143 rhs,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001144 &both_loaded_as_doubles,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001145 &check_for_internalized_strings,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001146 &flat_string_check);
1147
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001148 __ bind(&check_for_internalized_strings);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001149 // In the strict case the EmitStrictTwoHeapObjectCompare already took care of
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001150 // internalized strings.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001151 if (cc == eq && !strict()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001152 // Returns an answer for two internalized strings or two detectable objects.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001153 // Otherwise jumps to string case or not both strings case.
1154 // Assumes that r2 is the type of rhs_ on entry.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001155 EmitCheckForInternalizedStringsOrObjects(
1156 masm, lhs, rhs, &flat_string_check, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001157 }
1158
1159 // Check for both being sequential ASCII strings, and inline if that is the
1160 // case.
1161 __ bind(&flat_string_check);
1162
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001163 __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs, rhs, r2, r3, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001164
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001165 __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001166 if (cc == eq) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001167 StringCompareStub::GenerateFlatAsciiStringEquals(masm,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001168 lhs,
1169 rhs,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001170 r2,
1171 r3,
lrn@chromium.org1c092762011-05-09 09:42:16 +00001172 r4);
1173 } else {
1174 StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001175 lhs,
1176 rhs,
lrn@chromium.org1c092762011-05-09 09:42:16 +00001177 r2,
1178 r3,
1179 r4,
1180 r5);
1181 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001182 // Never falls through to here.
1183
1184 __ bind(&slow);
1185
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001186 __ Push(lhs, rhs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001187 // Figure out which native to call and setup the arguments.
1188 Builtins::JavaScript native;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001189 if (cc == eq) {
1190 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001191 } else {
1192 native = Builtins::COMPARE;
1193 int ncr; // NaN compare result
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001194 if (cc == lt || cc == le) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001195 ncr = GREATER;
1196 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001197 ASSERT(cc == gt || cc == ge); // remaining cases
ricow@chromium.org65fae842010-08-25 15:26:24 +00001198 ncr = LESS;
1199 }
1200 __ mov(r0, Operand(Smi::FromInt(ncr)));
1201 __ push(r0);
1202 }
1203
1204 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
1205 // tagged as a small integer.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001206 __ InvokeBuiltin(native, JUMP_FUNCTION);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001207
1208 __ bind(&miss);
1209 GenerateMiss(masm);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001210}
1211
1212
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001213// The stub expects its argument in the tos_ register and returns its result in
1214// it, too: zero for false, and a non-zero value for true.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001215void ToBooleanStub::Generate(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001216 // This stub overrides SometimesSetsUpAFrame() to return false. That means
1217 // we cannot call anything that could cause a GC from this stub.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001218 Label patch;
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001219 const Register map = r9.is(tos_) ? r7 : r9;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001220
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001221 // undefined -> false.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001222 CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001223
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001224 // Boolean -> its value.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001225 CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
1226 CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001227
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001228 // 'null' -> false.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001229 CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001230
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001231 if (types_.Contains(SMI)) {
1232 // Smis: 0 -> false, all other -> true
1233 __ tst(tos_, Operand(kSmiTagMask));
1234 // tos_ contains the correct return value already
1235 __ Ret(eq);
1236 } else if (types_.NeedsMap()) {
1237 // If we need a map later and have a Smi -> patch.
1238 __ JumpIfSmi(tos_, &patch);
1239 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001240
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001241 if (types_.NeedsMap()) {
1242 __ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001243
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001244 if (types_.CanBeUndetectable()) {
1245 __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
1246 __ tst(ip, Operand(1 << Map::kIsUndetectable));
1247 // Undetectable -> false.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001248 __ mov(tos_, Operand::Zero(), LeaveCC, ne);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001249 __ Ret(ne);
1250 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001251 }
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001252
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001253 if (types_.Contains(SPEC_OBJECT)) {
1254 // Spec object -> true.
1255 __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
1256 // tos_ contains the correct non-zero return value already.
1257 __ Ret(ge);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001258 }
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001259
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001260 if (types_.Contains(STRING)) {
1261 // String value -> false iff empty.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001262 __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
1263 __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
1264 __ Ret(lt); // the string length is OK as the return value
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001265 }
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001266
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001267 if (types_.Contains(HEAP_NUMBER)) {
1268 // Heap number -> false iff +0, -0, or NaN.
1269 Label not_heap_number;
1270 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
1271 __ b(ne, &not_heap_number);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001272
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001273 __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset));
1274 __ VFPCompareAndSetFlags(d1, 0.0);
1275 // "tos_" is a register, and contains a non zero value by default.
1276 // Hence we only need to overwrite "tos_" with zero to return false for
1277 // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
1278 __ mov(tos_, Operand::Zero(), LeaveCC, eq); // for FP_ZERO
1279 __ mov(tos_, Operand::Zero(), LeaveCC, vs); // for FP_NAN
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001280 __ Ret();
1281 __ bind(&not_heap_number);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001282 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001283
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001284 __ bind(&patch);
1285 GenerateTypeTransition(masm);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001286}
1287
1288
1289void ToBooleanStub::CheckOddball(MacroAssembler* masm,
1290 Type type,
1291 Heap::RootListIndex value,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001292 bool result) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001293 if (types_.Contains(type)) {
1294 // If we see an expected oddball, return its ToBoolean value tos_.
1295 __ LoadRoot(ip, value);
1296 __ cmp(tos_, ip);
1297 // The value of a root is never NULL, so we can avoid loading a non-null
1298 // value into tos_ when we want to return 'true'.
1299 if (!result) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001300 __ mov(tos_, Operand::Zero(), LeaveCC, eq);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001301 }
1302 __ Ret(eq);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001303 }
1304}
1305
1306
1307void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
1308 if (!tos_.is(r3)) {
1309 __ mov(r3, Operand(tos_));
1310 }
1311 __ mov(r2, Operand(Smi::FromInt(tos_.code())));
1312 __ mov(r1, Operand(Smi::FromInt(types_.ToByte())));
1313 __ Push(r3, r2, r1);
1314 // Patch the caller to an appropriate specialized stub and return the
1315 // operation result to the caller of the stub.
1316 __ TailCallExternalReference(
1317 ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()),
1318 3,
1319 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001320}
1321
1322
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001323void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
1324 // We don't allow a GC during a store buffer overflow so there is no need to
1325 // store the registers in any particular way, but we do have to store and
1326 // restore them.
1327 __ stm(db_w, sp, kCallerSaved | lr.bit());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001328
1329 const Register scratch = r1;
1330
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001331 if (save_doubles_ == kSaveFPRegs) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001332 __ SaveFPRegs(sp, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001333 }
1334 const int argument_count = 1;
1335 const int fp_argument_count = 0;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001336
1337 AllowExternalCallThatCantCauseGC scope(masm);
1338 __ PrepareCallCFunction(argument_count, fp_argument_count, scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001339 __ mov(r0, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001340 __ CallCFunction(
1341 ExternalReference::store_buffer_overflow_function(masm->isolate()),
1342 argument_count);
1343 if (save_doubles_ == kSaveFPRegs) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001344 __ RestoreFPRegs(sp, scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001345 }
1346 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0).
1347}
1348
1349
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001350void UnaryOpStub::PrintName(StringStream* stream) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001351 const char* op_name = Token::Name(op_);
1352 const char* overwrite_name = NULL; // Make g++ happy.
1353 switch (mode_) {
1354 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
1355 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break;
1356 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001357 stream->Add("UnaryOpStub_%s_%s_%s",
1358 op_name,
1359 overwrite_name,
1360 UnaryOpIC::GetName(operand_type_));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001361}
1362
1363
1364// TODO(svenpanne): Use virtual functions instead of switch.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001365void UnaryOpStub::Generate(MacroAssembler* masm) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001366 switch (operand_type_) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001367 case UnaryOpIC::UNINITIALIZED:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001368 GenerateTypeTransition(masm);
1369 break;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001370 case UnaryOpIC::SMI:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001371 GenerateSmiStub(masm);
1372 break;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001373 case UnaryOpIC::NUMBER:
1374 GenerateNumberStub(masm);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001375 break;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001376 case UnaryOpIC::GENERIC:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001377 GenerateGenericStub(masm);
1378 break;
1379 }
1380}
1381
1382
danno@chromium.org40cb8782011-05-25 07:58:50 +00001383void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001384 __ mov(r3, Operand(r0)); // the operand
1385 __ mov(r2, Operand(Smi::FromInt(op_)));
1386 __ mov(r1, Operand(Smi::FromInt(mode_)));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001387 __ mov(r0, Operand(Smi::FromInt(operand_type_)));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001388 __ Push(r3, r2, r1, r0);
1389
1390 __ TailCallExternalReference(
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001391 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001392}
1393
1394
1395// TODO(svenpanne): Use virtual functions instead of switch.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001396void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001397 switch (op_) {
1398 case Token::SUB:
1399 GenerateSmiStubSub(masm);
1400 break;
1401 case Token::BIT_NOT:
1402 GenerateSmiStubBitNot(masm);
1403 break;
1404 default:
1405 UNREACHABLE();
1406 }
1407}
1408
1409
danno@chromium.org40cb8782011-05-25 07:58:50 +00001410void UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001411 Label non_smi, slow;
1412 GenerateSmiCodeSub(masm, &non_smi, &slow);
1413 __ bind(&non_smi);
1414 __ bind(&slow);
1415 GenerateTypeTransition(masm);
1416}
1417
1418
danno@chromium.org40cb8782011-05-25 07:58:50 +00001419void UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001420 Label non_smi;
1421 GenerateSmiCodeBitNot(masm, &non_smi);
1422 __ bind(&non_smi);
1423 GenerateTypeTransition(masm);
1424}
1425
1426
danno@chromium.org40cb8782011-05-25 07:58:50 +00001427void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm,
1428 Label* non_smi,
1429 Label* slow) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001430 __ JumpIfNotSmi(r0, non_smi);
1431
1432 // The result of negating zero or the smallest negative smi is not a smi.
1433 __ bic(ip, r0, Operand(0x80000000), SetCC);
1434 __ b(eq, slow);
1435
1436 // Return '0 - value'.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001437 __ rsb(r0, r0, Operand::Zero());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001438 __ Ret();
1439}
1440
1441
danno@chromium.org40cb8782011-05-25 07:58:50 +00001442void UnaryOpStub::GenerateSmiCodeBitNot(MacroAssembler* masm,
1443 Label* non_smi) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001444 __ JumpIfNotSmi(r0, non_smi);
1445
1446 // Flip bits and revert inverted smi-tag.
1447 __ mvn(r0, Operand(r0));
1448 __ bic(r0, r0, Operand(kSmiTagMask));
1449 __ Ret();
1450}
1451
1452
1453// TODO(svenpanne): Use virtual functions instead of switch.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001454void UnaryOpStub::GenerateNumberStub(MacroAssembler* masm) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001455 switch (op_) {
1456 case Token::SUB:
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001457 GenerateNumberStubSub(masm);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001458 break;
1459 case Token::BIT_NOT:
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001460 GenerateNumberStubBitNot(masm);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001461 break;
1462 default:
1463 UNREACHABLE();
1464 }
1465}
1466
1467
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001468void UnaryOpStub::GenerateNumberStubSub(MacroAssembler* masm) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001469 Label non_smi, slow, call_builtin;
1470 GenerateSmiCodeSub(masm, &non_smi, &call_builtin);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001471 __ bind(&non_smi);
1472 GenerateHeapNumberCodeSub(masm, &slow);
1473 __ bind(&slow);
1474 GenerateTypeTransition(masm);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001475 __ bind(&call_builtin);
1476 GenerateGenericCodeFallback(masm);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001477}
1478
1479
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001480void UnaryOpStub::GenerateNumberStubBitNot(MacroAssembler* masm) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001481 Label non_smi, slow;
1482 GenerateSmiCodeBitNot(masm, &non_smi);
1483 __ bind(&non_smi);
1484 GenerateHeapNumberCodeBitNot(masm, &slow);
1485 __ bind(&slow);
1486 GenerateTypeTransition(masm);
1487}
1488
danno@chromium.org40cb8782011-05-25 07:58:50 +00001489void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
1490 Label* slow) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001491 EmitCheckForHeapNumber(masm, r0, r1, r6, slow);
1492 // r0 is a heap number. Get a new heap number in r1.
1493 if (mode_ == UNARY_OVERWRITE) {
1494 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
1495 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign.
1496 __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
1497 } else {
1498 Label slow_allocate_heapnumber, heapnumber_allocated;
1499 __ AllocateHeapNumber(r1, r2, r3, r6, &slow_allocate_heapnumber);
1500 __ jmp(&heapnumber_allocated);
1501
1502 __ bind(&slow_allocate_heapnumber);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001503 {
1504 FrameScope scope(masm, StackFrame::INTERNAL);
1505 __ push(r0);
1506 __ CallRuntime(Runtime::kNumberAlloc, 0);
1507 __ mov(r1, Operand(r0));
1508 __ pop(r0);
1509 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001510
1511 __ bind(&heapnumber_allocated);
1512 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
1513 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
1514 __ str(r3, FieldMemOperand(r1, HeapNumber::kMantissaOffset));
1515 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign.
1516 __ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset));
1517 __ mov(r0, Operand(r1));
1518 }
1519 __ Ret();
1520}
1521
1522
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001523void UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
1524 Label* slow) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001525 EmitCheckForHeapNumber(masm, r0, r1, r6, slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001526
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001527 // Convert the heap number in r0 to an untagged integer in r1.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001528 __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
1529 __ ECMAToInt32(r1, d0, r2, r3, r4, d1);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001530
1531 // Do the bitwise operation and check if the result fits in a smi.
1532 Label try_float;
1533 __ mvn(r1, Operand(r1));
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001534 __ cmn(r1, Operand(0x40000000));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001535 __ b(mi, &try_float);
1536
1537 // Tag the result as a smi and we're done.
1538 __ mov(r0, Operand(r1, LSL, kSmiTagSize));
1539 __ Ret();
1540
1541 // Try to store the result in a heap number.
1542 __ bind(&try_float);
1543 if (mode_ == UNARY_NO_OVERWRITE) {
1544 Label slow_allocate_heapnumber, heapnumber_allocated;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001545 __ AllocateHeapNumber(r0, r3, r4, r6, &slow_allocate_heapnumber);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001546 __ jmp(&heapnumber_allocated);
1547
1548 __ bind(&slow_allocate_heapnumber);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001549 {
1550 FrameScope scope(masm, StackFrame::INTERNAL);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001551 // Push the lower bit of the result (left shifted to look like a smi).
1552 __ mov(r2, Operand(r1, LSL, 31));
1553 // Push the 31 high bits (bit 0 cleared to look like a smi).
1554 __ bic(r1, r1, Operand(1));
1555 __ Push(r2, r1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001556 __ CallRuntime(Runtime::kNumberAlloc, 0);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001557 __ Pop(r2, r1); // Restore the result.
1558 __ orr(r1, r1, Operand(r2, LSR, 31));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001559 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001560 __ bind(&heapnumber_allocated);
1561 }
1562
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001563 __ vmov(s0, r1);
1564 __ vcvt_f64_s32(d0, s0);
1565 __ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
1566 __ Ret();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001567}
1568
1569
1570// TODO(svenpanne): Use virtual functions instead of switch.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001571void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001572 switch (op_) {
1573 case Token::SUB:
1574 GenerateGenericStubSub(masm);
1575 break;
1576 case Token::BIT_NOT:
1577 GenerateGenericStubBitNot(masm);
1578 break;
1579 default:
1580 UNREACHABLE();
1581 }
1582}
1583
1584
danno@chromium.org40cb8782011-05-25 07:58:50 +00001585void UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001586 Label non_smi, slow;
1587 GenerateSmiCodeSub(masm, &non_smi, &slow);
1588 __ bind(&non_smi);
1589 GenerateHeapNumberCodeSub(masm, &slow);
1590 __ bind(&slow);
1591 GenerateGenericCodeFallback(masm);
1592}
1593
1594
danno@chromium.org40cb8782011-05-25 07:58:50 +00001595void UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001596 Label non_smi, slow;
1597 GenerateSmiCodeBitNot(masm, &non_smi);
1598 __ bind(&non_smi);
1599 GenerateHeapNumberCodeBitNot(masm, &slow);
1600 __ bind(&slow);
1601 GenerateGenericCodeFallback(masm);
1602}
1603
1604
danno@chromium.org40cb8782011-05-25 07:58:50 +00001605void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001606 // Handle the slow case by jumping to the JavaScript builtin.
1607 __ push(r0);
1608 switch (op_) {
1609 case Token::SUB:
1610 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
1611 break;
1612 case Token::BIT_NOT:
1613 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
1614 break;
1615 default:
1616 UNREACHABLE();
1617 }
1618}
1619
1620
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001621// Generates code to call a C function to do a double operation.
1622// This code never falls through, but returns with a heap number containing
1623// the result in r0.
1624// Register heapnumber_result must be a heap number in which the
1625// result of the operation will be stored.
1626// Requires the following layout on entry:
1627// d0: Left value.
1628// d1: Right value.
1629// If soft float ABI, use also r0, r1, r2, r3.
1630static void CallCCodeForDoubleOperation(MacroAssembler* masm,
1631 Token::Value op,
1632 Register heap_number_result,
1633 Register scratch) {
1634 // Assert that heap_number_result is callee-saved.
1635 // We currently always use r5 to pass it.
1636 ASSERT(heap_number_result.is(r5));
1637
1638 // Push the current return address before the C call. Return will be
1639 // through pop(pc) below.
1640 __ push(lr);
1641 __ PrepareCallCFunction(0, 2, scratch);
1642 if (!masm->use_eabi_hardfloat()) {
1643 __ vmov(r0, r1, d0);
1644 __ vmov(r2, r3, d1);
1645 }
1646 {
1647 AllowExternalCallThatCantCauseGC scope(masm);
1648 __ CallCFunction(
1649 ExternalReference::double_fp_operation(op, masm->isolate()), 0, 2);
1650 }
1651 // Store answer in the overwritable heap number. Double returned in
1652 // registers r0 and r1 or in d0.
1653 if (masm->use_eabi_hardfloat()) {
1654 __ vstr(d0, FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
1655 } else {
1656 __ Strd(r0, r1,
1657 FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
1658 }
1659 // Place heap_number_result in r0 and return to the pushed return address.
1660 __ mov(r0, Operand(heap_number_result));
1661 __ pop(pc);
1662}
1663
1664
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001665void BinaryOpStub::Initialize() {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001666 platform_specific_bit_ = true; // VFP2 is a base requirement for V8
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001667}
1668
1669
danno@chromium.org40cb8782011-05-25 07:58:50 +00001670void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001671 Label get_result;
1672
1673 __ Push(r1, r0);
1674
1675 __ mov(r2, Operand(Smi::FromInt(MinorKey())));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001676 __ push(r2);
ager@chromium.org378b34e2011-01-28 08:04:38 +00001677
1678 __ TailCallExternalReference(
danno@chromium.org40cb8782011-05-25 07:58:50 +00001679 ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001680 masm->isolate()),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001681 3,
ager@chromium.org378b34e2011-01-28 08:04:38 +00001682 1);
1683}
1684
1685
danno@chromium.org40cb8782011-05-25 07:58:50 +00001686void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(
ager@chromium.org378b34e2011-01-28 08:04:38 +00001687 MacroAssembler* masm) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001688 UNIMPLEMENTED();
ager@chromium.org378b34e2011-01-28 08:04:38 +00001689}
1690
1691
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001692void BinaryOpStub_GenerateSmiSmiOperation(MacroAssembler* masm,
1693 Token::Value op) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001694 Register left = r1;
1695 Register right = r0;
1696 Register scratch1 = r7;
1697 Register scratch2 = r9;
1698
1699 ASSERT(right.is(r0));
1700 STATIC_ASSERT(kSmiTag == 0);
1701
1702 Label not_smi_result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001703 switch (op) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001704 case Token::ADD:
1705 __ add(right, left, Operand(right), SetCC); // Add optimistically.
1706 __ Ret(vc);
1707 __ sub(right, right, Operand(left)); // Revert optimistic add.
1708 break;
1709 case Token::SUB:
1710 __ sub(right, left, Operand(right), SetCC); // Subtract optimistically.
1711 __ Ret(vc);
1712 __ sub(right, left, Operand(right)); // Revert optimistic subtract.
1713 break;
1714 case Token::MUL:
1715 // Remove tag from one of the operands. This way the multiplication result
1716 // will be a smi if it fits the smi range.
1717 __ SmiUntag(ip, right);
1718 // Do multiplication
1719 // scratch1 = lower 32 bits of ip * left.
1720 // scratch2 = higher 32 bits of ip * left.
1721 __ smull(scratch1, scratch2, left, ip);
1722 // Check for overflowing the smi range - no overflow if higher 33 bits of
1723 // the result are identical.
1724 __ mov(ip, Operand(scratch1, ASR, 31));
1725 __ cmp(ip, Operand(scratch2));
1726 __ b(ne, &not_smi_result);
1727 // Go slow on zero result to handle -0.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001728 __ cmp(scratch1, Operand::Zero());
ager@chromium.org378b34e2011-01-28 08:04:38 +00001729 __ mov(right, Operand(scratch1), LeaveCC, ne);
1730 __ Ret(ne);
1731 // We need -0 if we were multiplying a negative number with 0 to get 0.
1732 // We know one of them was zero.
1733 __ add(scratch2, right, Operand(left), SetCC);
1734 __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl);
1735 __ Ret(pl); // Return smi 0 if the non-zero one was positive.
1736 // We fall through here if we multiplied a negative number with 0, because
1737 // that would mean we should produce -0.
1738 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001739 case Token::DIV: {
1740 Label div_with_sdiv;
1741
1742 // Check for 0 divisor.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001743 __ cmp(right, Operand::Zero());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001744 __ b(eq, &not_smi_result);
1745
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001746 // Check for power of two on the right hand side.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001747 __ sub(scratch1, right, Operand(1));
1748 __ tst(scratch1, right);
1749 if (CpuFeatures::IsSupported(SUDIV)) {
1750 __ b(ne, &div_with_sdiv);
1751 // Check for no remainder.
1752 __ tst(left, scratch1);
1753 __ b(ne, &not_smi_result);
1754 // Check for positive left hand side.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001755 __ cmp(left, Operand::Zero());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001756 __ b(mi, &div_with_sdiv);
1757 } else {
1758 __ b(ne, &not_smi_result);
1759 // Check for positive and no remainder.
1760 __ orr(scratch2, scratch1, Operand(0x80000000u));
1761 __ tst(left, scratch2);
1762 __ b(ne, &not_smi_result);
1763 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001764
1765 // Perform division by shifting.
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00001766 __ clz(scratch1, scratch1);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001767 __ rsb(scratch1, scratch1, Operand(31));
1768 __ mov(right, Operand(left, LSR, scratch1));
1769 __ Ret();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001770
1771 if (CpuFeatures::IsSupported(SUDIV)) {
1772 Label result_not_zero;
1773
1774 __ bind(&div_with_sdiv);
1775 // Do division.
1776 __ sdiv(scratch1, left, right);
1777 // Check that the remainder is zero.
1778 __ mls(scratch2, scratch1, right, left);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001779 __ cmp(scratch2, Operand::Zero());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001780 __ b(ne, &not_smi_result);
1781 // Check for negative zero result.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001782 __ cmp(scratch1, Operand::Zero());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001783 __ b(ne, &result_not_zero);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001784 __ cmp(right, Operand::Zero());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001785 __ b(lt, &not_smi_result);
1786 __ bind(&result_not_zero);
1787 // Check for the corner case of dividing the most negative smi by -1.
1788 __ cmp(scratch1, Operand(0x40000000));
1789 __ b(eq, &not_smi_result);
1790 // Tag and return the result.
1791 __ SmiTag(right, scratch1);
1792 __ Ret();
1793 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001794 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001795 }
1796 case Token::MOD: {
1797 Label modulo_with_sdiv;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001798
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001799 if (CpuFeatures::IsSupported(SUDIV)) {
1800 // Check for x % 0.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001801 __ cmp(right, Operand::Zero());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001802 __ b(eq, &not_smi_result);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001803
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001804 // Check for two positive smis.
1805 __ orr(scratch1, left, Operand(right));
1806 __ tst(scratch1, Operand(0x80000000u));
1807 __ b(ne, &modulo_with_sdiv);
1808
1809 // Check for power of two on the right hand side.
1810 __ sub(scratch1, right, Operand(1));
1811 __ tst(scratch1, right);
1812 __ b(ne, &modulo_with_sdiv);
1813 } else {
1814 // Check for two positive smis.
1815 __ orr(scratch1, left, Operand(right));
1816 __ tst(scratch1, Operand(0x80000000u));
1817 __ b(ne, &not_smi_result);
1818
1819 // Check for power of two on the right hand side.
1820 __ JumpIfNotPowerOfTwoOrZero(right, scratch1, &not_smi_result);
1821 }
1822
1823 // Perform modulus by masking (scratch1 contains right - 1).
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001824 __ and_(right, left, Operand(scratch1));
1825 __ Ret();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001826
1827 if (CpuFeatures::IsSupported(SUDIV)) {
1828 __ bind(&modulo_with_sdiv);
1829 __ mov(scratch2, right);
1830 // Perform modulus with sdiv and mls.
1831 __ sdiv(scratch1, left, right);
1832 __ mls(right, scratch1, right, left);
1833 // Return if the result is not 0.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001834 __ cmp(right, Operand::Zero());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001835 __ Ret(ne);
1836 // The result is 0, check for -0 case.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001837 __ cmp(left, Operand::Zero());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001838 __ Ret(pl);
1839 // This is a -0 case, restore the value of right.
1840 __ mov(right, scratch2);
1841 // We fall through here to not_smi_result to produce -0.
1842 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001843 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001844 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001845 case Token::BIT_OR:
1846 __ orr(right, left, Operand(right));
1847 __ Ret();
1848 break;
1849 case Token::BIT_AND:
1850 __ and_(right, left, Operand(right));
1851 __ Ret();
1852 break;
1853 case Token::BIT_XOR:
1854 __ eor(right, left, Operand(right));
1855 __ Ret();
1856 break;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001857 case Token::SAR:
1858 // Remove tags from right operand.
1859 __ GetLeastBitsFromSmi(scratch1, right, 5);
1860 __ mov(right, Operand(left, ASR, scratch1));
1861 // Smi tag result.
1862 __ bic(right, right, Operand(kSmiTagMask));
1863 __ Ret();
1864 break;
1865 case Token::SHR:
1866 // Remove tags from operands. We can't do this on a 31 bit number
1867 // because then the 0s get shifted into bit 30 instead of bit 31.
1868 __ SmiUntag(scratch1, left);
1869 __ GetLeastBitsFromSmi(scratch2, right, 5);
1870 __ mov(scratch1, Operand(scratch1, LSR, scratch2));
1871 // Unsigned shift is not allowed to produce a negative number, so
1872 // check the sign bit and the sign bit after Smi tagging.
1873 __ tst(scratch1, Operand(0xc0000000));
1874 __ b(ne, &not_smi_result);
1875 // Smi tag result.
1876 __ SmiTag(right, scratch1);
1877 __ Ret();
1878 break;
1879 case Token::SHL:
1880 // Remove tags from operands.
1881 __ SmiUntag(scratch1, left);
1882 __ GetLeastBitsFromSmi(scratch2, right, 5);
1883 __ mov(scratch1, Operand(scratch1, LSL, scratch2));
1884 // Check that the signed result fits in a Smi.
1885 __ add(scratch2, scratch1, Operand(0x40000000), SetCC);
1886 __ b(mi, &not_smi_result);
1887 __ SmiTag(right, scratch1);
1888 __ Ret();
1889 break;
ager@chromium.org378b34e2011-01-28 08:04:38 +00001890 default:
1891 UNREACHABLE();
1892 }
1893 __ bind(&not_smi_result);
1894}
1895
1896
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001897void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
1898 Register result,
1899 Register heap_number_map,
1900 Register scratch1,
1901 Register scratch2,
1902 Label* gc_required,
1903 OverwriteMode mode);
1904
1905
1906void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
1907 BinaryOpIC::TypeInfo left_type,
1908 BinaryOpIC::TypeInfo right_type,
1909 bool smi_operands,
1910 Label* not_numbers,
1911 Label* gc_required,
1912 Label* miss,
1913 Token::Value op,
1914 OverwriteMode mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001915 Register left = r1;
1916 Register right = r0;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001917 Register scratch1 = r6;
1918 Register scratch2 = r7;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001919 Register scratch3 = r4;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001920
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001921 ASSERT(smi_operands || (not_numbers != NULL));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001922 if (smi_operands) {
1923 __ AssertSmi(left);
1924 __ AssertSmi(right);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001925 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001926 if (left_type == BinaryOpIC::SMI) {
1927 __ JumpIfNotSmi(left, miss);
1928 }
1929 if (right_type == BinaryOpIC::SMI) {
1930 __ JumpIfNotSmi(right, miss);
1931 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001932
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001933 Register heap_number_map = r9;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001934 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
1935
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001936 switch (op) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001937 case Token::ADD:
1938 case Token::SUB:
1939 case Token::MUL:
1940 case Token::DIV:
1941 case Token::MOD: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001942 // Allocate new heap number for result.
1943 Register result = r5;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001944 BinaryOpStub_GenerateHeapResultAllocation(
1945 masm, result, heap_number_map, scratch1, scratch2, gc_required, mode);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001946
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001947 // Load left and right operands into d0 and d1.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001948 if (smi_operands) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001949 __ SmiUntag(scratch1, right);
1950 __ vmov(d1.high(), scratch1);
1951 __ vcvt_f64_s32(d1, d1.high());
1952 __ SmiUntag(scratch1, left);
1953 __ vmov(d0.high(), scratch1);
1954 __ vcvt_f64_s32(d0, d0.high());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001955 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001956 // Load right operand into d1.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001957 if (right_type == BinaryOpIC::INT32) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001958 __ LoadNumberAsInt32Double(
1959 right, d1, heap_number_map, scratch1, d8, miss);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001960 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001961 Label* fail = (right_type == BinaryOpIC::NUMBER) ? miss : not_numbers;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001962 __ LoadNumber(right, d1, heap_number_map, scratch1, fail);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001963 }
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001964 // Load left operand into d0.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001965 if (left_type == BinaryOpIC::INT32) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001966 __ LoadNumberAsInt32Double(
1967 left, d0, heap_number_map, scratch1, d8, miss);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001968 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001969 Label* fail = (left_type == BinaryOpIC::NUMBER) ? miss : not_numbers;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001970 __ LoadNumber(
1971 left, d0, heap_number_map, scratch1, fail);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001972 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001973 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001974
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001975 // Calculate the result.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001976 if (op != Token::MOD) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001977 // Using VFP registers:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001978 // d0: Left value
1979 // d1: Right value
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001980 switch (op) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001981 case Token::ADD:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001982 __ vadd(d5, d0, d1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001983 break;
1984 case Token::SUB:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001985 __ vsub(d5, d0, d1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001986 break;
1987 case Token::MUL:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001988 __ vmul(d5, d0, d1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001989 break;
1990 case Token::DIV:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001991 __ vdiv(d5, d0, d1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001992 break;
1993 default:
1994 UNREACHABLE();
1995 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001996
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001997 __ sub(r0, result, Operand(kHeapObjectTag));
1998 __ vstr(d5, r0, HeapNumber::kValueOffset);
1999 __ add(r0, r0, Operand(kHeapObjectTag));
2000 __ Ret();
2001 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002002 // Call the C function to handle the double operation.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002003 CallCCodeForDoubleOperation(masm, op, result, scratch1);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002004 if (FLAG_debug_code) {
2005 __ stop("Unreachable code.");
2006 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002007 }
2008 break;
2009 }
2010 case Token::BIT_OR:
2011 case Token::BIT_XOR:
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002012 case Token::BIT_AND:
2013 case Token::SAR:
2014 case Token::SHR:
2015 case Token::SHL: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002016 if (smi_operands) {
2017 __ SmiUntag(r3, left);
2018 __ SmiUntag(r2, right);
2019 } else {
2020 // Convert operands to 32-bit integers. Right in r2 and left in r3.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002021 __ ConvertNumberToInt32(
2022 left, r3, heap_number_map,
2023 scratch1, scratch2, scratch3, d0, d1, not_numbers);
2024 __ ConvertNumberToInt32(
2025 right, r2, heap_number_map,
2026 scratch1, scratch2, scratch3, d0, d1, not_numbers);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002027 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002028
2029 Label result_not_a_smi;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002030 switch (op) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002031 case Token::BIT_OR:
2032 __ orr(r2, r3, Operand(r2));
2033 break;
2034 case Token::BIT_XOR:
2035 __ eor(r2, r3, Operand(r2));
2036 break;
2037 case Token::BIT_AND:
2038 __ and_(r2, r3, Operand(r2));
2039 break;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002040 case Token::SAR:
2041 // Use only the 5 least significant bits of the shift count.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002042 __ GetLeastBitsFromInt32(r2, r2, 5);
2043 __ mov(r2, Operand(r3, ASR, r2));
2044 break;
2045 case Token::SHR:
2046 // Use only the 5 least significant bits of the shift count.
2047 __ GetLeastBitsFromInt32(r2, r2, 5);
2048 __ mov(r2, Operand(r3, LSR, r2), SetCC);
2049 // SHR is special because it is required to produce a positive answer.
2050 // The code below for writing into heap numbers isn't capable of
2051 // writing the register as an unsigned int so we go to slow case if we
2052 // hit this case.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002053 __ b(mi, &result_not_a_smi);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002054 break;
2055 case Token::SHL:
2056 // Use only the 5 least significant bits of the shift count.
2057 __ GetLeastBitsFromInt32(r2, r2, 5);
2058 __ mov(r2, Operand(r3, LSL, r2));
2059 break;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002060 default:
2061 UNREACHABLE();
2062 }
2063
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002064 // Check that the *signed* result fits in a smi.
2065 __ add(r3, r2, Operand(0x40000000), SetCC);
2066 __ b(mi, &result_not_a_smi);
2067 __ SmiTag(r0, r2);
2068 __ Ret();
2069
2070 // Allocate new heap number for result.
2071 __ bind(&result_not_a_smi);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002072 Register result = r5;
2073 if (smi_operands) {
2074 __ AllocateHeapNumber(
2075 result, scratch1, scratch2, heap_number_map, gc_required);
2076 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002077 BinaryOpStub_GenerateHeapResultAllocation(
2078 masm, result, heap_number_map, scratch1, scratch2, gc_required,
2079 mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002080 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002081
2082 // r2: Answer as signed int32.
2083 // r5: Heap number to write answer into.
2084
2085 // Nothing can go wrong now, so move the heap number to r0, which is the
2086 // result.
2087 __ mov(r0, Operand(r5));
2088
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002089 // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As
2090 // mentioned above SHR needs to always produce a positive result.
2091 __ vmov(s0, r2);
2092 if (op == Token::SHR) {
2093 __ vcvt_f64_u32(d0, s0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002094 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002095 __ vcvt_f64_s32(d0, s0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002096 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002097 __ sub(r3, r0, Operand(kHeapObjectTag));
2098 __ vstr(d0, r3, HeapNumber::kValueOffset);
2099 __ Ret();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002100 break;
2101 }
2102 default:
2103 UNREACHABLE();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002104 }
2105}
2106
2107
2108// Generate the smi code. If the operation on smis are successful this return is
2109// generated. If the result is not a smi and heap number allocation is not
2110// requested the code falls through. If number allocation is requested but a
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002111// heap number cannot be allocated the code jumps to the label gc_required.
2112void BinaryOpStub_GenerateSmiCode(
danno@chromium.org40cb8782011-05-25 07:58:50 +00002113 MacroAssembler* masm,
danno@chromium.org160a7b02011-04-18 15:51:38 +00002114 Label* use_runtime,
ager@chromium.org378b34e2011-01-28 08:04:38 +00002115 Label* gc_required,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002116 Token::Value op,
2117 BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results,
2118 OverwriteMode mode) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002119 Label not_smis;
2120
ager@chromium.org378b34e2011-01-28 08:04:38 +00002121 Register left = r1;
2122 Register right = r0;
2123 Register scratch1 = r7;
ager@chromium.org378b34e2011-01-28 08:04:38 +00002124
2125 // Perform combined smi check on both operands.
2126 __ orr(scratch1, left, Operand(right));
2127 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002128 __ JumpIfNotSmi(scratch1, &not_smis);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002129
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002130 // If the smi-smi operation results in a smi return is generated.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002131 BinaryOpStub_GenerateSmiSmiOperation(masm, op);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002132
2133 // If heap number results are possible generate the result in an allocated
2134 // heap number.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002135 if (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) {
2136 BinaryOpStub_GenerateFPOperation(
2137 masm, BinaryOpIC::UNINITIALIZED, BinaryOpIC::UNINITIALIZED, true,
2138 use_runtime, gc_required, &not_smis, op, mode);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002139 }
2140 __ bind(&not_smis);
2141}
2142
2143
danno@chromium.org40cb8782011-05-25 07:58:50 +00002144void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002145 Label not_smis, call_runtime;
2146
danno@chromium.org40cb8782011-05-25 07:58:50 +00002147 if (result_type_ == BinaryOpIC::UNINITIALIZED ||
2148 result_type_ == BinaryOpIC::SMI) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002149 // Only allow smi results.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002150 BinaryOpStub_GenerateSmiCode(
2151 masm, &call_runtime, NULL, op_, NO_HEAPNUMBER_RESULTS, mode_);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002152 } else {
2153 // Allow heap number result and don't make a transition if a heap number
2154 // cannot be allocated.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002155 BinaryOpStub_GenerateSmiCode(
2156 masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS,
2157 mode_);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002158 }
2159
2160 // Code falls through if the result is not returned as either a smi or heap
2161 // number.
2162 GenerateTypeTransition(masm);
2163
2164 __ bind(&call_runtime);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002165 GenerateRegisterArgsPush(masm);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002166 GenerateCallRuntime(masm);
2167}
2168
2169
danno@chromium.org40cb8782011-05-25 07:58:50 +00002170void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
danno@chromium.org160a7b02011-04-18 15:51:38 +00002171 Label call_runtime;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002172 ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002173 ASSERT(op_ == Token::ADD);
2174 // If both arguments are strings, call the string add stub.
2175 // Otherwise, do a transition.
2176
2177 // Registers containing left and right operands respectively.
2178 Register left = r1;
2179 Register right = r0;
2180
2181 // Test if left operand is a string.
2182 __ JumpIfSmi(left, &call_runtime);
2183 __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE);
2184 __ b(ge, &call_runtime);
2185
2186 // Test if right operand is a string.
2187 __ JumpIfSmi(right, &call_runtime);
2188 __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE);
2189 __ b(ge, &call_runtime);
2190
2191 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
2192 GenerateRegisterArgsPush(masm);
2193 __ TailCallStub(&string_add_stub);
2194
2195 __ bind(&call_runtime);
2196 GenerateTypeTransition(masm);
2197}
2198
2199
danno@chromium.org40cb8782011-05-25 07:58:50 +00002200void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002201 ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002202
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002203 Register left = r1;
2204 Register right = r0;
2205 Register scratch1 = r7;
2206 Register scratch2 = r9;
2207 DwVfpRegister double_scratch = d0;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002208
2209 Register heap_number_result = no_reg;
2210 Register heap_number_map = r6;
2211 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2212
2213 Label call_runtime;
2214 // Labels for type transition, used for wrong input or output types.
2215 // Both label are currently actually bound to the same position. We use two
2216 // different label to differentiate the cause leading to type transition.
2217 Label transition;
2218
2219 // Smi-smi fast case.
2220 Label skip;
2221 __ orr(scratch1, left, right);
2222 __ JumpIfNotSmi(scratch1, &skip);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002223 BinaryOpStub_GenerateSmiSmiOperation(masm, op_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002224 // Fall through if the result is not a smi.
2225 __ bind(&skip);
2226
2227 switch (op_) {
2228 case Token::ADD:
2229 case Token::SUB:
2230 case Token::MUL:
2231 case Token::DIV:
2232 case Token::MOD: {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002233 // It could be that only SMIs have been seen at either the left
2234 // or the right operand. For precise type feedback, patch the IC
2235 // again if this changes.
2236 if (left_type_ == BinaryOpIC::SMI) {
2237 __ JumpIfNotSmi(left, &transition);
2238 }
2239 if (right_type_ == BinaryOpIC::SMI) {
2240 __ JumpIfNotSmi(right, &transition);
2241 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00002242 // Load both operands and check that they are 32-bit integer.
2243 // Jump to type transition if they are not. The registers r0 and r1 (right
2244 // and left) are preserved for the runtime call.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002245 __ LoadNumberAsInt32Double(
2246 right, d1, heap_number_map, scratch1, d8, &transition);
2247 __ LoadNumberAsInt32Double(
2248 left, d0, heap_number_map, scratch1, d8, &transition);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002249
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002250 if (op_ != Token::MOD) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002251 Label return_heap_number;
2252 switch (op_) {
2253 case Token::ADD:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002254 __ vadd(d5, d0, d1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002255 break;
2256 case Token::SUB:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002257 __ vsub(d5, d0, d1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002258 break;
2259 case Token::MUL:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002260 __ vmul(d5, d0, d1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002261 break;
2262 case Token::DIV:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002263 __ vdiv(d5, d0, d1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002264 break;
2265 default:
2266 UNREACHABLE();
2267 }
2268
2269 if (op_ != Token::DIV) {
2270 // These operations produce an integer result.
2271 // Try to return a smi if we can.
2272 // Otherwise return a heap number if allowed, or jump to type
2273 // transition.
2274
danno@chromium.org40cb8782011-05-25 07:58:50 +00002275 if (result_type_ <= BinaryOpIC::INT32) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002276 __ TryDoubleToInt32Exact(scratch1, d5, d8);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002277 // If the ne condition is set, result does
2278 // not fit in a 32-bit integer.
2279 __ b(ne, &transition);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002280 } else {
2281 __ vcvt_s32_f64(s8, d5);
2282 __ vmov(scratch1, s8);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002283 }
2284
2285 // Check if the result fits in a smi.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002286 __ add(scratch2, scratch1, Operand(0x40000000), SetCC);
2287 // If not try to return a heap number.
2288 __ b(mi, &return_heap_number);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002289 // Check for minus zero. Return heap number for minus zero if
2290 // double results are allowed; otherwise transition.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002291 Label not_zero;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002292 __ cmp(scratch1, Operand::Zero());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002293 __ b(ne, &not_zero);
2294 __ vmov(scratch2, d5.high());
2295 __ tst(scratch2, Operand(HeapNumber::kSignMask));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002296 __ b(ne, result_type_ <= BinaryOpIC::INT32 ? &transition
2297 : &return_heap_number);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002298 __ bind(&not_zero);
2299
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002300 // Tag the result and return.
2301 __ SmiTag(r0, scratch1);
2302 __ Ret();
lrn@chromium.org7516f052011-03-30 08:52:27 +00002303 } else {
2304 // DIV just falls through to allocating a heap number.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002305 }
2306
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002307 __ bind(&return_heap_number);
2308 // Return a heap number, or fall through to type transition or runtime
2309 // call if we can't.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002310 // We are using vfp registers so r5 is available.
2311 heap_number_result = r5;
2312 BinaryOpStub_GenerateHeapResultAllocation(masm,
2313 heap_number_result,
2314 heap_number_map,
2315 scratch1,
2316 scratch2,
2317 &call_runtime,
2318 mode_);
2319 __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
2320 __ vstr(d5, r0, HeapNumber::kValueOffset);
2321 __ mov(r0, heap_number_result);
2322 __ Ret();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002323
2324 // A DIV operation expecting an integer result falls through
2325 // to type transition.
2326
2327 } else {
2328 // We preserved r0 and r1 to be able to call runtime.
2329 // Save the left value on the stack.
2330 __ Push(r5, r4);
2331
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002332 Label pop_and_call_runtime;
2333
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002334 // Allocate a heap number to store the result.
2335 heap_number_result = r5;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002336 BinaryOpStub_GenerateHeapResultAllocation(masm,
2337 heap_number_result,
2338 heap_number_map,
2339 scratch1,
2340 scratch2,
2341 &pop_and_call_runtime,
2342 mode_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002343
2344 // Load the left value from the value saved on the stack.
2345 __ Pop(r1, r0);
2346
2347 // Call the C function to handle the double operation.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002348 CallCCodeForDoubleOperation(masm, op_, heap_number_result, scratch1);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002349 if (FLAG_debug_code) {
2350 __ stop("Unreachable code.");
2351 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002352
2353 __ bind(&pop_and_call_runtime);
2354 __ Drop(2);
2355 __ b(&call_runtime);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002356 }
2357
2358 break;
2359 }
2360
2361 case Token::BIT_OR:
2362 case Token::BIT_XOR:
2363 case Token::BIT_AND:
2364 case Token::SAR:
2365 case Token::SHR:
2366 case Token::SHL: {
2367 Label return_heap_number;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002368 // Convert operands to 32-bit integers. Right in r2 and left in r3. The
2369 // registers r0 and r1 (right and left) are preserved for the runtime
2370 // call.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002371 __ LoadNumberAsInt32(left, r3, heap_number_map,
2372 scratch1, d0, d1, &transition);
2373 __ LoadNumberAsInt32(right, r2, heap_number_map,
2374 scratch1, d0, d1, &transition);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002375
2376 // The ECMA-262 standard specifies that, for shift operations, only the
2377 // 5 least significant bits of the shift value should be used.
2378 switch (op_) {
2379 case Token::BIT_OR:
2380 __ orr(r2, r3, Operand(r2));
2381 break;
2382 case Token::BIT_XOR:
2383 __ eor(r2, r3, Operand(r2));
2384 break;
2385 case Token::BIT_AND:
2386 __ and_(r2, r3, Operand(r2));
2387 break;
2388 case Token::SAR:
2389 __ and_(r2, r2, Operand(0x1f));
2390 __ mov(r2, Operand(r3, ASR, r2));
2391 break;
2392 case Token::SHR:
2393 __ and_(r2, r2, Operand(0x1f));
2394 __ mov(r2, Operand(r3, LSR, r2), SetCC);
2395 // SHR is special because it is required to produce a positive answer.
2396 // We only get a negative result if the shift value (r2) is 0.
2397 // This result cannot be respresented as a signed 32-bit integer, try
2398 // to return a heap number if we can.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002399 __ b(mi, (result_type_ <= BinaryOpIC::INT32)
2400 ? &transition
2401 : &return_heap_number);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002402 break;
2403 case Token::SHL:
2404 __ and_(r2, r2, Operand(0x1f));
2405 __ mov(r2, Operand(r3, LSL, r2));
2406 break;
2407 default:
2408 UNREACHABLE();
2409 }
2410
2411 // Check if the result fits in a smi.
2412 __ add(scratch1, r2, Operand(0x40000000), SetCC);
2413 // If not try to return a heap number. (We know the result is an int32.)
2414 __ b(mi, &return_heap_number);
2415 // Tag the result and return.
2416 __ SmiTag(r0, r2);
2417 __ Ret();
2418
2419 __ bind(&return_heap_number);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002420 heap_number_result = r5;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002421 BinaryOpStub_GenerateHeapResultAllocation(masm,
2422 heap_number_result,
2423 heap_number_map,
2424 scratch1,
2425 scratch2,
2426 &call_runtime,
2427 mode_);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002428
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002429 if (op_ != Token::SHR) {
2430 // Convert the result to a floating point value.
2431 __ vmov(double_scratch.low(), r2);
2432 __ vcvt_f64_s32(double_scratch, double_scratch.low());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002433 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002434 // The result must be interpreted as an unsigned 32-bit integer.
2435 __ vmov(double_scratch.low(), r2);
2436 __ vcvt_f64_u32(double_scratch, double_scratch.low());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002437 }
2438
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002439 // Store the result.
2440 __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
2441 __ vstr(double_scratch, r0, HeapNumber::kValueOffset);
2442 __ mov(r0, heap_number_result);
2443 __ Ret();
2444
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002445 break;
2446 }
2447
2448 default:
2449 UNREACHABLE();
2450 }
2451
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002452 // We never expect DIV to yield an integer result, so we always generate
2453 // type transition code for DIV operations expecting an integer result: the
2454 // code will fall through to this type transition.
2455 if (transition.is_linked() ||
2456 ((op_ == Token::DIV) && (result_type_ <= BinaryOpIC::INT32))) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002457 __ bind(&transition);
2458 GenerateTypeTransition(masm);
2459 }
2460
2461 __ bind(&call_runtime);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002462 GenerateRegisterArgsPush(masm);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002463 GenerateCallRuntime(masm);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002464}
2465
2466
danno@chromium.org40cb8782011-05-25 07:58:50 +00002467void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002468 Label call_runtime;
2469
2470 if (op_ == Token::ADD) {
2471 // Handle string addition here, because it is the only operation
2472 // that does not do a ToNumber conversion on the operands.
2473 GenerateAddStrings(masm);
2474 }
2475
2476 // Convert oddball arguments to numbers.
2477 Label check, done;
2478 __ CompareRoot(r1, Heap::kUndefinedValueRootIndex);
2479 __ b(ne, &check);
2480 if (Token::IsBitOp(op_)) {
2481 __ mov(r1, Operand(Smi::FromInt(0)));
2482 } else {
2483 __ LoadRoot(r1, Heap::kNanValueRootIndex);
2484 }
2485 __ jmp(&done);
2486 __ bind(&check);
2487 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
2488 __ b(ne, &done);
2489 if (Token::IsBitOp(op_)) {
2490 __ mov(r0, Operand(Smi::FromInt(0)));
2491 } else {
2492 __ LoadRoot(r0, Heap::kNanValueRootIndex);
2493 }
2494 __ bind(&done);
2495
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002496 GenerateNumberStub(masm);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002497}
2498
2499
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002500void BinaryOpStub::GenerateNumberStub(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002501 Label call_runtime, transition;
2502 BinaryOpStub_GenerateFPOperation(
2503 masm, left_type_, right_type_, false,
2504 &transition, &call_runtime, &transition, op_, mode_);
2505
2506 __ bind(&transition);
2507 GenerateTypeTransition(masm);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002508
2509 __ bind(&call_runtime);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002510 GenerateRegisterArgsPush(masm);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002511 GenerateCallRuntime(masm);
2512}
2513
2514
danno@chromium.org40cb8782011-05-25 07:58:50 +00002515void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002516 Label call_runtime, call_string_add_or_runtime, transition;
ager@chromium.org378b34e2011-01-28 08:04:38 +00002517
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002518 BinaryOpStub_GenerateSmiCode(
2519 masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS, mode_);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002520
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002521 BinaryOpStub_GenerateFPOperation(
2522 masm, left_type_, right_type_, false,
2523 &call_string_add_or_runtime, &call_runtime, &transition, op_, mode_);
2524
2525 __ bind(&transition);
2526 GenerateTypeTransition(masm);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002527
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002528 __ bind(&call_string_add_or_runtime);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002529 if (op_ == Token::ADD) {
2530 GenerateAddStrings(masm);
2531 }
2532
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002533 __ bind(&call_runtime);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002534 GenerateRegisterArgsPush(masm);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002535 GenerateCallRuntime(masm);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002536}
2537
2538
danno@chromium.org40cb8782011-05-25 07:58:50 +00002539void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002540 ASSERT(op_ == Token::ADD);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002541 Label left_not_string, call_runtime;
ager@chromium.org378b34e2011-01-28 08:04:38 +00002542
2543 Register left = r1;
2544 Register right = r0;
ager@chromium.org378b34e2011-01-28 08:04:38 +00002545
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002546 // Check if left argument is a string.
2547 __ JumpIfSmi(left, &left_not_string);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002548 __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002549 __ b(ge, &left_not_string);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002550
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002551 StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
2552 GenerateRegisterArgsPush(masm);
2553 __ TailCallStub(&string_add_left_stub);
2554
2555 // Left operand is not a string, test right.
2556 __ bind(&left_not_string);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002557 __ JumpIfSmi(right, &call_runtime);
2558 __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE);
2559 __ b(ge, &call_runtime);
2560
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002561 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002562 GenerateRegisterArgsPush(masm);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002563 __ TailCallStub(&string_add_right_stub);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002564
2565 // At least one argument is not a string.
2566 __ bind(&call_runtime);
2567}
2568
2569
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002570void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
2571 Register result,
2572 Register heap_number_map,
2573 Register scratch1,
2574 Register scratch2,
2575 Label* gc_required,
2576 OverwriteMode mode) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002577 // Code below will scratch result if allocation fails. To keep both arguments
2578 // intact for the runtime call result cannot be one of these.
2579 ASSERT(!result.is(r0) && !result.is(r1));
2580
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002581 if (mode == OVERWRITE_LEFT || mode == OVERWRITE_RIGHT) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002582 Label skip_allocation, allocated;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002583 Register overwritable_operand = mode == OVERWRITE_LEFT ? r1 : r0;
ager@chromium.org378b34e2011-01-28 08:04:38 +00002584 // If the overwritable operand is already an object, we skip the
2585 // allocation of a heap number.
2586 __ JumpIfNotSmi(overwritable_operand, &skip_allocation);
2587 // Allocate a heap number for the result.
2588 __ AllocateHeapNumber(
2589 result, scratch1, scratch2, heap_number_map, gc_required);
2590 __ b(&allocated);
2591 __ bind(&skip_allocation);
2592 // Use object holding the overwritable operand for result.
2593 __ mov(result, Operand(overwritable_operand));
2594 __ bind(&allocated);
2595 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002596 ASSERT(mode == NO_OVERWRITE);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002597 __ AllocateHeapNumber(
2598 result, scratch1, scratch2, heap_number_map, gc_required);
2599 }
2600}
2601
2602
danno@chromium.org40cb8782011-05-25 07:58:50 +00002603void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002604 __ Push(r1, r0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002605}
2606
2607
ricow@chromium.org65fae842010-08-25 15:26:24 +00002608void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002609 // Untagged case: double input in d2, double result goes
2610 // into d2.
2611 // Tagged case: tagged input on top of stack and in r0,
2612 // tagged result (heap number) goes into r0.
2613
ricow@chromium.org65fae842010-08-25 15:26:24 +00002614 Label input_not_smi;
2615 Label loaded;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002616 Label calculate;
2617 Label invalid_cache;
2618 const Register scratch0 = r9;
2619 const Register scratch1 = r7;
2620 const Register cache_entry = r0;
2621 const bool tagged = (argument_type_ == TAGGED);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002622
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002623 if (tagged) {
2624 // Argument is a number and is on stack and in r0.
2625 // Load argument and check if it is a smi.
2626 __ JumpIfNotSmi(r0, &input_not_smi);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002627
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002628 // Input is a smi. Convert to double and load the low and high words
2629 // of the double into r2, r3.
2630 __ IntegerToDoubleConversionWithVFP3(r0, r3, r2);
2631 __ b(&loaded);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002632
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002633 __ bind(&input_not_smi);
2634 // Check if input is a HeapNumber.
2635 __ CheckMap(r0,
2636 r1,
2637 Heap::kHeapNumberMapRootIndex,
2638 &calculate,
2639 DONT_DO_SMI_CHECK);
2640 // Input is a HeapNumber. Load it to a double register and store the
2641 // low and high words into r2, r3.
2642 __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
2643 __ vmov(r2, r3, d0);
2644 } else {
2645 // Input is untagged double in d2. Output goes to d2.
2646 __ vmov(r2, r3, d2);
2647 }
2648 __ bind(&loaded);
2649 // r2 = low 32 bits of double value
2650 // r3 = high 32 bits of double value
2651 // Compute hash (the shifts are arithmetic):
2652 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
2653 __ eor(r1, r2, Operand(r3));
2654 __ eor(r1, r1, Operand(r1, ASR, 16));
2655 __ eor(r1, r1, Operand(r1, ASR, 8));
2656 ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
2657 __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002658
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002659 // r2 = low 32 bits of double value.
2660 // r3 = high 32 bits of double value.
2661 // r1 = TranscendentalCache::hash(double value).
2662 Isolate* isolate = masm->isolate();
2663 ExternalReference cache_array =
2664 ExternalReference::transcendental_cache_array_address(isolate);
2665 __ mov(cache_entry, Operand(cache_array));
2666 // cache_entry points to cache array.
2667 int cache_array_index
2668 = type_ * sizeof(isolate->transcendental_cache()->caches_[0]);
2669 __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index));
2670 // r0 points to the cache for the type type_.
2671 // If NULL, the cache hasn't been initialized yet, so go through runtime.
2672 __ cmp(cache_entry, Operand::Zero());
2673 __ b(eq, &invalid_cache);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002674
2675#ifdef DEBUG
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002676 // Check that the layout of cache elements match expectations.
2677 { TranscendentalCache::SubCache::Element test_elem[2];
2678 char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
2679 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
2680 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
2681 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
2682 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
2683 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
2684 CHECK_EQ(0, elem_in0 - elem_start);
2685 CHECK_EQ(kIntSize, elem_in1 - elem_start);
2686 CHECK_EQ(2 * kIntSize, elem_out - elem_start);
2687 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002688#endif
2689
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002690 // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12].
2691 __ add(r1, r1, Operand(r1, LSL, 1));
2692 __ add(cache_entry, cache_entry, Operand(r1, LSL, 2));
2693 // Check if cache matches: Double value is stored in uint32_t[2] array.
2694 __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit());
2695 __ cmp(r2, r4);
2696 __ cmp(r3, r5, eq);
2697 __ b(ne, &calculate);
2698 // Cache hit. Load result, cleanup and return.
2699 Counters* counters = masm->isolate()->counters();
2700 __ IncrementCounter(
2701 counters->transcendental_cache_hit(), 1, scratch0, scratch1);
2702 if (tagged) {
2703 // Pop input value from stack and load result into r0.
2704 __ pop();
2705 __ mov(r0, Operand(r6));
2706 } else {
2707 // Load result into d2.
2708 __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
2709 }
2710 __ Ret();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002711
2712 __ bind(&calculate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002713 __ IncrementCounter(
2714 counters->transcendental_cache_miss(), 1, scratch0, scratch1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002715 if (tagged) {
2716 __ bind(&invalid_cache);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002717 ExternalReference runtime_function =
2718 ExternalReference(RuntimeFunction(), masm->isolate());
2719 __ TailCallExternalReference(runtime_function, 1, 1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002720 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002721 Label no_update;
2722 Label skip_cache;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002723
2724 // Call C function to calculate the result and update the cache.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002725 // r0: precalculated cache entry address.
2726 // r2 and r3: parts of the double value.
2727 // Store r0, r2 and r3 on stack for later before calling C function.
2728 __ Push(r3, r2, cache_entry);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002729 GenerateCallCFunction(masm, scratch0);
2730 __ GetCFunctionDoubleResult(d2);
2731
2732 // Try to update the cache. If we cannot allocate a
2733 // heap number, we return the result without updating.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002734 __ Pop(r3, r2, cache_entry);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002735 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex);
2736 __ AllocateHeapNumber(r6, scratch0, scratch1, r5, &no_update);
2737 __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
2738 __ stm(ia, cache_entry, r2.bit() | r3.bit() | r6.bit());
2739 __ Ret();
2740
2741 __ bind(&invalid_cache);
2742 // The cache is invalid. Call runtime which will recreate the
2743 // cache.
2744 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex);
2745 __ AllocateHeapNumber(r0, scratch0, scratch1, r5, &skip_cache);
2746 __ vstr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002747 {
2748 FrameScope scope(masm, StackFrame::INTERNAL);
2749 __ push(r0);
2750 __ CallRuntime(RuntimeFunction(), 1);
2751 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002752 __ vldr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset));
2753 __ Ret();
2754
2755 __ bind(&skip_cache);
2756 // Call C function to calculate the result and answer directly
2757 // without updating the cache.
2758 GenerateCallCFunction(masm, scratch0);
2759 __ GetCFunctionDoubleResult(d2);
2760 __ bind(&no_update);
2761
2762 // We return the value in d2 without adding it to the cache, but
2763 // we cause a scavenging GC so that future allocations will succeed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002764 {
2765 FrameScope scope(masm, StackFrame::INTERNAL);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002766
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002767 // Allocate an aligned object larger than a HeapNumber.
2768 ASSERT(4 * kPointerSize >= HeapNumber::kSize);
2769 __ mov(scratch0, Operand(4 * kPointerSize));
2770 __ push(scratch0);
2771 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
2772 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002773 __ Ret();
2774 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002775}
ricow@chromium.org65fae842010-08-25 15:26:24 +00002776
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002777
2778void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm,
2779 Register scratch) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002780 Isolate* isolate = masm->isolate();
2781
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002782 __ push(lr);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002783 __ PrepareCallCFunction(0, 1, scratch);
2784 if (masm->use_eabi_hardfloat()) {
2785 __ vmov(d0, d2);
2786 } else {
2787 __ vmov(r0, r1, d2);
2788 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002789 AllowExternalCallThatCantCauseGC scope(masm);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002790 switch (type_) {
2791 case TranscendentalCache::SIN:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002792 __ CallCFunction(ExternalReference::math_sin_double_function(isolate),
2793 0, 1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002794 break;
2795 case TranscendentalCache::COS:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002796 __ CallCFunction(ExternalReference::math_cos_double_function(isolate),
2797 0, 1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002798 break;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002799 case TranscendentalCache::TAN:
2800 __ CallCFunction(ExternalReference::math_tan_double_function(isolate),
2801 0, 1);
2802 break;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002803 case TranscendentalCache::LOG:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002804 __ CallCFunction(ExternalReference::math_log_double_function(isolate),
2805 0, 1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002806 break;
2807 default:
2808 UNIMPLEMENTED();
2809 break;
2810 }
2811 __ pop(lr);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002812}
2813
2814
2815Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
2816 switch (type_) {
2817 // Add more cases when necessary.
2818 case TranscendentalCache::SIN: return Runtime::kMath_sin;
2819 case TranscendentalCache::COS: return Runtime::kMath_cos;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002820 case TranscendentalCache::TAN: return Runtime::kMath_tan;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002821 case TranscendentalCache::LOG: return Runtime::kMath_log;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002822 default:
2823 UNIMPLEMENTED();
2824 return Runtime::kAbort;
2825 }
2826}
2827
2828
2829void StackCheckStub::Generate(MacroAssembler* masm) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00002830 __ TailCallRuntime(Runtime::kStackGuard, 0, 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002831}
2832
2833
yangguo@chromium.org56454712012-02-16 15:33:53 +00002834void InterruptStub::Generate(MacroAssembler* masm) {
2835 __ TailCallRuntime(Runtime::kInterrupt, 0, 1);
2836}
2837
2838
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002839void MathPowStub::Generate(MacroAssembler* masm) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002840 const Register base = r1;
2841 const Register exponent = r2;
2842 const Register heapnumbermap = r5;
2843 const Register heapnumber = r0;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002844 const DwVfpRegister double_base = d1;
2845 const DwVfpRegister double_exponent = d2;
2846 const DwVfpRegister double_result = d3;
2847 const DwVfpRegister double_scratch = d0;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002848 const SwVfpRegister single_scratch = s0;
2849 const Register scratch = r9;
2850 const Register scratch2 = r7;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002851
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002852 Label call_runtime, done, int_exponent;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002853 if (exponent_type_ == ON_STACK) {
2854 Label base_is_smi, unpack_exponent;
2855 // The exponent and base are supplied as arguments on the stack.
2856 // This can only happen if the stub is called from non-optimized code.
2857 // Load input parameters from stack to double registers.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002858 __ ldr(base, MemOperand(sp, 1 * kPointerSize));
2859 __ ldr(exponent, MemOperand(sp, 0 * kPointerSize));
2860
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002861 __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002862
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002863 __ UntagAndJumpIfSmi(scratch, base, &base_is_smi);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002864 __ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset));
2865 __ cmp(scratch, heapnumbermap);
2866 __ b(ne, &call_runtime);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002867
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002868 __ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
2869 __ jmp(&unpack_exponent);
2870
2871 __ bind(&base_is_smi);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002872 __ vmov(single_scratch, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002873 __ vcvt_f64_s32(double_base, single_scratch);
2874 __ bind(&unpack_exponent);
2875
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002876 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002877
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002878 __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset));
2879 __ cmp(scratch, heapnumbermap);
2880 __ b(ne, &call_runtime);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002881 __ vldr(double_exponent,
2882 FieldMemOperand(exponent, HeapNumber::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002883 } else if (exponent_type_ == TAGGED) {
2884 // Base is already in double_base.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002885 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002886
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002887 __ vldr(double_exponent,
2888 FieldMemOperand(exponent, HeapNumber::kValueOffset));
2889 }
2890
2891 if (exponent_type_ != INTEGER) {
2892 Label int_exponent_convert;
2893 // Detect integer exponents stored as double.
2894 __ vcvt_u32_f64(single_scratch, double_exponent);
2895 // We do not check for NaN or Infinity here because comparing numbers on
2896 // ARM correctly distinguishes NaNs. We end up calling the built-in.
2897 __ vcvt_f64_u32(double_scratch, single_scratch);
2898 __ VFPCompareAndSetFlags(double_scratch, double_exponent);
2899 __ b(eq, &int_exponent_convert);
2900
2901 if (exponent_type_ == ON_STACK) {
2902 // Detect square root case. Crankshaft detects constant +/-0.5 at
2903 // compile time and uses DoMathPowHalf instead. We then skip this check
2904 // for non-constant cases of +/-0.5 as these hardly occur.
2905 Label not_plus_half;
2906
2907 // Test for 0.5.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002908 __ vmov(double_scratch, 0.5, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002909 __ VFPCompareAndSetFlags(double_exponent, double_scratch);
2910 __ b(ne, &not_plus_half);
2911
2912 // Calculates square root of base. Check for the special case of
2913 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002914 __ vmov(double_scratch, -V8_INFINITY, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002915 __ VFPCompareAndSetFlags(double_base, double_scratch);
2916 __ vneg(double_result, double_scratch, eq);
2917 __ b(eq, &done);
2918
2919 // Add +0 to convert -0 to +0.
2920 __ vadd(double_scratch, double_base, kDoubleRegZero);
2921 __ vsqrt(double_result, double_scratch);
2922 __ jmp(&done);
2923
2924 __ bind(&not_plus_half);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002925 __ vmov(double_scratch, -0.5, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002926 __ VFPCompareAndSetFlags(double_exponent, double_scratch);
2927 __ b(ne, &call_runtime);
2928
2929 // Calculates square root of base. Check for the special case of
2930 // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002931 __ vmov(double_scratch, -V8_INFINITY, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002932 __ VFPCompareAndSetFlags(double_base, double_scratch);
2933 __ vmov(double_result, kDoubleRegZero, eq);
2934 __ b(eq, &done);
2935
2936 // Add +0 to convert -0 to +0.
2937 __ vadd(double_scratch, double_base, kDoubleRegZero);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002938 __ vmov(double_result, 1.0, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002939 __ vsqrt(double_scratch, double_scratch);
2940 __ vdiv(double_result, double_result, double_scratch);
2941 __ jmp(&done);
2942 }
2943
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002944 __ push(lr);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002945 {
2946 AllowExternalCallThatCantCauseGC scope(masm);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002947 __ PrepareCallCFunction(0, 2, scratch);
2948 __ SetCallCDoubleArguments(double_base, double_exponent);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002949 __ CallCFunction(
2950 ExternalReference::power_double_double_function(masm->isolate()),
2951 0, 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002952 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002953 __ pop(lr);
2954 __ GetCFunctionDoubleResult(double_result);
2955 __ jmp(&done);
2956
2957 __ bind(&int_exponent_convert);
2958 __ vcvt_u32_f64(single_scratch, double_exponent);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002959 __ vmov(scratch, single_scratch);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002960 }
2961
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002962 // Calculate power with integer exponent.
2963 __ bind(&int_exponent);
2964
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002965 // Get two copies of exponent in the registers scratch and exponent.
2966 if (exponent_type_ == INTEGER) {
2967 __ mov(scratch, exponent);
2968 } else {
2969 // Exponent has previously been stored into scratch as untagged integer.
2970 __ mov(exponent, scratch);
2971 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002972 __ vmov(double_scratch, double_base); // Back up base.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002973 __ vmov(double_result, 1.0, scratch2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002974
2975 // Get absolute value of exponent.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002976 __ cmp(scratch, Operand::Zero());
2977 __ mov(scratch2, Operand::Zero(), LeaveCC, mi);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002978 __ sub(scratch, scratch2, scratch, LeaveCC, mi);
2979
2980 Label while_true;
2981 __ bind(&while_true);
2982 __ mov(scratch, Operand(scratch, ASR, 1), SetCC);
2983 __ vmul(double_result, double_result, double_scratch, cs);
2984 __ vmul(double_scratch, double_scratch, double_scratch, ne);
2985 __ b(ne, &while_true);
2986
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002987 __ cmp(exponent, Operand::Zero());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002988 __ b(ge, &done);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002989 __ vmov(double_scratch, 1.0, scratch);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002990 __ vdiv(double_result, double_scratch, double_result);
2991 // Test whether result is zero. Bail out to check for subnormal result.
2992 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
2993 __ VFPCompareAndSetFlags(double_result, 0.0);
2994 __ b(ne, &done);
2995 // double_exponent may not containe the exponent value if the input was a
2996 // smi. We set it with exponent value before bailing out.
2997 __ vmov(single_scratch, exponent);
2998 __ vcvt_f64_s32(double_exponent, single_scratch);
2999
3000 // Returning or bailing out.
3001 Counters* counters = masm->isolate()->counters();
3002 if (exponent_type_ == ON_STACK) {
3003 // The arguments are still on the stack.
3004 __ bind(&call_runtime);
3005 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3006
3007 // The stub is called from non-optimized code, which expects the result
3008 // as heap number in exponent.
3009 __ bind(&done);
3010 __ AllocateHeapNumber(
3011 heapnumber, scratch, scratch2, heapnumbermap, &call_runtime);
3012 __ vstr(double_result,
3013 FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
3014 ASSERT(heapnumber.is(r0));
3015 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
3016 __ Ret(2);
3017 } else {
3018 __ push(lr);
3019 {
3020 AllowExternalCallThatCantCauseGC scope(masm);
3021 __ PrepareCallCFunction(0, 2, scratch);
3022 __ SetCallCDoubleArguments(double_base, double_exponent);
3023 __ CallCFunction(
3024 ExternalReference::power_double_double_function(masm->isolate()),
3025 0, 2);
3026 }
3027 __ pop(lr);
3028 __ GetCFunctionDoubleResult(double_result);
3029
3030 __ bind(&done);
3031 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
3032 __ Ret();
3033 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003034}
3035
3036
3037bool CEntryStub::NeedsImmovableCode() {
3038 return true;
3039}
3040
3041
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003042bool CEntryStub::IsPregenerated() {
3043 return (!save_doubles_ || ISOLATE->fp_stubs_generated()) &&
3044 result_size_ == 1;
3045}
3046
3047
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003048void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
3049 CEntryStub::GenerateAheadOfTime(isolate);
3050 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
3051 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003052 StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003053 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003054 if (FLAG_optimize_constructed_arrays) {
3055 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
3056 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003057}
3058
3059
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003060void CodeStub::GenerateFPStubs(Isolate* isolate) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003061 SaveFPRegsMode mode = kSaveFPRegs;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003062 CEntryStub save_doubles(1, mode);
3063 StoreBufferOverflowStub stub(mode);
3064 // These stubs might already be in the snapshot, detect that and don't
3065 // regenerate, which would lead to code stub initialization state being messed
3066 // up.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003067 Code* save_doubles_code;
3068 if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) {
3069 save_doubles_code = *save_doubles.GetCode(isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003070 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003071 Code* store_buffer_overflow_code;
3072 if (!stub.FindCodeInCache(&store_buffer_overflow_code, isolate)) {
3073 store_buffer_overflow_code = *stub.GetCode(isolate);
3074 }
3075 save_doubles_code->set_is_pregenerated(true);
3076 store_buffer_overflow_code->set_is_pregenerated(true);
ulan@chromium.org750145a2013-03-07 15:14:13 +00003077 isolate->set_fp_stubs_generated(true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003078}
3079
3080
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003081void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003082 CEntryStub stub(1, kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003083 Handle<Code> code = stub.GetCode(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003084 code->set_is_pregenerated(true);
3085}
3086
3087
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003088static void JumpIfOOM(MacroAssembler* masm,
3089 Register value,
3090 Register scratch,
3091 Label* oom_label) {
3092 STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
3093 STATIC_ASSERT(kFailureTag == 3);
3094 __ and_(scratch, value, Operand(0xf));
3095 __ cmp(scratch, Operand(0xf));
3096 __ b(eq, oom_label);
3097}
3098
3099
ricow@chromium.org65fae842010-08-25 15:26:24 +00003100void CEntryStub::GenerateCore(MacroAssembler* masm,
3101 Label* throw_normal_exception,
3102 Label* throw_termination_exception,
3103 Label* throw_out_of_memory_exception,
3104 bool do_gc,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003105 bool always_allocate) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003106 // r0: result parameter for PerformGC, if any
3107 // r4: number of arguments including receiver (C callee-saved)
3108 // r5: pointer to builtin function (C callee-saved)
3109 // r6: pointer to the first argument (C callee-saved)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003110 Isolate* isolate = masm->isolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003111
3112 if (do_gc) {
3113 // Passing r0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003114 __ PrepareCallCFunction(1, 0, r1);
3115 __ CallCFunction(ExternalReference::perform_gc_function(isolate),
3116 1, 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003117 }
3118
3119 ExternalReference scope_depth =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003120 ExternalReference::heap_always_allocate_scope_depth(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003121 if (always_allocate) {
3122 __ mov(r0, Operand(scope_depth));
3123 __ ldr(r1, MemOperand(r0));
3124 __ add(r1, r1, Operand(1));
3125 __ str(r1, MemOperand(r0));
3126 }
3127
3128 // Call C built-in.
3129 // r0 = argc, r1 = argv
3130 __ mov(r0, Operand(r4));
3131 __ mov(r1, Operand(r6));
3132
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003133#if defined(V8_HOST_ARCH_ARM)
ricow@chromium.org65fae842010-08-25 15:26:24 +00003134 int frame_alignment = MacroAssembler::ActivationFrameAlignment();
3135 int frame_alignment_mask = frame_alignment - 1;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003136 if (FLAG_debug_code) {
3137 if (frame_alignment > kPointerSize) {
3138 Label alignment_as_expected;
3139 ASSERT(IsPowerOf2(frame_alignment));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003140 __ tst(sp, Operand(frame_alignment_mask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003141 __ b(eq, &alignment_as_expected);
3142 // Don't use Check here, as it will call Runtime_Abort re-entering here.
3143 __ stop("Unexpected alignment");
3144 __ bind(&alignment_as_expected);
3145 }
3146 }
3147#endif
3148
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003149 __ mov(r2, Operand(ExternalReference::isolate_address(isolate)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003150
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003151 // To let the GC traverse the return address of the exit frames, we need to
3152 // know where the return address is. The CEntryStub is unmovable, so
3153 // we can store the address on the stack to be able to find it again and
3154 // we never have to restore it, because it will not change.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003155 // Compute the return address in lr to return to after the jump below. Pc is
3156 // already at '+ 8' from the current instruction but return is after three
3157 // instructions so add another 4 to pc to get the return address.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003158 {
3159 // Prevent literal pool emission before return address.
3160 Assembler::BlockConstPoolScope block_const_pool(masm);
3161 masm->add(lr, pc, Operand(4));
3162 __ str(lr, MemOperand(sp, 0));
3163 masm->Jump(r5);
3164 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003165
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003166 __ VFPEnsureFPSCRState(r2);
3167
ricow@chromium.org65fae842010-08-25 15:26:24 +00003168 if (always_allocate) {
3169 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
3170 // though (contain the result).
3171 __ mov(r2, Operand(scope_depth));
3172 __ ldr(r3, MemOperand(r2));
3173 __ sub(r3, r3, Operand(1));
3174 __ str(r3, MemOperand(r2));
3175 }
3176
3177 // check for failure result
3178 Label failure_returned;
3179 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
3180 // Lower 2 bits of r2 are 0 iff r0 has failure tag.
3181 __ add(r2, r0, Operand(1));
3182 __ tst(r2, Operand(kFailureTagMask));
3183 __ b(eq, &failure_returned);
3184
3185 // Exit C frame and return.
3186 // r0:r1: result
3187 // sp: stack pointer
3188 // fp: frame pointer
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003189 // Callee-saved register r4 still holds argc.
3190 __ LeaveExitFrame(save_doubles_, r4);
3191 __ mov(pc, lr);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003192
3193 // check if we should retry or throw exception
3194 Label retry;
3195 __ bind(&failure_returned);
3196 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
3197 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
3198 __ b(eq, &retry);
3199
3200 // Special handling of out of memory exceptions.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003201 JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003202
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003203 // Retrieve the pending exception.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003204 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003205 isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003206 __ ldr(r0, MemOperand(ip));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003207
3208 // See if we just retrieved an OOM exception.
3209 JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
3210
3211 // Clear the pending exception.
3212 __ mov(r3, Operand(isolate->factory()->the_hole_value()));
3213 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
3214 isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003215 __ str(r3, MemOperand(ip));
3216
3217 // Special handling of termination exceptions which are uncatchable
3218 // by javascript code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003219 __ cmp(r0, Operand(isolate->factory()->termination_exception()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003220 __ b(eq, throw_termination_exception);
3221
3222 // Handle normal exception.
3223 __ jmp(throw_normal_exception);
3224
3225 __ bind(&retry); // pass last failure (r0) as parameter (r0) when retrying
3226}
3227
3228
3229void CEntryStub::Generate(MacroAssembler* masm) {
3230 // Called from JavaScript; parameters are on stack as if calling JS function
3231 // r0: number of arguments including receiver
3232 // r1: pointer to builtin function
3233 // fp: frame pointer (restored after C call)
3234 // sp: stack pointer (restored as callee's sp after C call)
3235 // cp: current context (C callee-saved)
3236
3237 // Result returned in r0 or r0+r1 by default.
3238
3239 // NOTE: Invocations of builtins may return failure objects
3240 // instead of a proper result. The builtin entry handles
3241 // this by performing a garbage collection and retrying the
3242 // builtin once.
3243
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003244 // Compute the argv pointer in a callee-saved register.
3245 __ add(r6, sp, Operand(r0, LSL, kPointerSizeLog2));
3246 __ sub(r6, r6, Operand(kPointerSize));
3247
ricow@chromium.org65fae842010-08-25 15:26:24 +00003248 // Enter the exit frame that transitions from JavaScript to C++.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003249 FrameScope scope(masm, StackFrame::MANUAL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003250 __ EnterExitFrame(save_doubles_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003251
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003252 // Set up argc and the builtin function in callee-saved registers.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003253 __ mov(r4, Operand(r0));
3254 __ mov(r5, Operand(r1));
3255
ricow@chromium.org65fae842010-08-25 15:26:24 +00003256 // r4: number of arguments (C callee-saved)
3257 // r5: pointer to builtin function (C callee-saved)
3258 // r6: pointer to first argument (C callee-saved)
3259
3260 Label throw_normal_exception;
3261 Label throw_termination_exception;
3262 Label throw_out_of_memory_exception;
3263
3264 // Call into the runtime system.
3265 GenerateCore(masm,
3266 &throw_normal_exception,
3267 &throw_termination_exception,
3268 &throw_out_of_memory_exception,
3269 false,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003270 false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003271
3272 // Do space-specific GC and retry runtime call.
3273 GenerateCore(masm,
3274 &throw_normal_exception,
3275 &throw_termination_exception,
3276 &throw_out_of_memory_exception,
3277 true,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003278 false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003279
3280 // Do full GC and retry runtime call one final time.
3281 Failure* failure = Failure::InternalError();
3282 __ mov(r0, Operand(reinterpret_cast<int32_t>(failure)));
3283 GenerateCore(masm,
3284 &throw_normal_exception,
3285 &throw_termination_exception,
3286 &throw_out_of_memory_exception,
3287 true,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003288 true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003289
3290 __ bind(&throw_out_of_memory_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003291 // Set external caught exception to false.
3292 Isolate* isolate = masm->isolate();
3293 ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
3294 isolate);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003295 __ mov(r0, Operand(false, RelocInfo::NONE32));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003296 __ mov(r2, Operand(external_caught));
3297 __ str(r0, MemOperand(r2));
3298
3299 // Set pending exception and r0 to out of memory exception.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003300 Label already_have_failure;
3301 JumpIfOOM(masm, r0, ip, &already_have_failure);
3302 Failure* out_of_memory = Failure::OutOfMemoryException(0x1);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003303 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003304 __ bind(&already_have_failure);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003305 __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
3306 isolate)));
3307 __ str(r0, MemOperand(r2));
3308 // Fall through to the next label.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003309
3310 __ bind(&throw_termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003311 __ ThrowUncatchable(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003312
3313 __ bind(&throw_normal_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003314 __ Throw(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003315}
3316
3317
3318void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
3319 // r0: code entry
3320 // r1: function
3321 // r2: receiver
3322 // r3: argc
3323 // [sp+0]: argv
3324
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003325 Label invoke, handler_entry, exit;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003326
3327 // Called from C, so do not pop argc and args on exit (preserve sp)
3328 // No need to save register-passed args
3329 // Save callee-saved registers (incl. cp and fp), sp, and lr
3330 __ stm(db_w, sp, kCalleeSaved | lr.bit());
3331
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003332 // Save callee-saved vfp registers.
3333 __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
3334 // Set up the reserved register for 0.0.
3335 __ vmov(kDoubleRegZero, 0.0);
3336 __ VFPEnsureFPSCRState(r4);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00003337
ricow@chromium.org65fae842010-08-25 15:26:24 +00003338 // Get address of argv, see stm above.
3339 // r0: code entry
3340 // r1: function
3341 // r2: receiver
3342 // r3: argc
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00003343
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003344 // Set up argv in r4.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00003345 int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003346 offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00003347 __ ldr(r4, MemOperand(sp, offset_to_argv));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003348
3349 // Push a frame with special values setup to mark it as an entry frame.
3350 // r0: code entry
3351 // r1: function
3352 // r2: receiver
3353 // r3: argc
3354 // r4: argv
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003355 Isolate* isolate = masm->isolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003356 __ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used.
3357 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
3358 __ mov(r7, Operand(Smi::FromInt(marker)));
3359 __ mov(r6, Operand(Smi::FromInt(marker)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003360 __ mov(r5,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003361 Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003362 __ ldr(r5, MemOperand(r5));
3363 __ Push(r8, r7, r6, r5);
3364
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003365 // Set up frame pointer for the frame to be pushed.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003366 __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
3367
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003368 // If this is the outermost JS call, set js_entry_sp value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003369 Label non_outermost_js;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003370 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003371 __ mov(r5, Operand(ExternalReference(js_entry_sp)));
3372 __ ldr(r6, MemOperand(r5));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003373 __ cmp(r6, Operand::Zero());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003374 __ b(ne, &non_outermost_js);
3375 __ str(fp, MemOperand(r5));
3376 __ mov(ip, Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
3377 Label cont;
3378 __ b(&cont);
3379 __ bind(&non_outermost_js);
3380 __ mov(ip, Operand(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
3381 __ bind(&cont);
3382 __ push(ip);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003383
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003384 // Jump to a faked try block that does the invoke, with a faked catch
3385 // block that sets the pending exception.
3386 __ jmp(&invoke);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003387
3388 // Block literal pool emission whilst taking the position of the handler
3389 // entry. This avoids making the assumption that literal pools are always
3390 // emitted after an instruction is emitted, rather than before.
3391 {
3392 Assembler::BlockConstPoolScope block_const_pool(masm);
3393 __ bind(&handler_entry);
3394 handler_offset_ = handler_entry.pos();
3395 // Caught exception: Store result (exception) in the pending exception
3396 // field in the JSEnv and return a failure sentinel. Coming in here the
3397 // fp will be invalid because the PushTryHandler below sets it to 0 to
3398 // signal the existence of the JSEntry frame.
3399 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
3400 isolate)));
3401 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003402 __ str(r0, MemOperand(ip));
3403 __ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
3404 __ b(&exit);
3405
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003406 // Invoke: Link this frame into the handler chain. There's only one
3407 // handler block in this code object, so its index is 0.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003408 __ bind(&invoke);
3409 // Must preserve r0-r4, r5-r7 are available.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00003410 __ PushTryHandler(StackHandler::JS_ENTRY, 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003411 // If an exception not caught by another handler occurs, this handler
3412 // returns control to the code after the bl(&invoke) above, which
3413 // restores all kCalleeSaved registers (including cp and fp) to their
3414 // saved values before returning a failure to C.
3415
3416 // Clear any pending exceptions.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003417 __ mov(r5, Operand(isolate->factory()->the_hole_value()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003418 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003419 isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003420 __ str(r5, MemOperand(ip));
3421
3422 // Invoke the function by calling through JS entry trampoline builtin.
3423 // Notice that we cannot store a reference to the trampoline code directly in
3424 // this stub, because runtime stubs are not traversed when doing GC.
3425
3426 // Expected registers by Builtins::JSEntryTrampoline
3427 // r0: code entry
3428 // r1: function
3429 // r2: receiver
3430 // r3: argc
3431 // r4: argv
3432 if (is_construct) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003433 ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003434 isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003435 __ mov(ip, Operand(construct_entry));
3436 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003437 ExternalReference entry(Builtins::kJSEntryTrampoline, isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003438 __ mov(ip, Operand(entry));
3439 }
3440 __ ldr(ip, MemOperand(ip)); // deref address
3441
3442 // Branch and link to JSEntryTrampoline. We don't use the double underscore
3443 // macro for the add instruction because we don't want the coverage tool
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003444 // inserting instructions here after we read the pc. We block literal pool
3445 // emission for the same reason.
3446 {
3447 Assembler::BlockConstPoolScope block_const_pool(masm);
3448 __ mov(lr, Operand(pc));
3449 masm->add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
3450 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003451
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003452 // Unlink this frame from the handler chain.
3453 __ PopTryHandler();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003454
3455 __ bind(&exit); // r0 holds result
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003456 // Check if the current stack frame is marked as the outermost JS frame.
3457 Label non_outermost_js_2;
3458 __ pop(r5);
3459 __ cmp(r5, Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
3460 __ b(ne, &non_outermost_js_2);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003461 __ mov(r6, Operand::Zero());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003462 __ mov(r5, Operand(ExternalReference(js_entry_sp)));
3463 __ str(r6, MemOperand(r5));
3464 __ bind(&non_outermost_js_2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003465
ricow@chromium.org65fae842010-08-25 15:26:24 +00003466 // Restore the top frame descriptors from the stack.
3467 __ pop(r3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003468 __ mov(ip,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003469 Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003470 __ str(r3, MemOperand(ip));
3471
3472 // Reset the stack to the callee saved registers.
3473 __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
3474
3475 // Restore callee-saved registers and return.
3476#ifdef DEBUG
3477 if (FLAG_debug_code) {
3478 __ mov(lr, Operand(pc));
3479 }
3480#endif
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00003481
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003482 // Restore callee-saved vfp registers.
3483 __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00003484
ricow@chromium.org65fae842010-08-25 15:26:24 +00003485 __ ldm(ia_w, sp, kCalleeSaved | pc.bit());
3486}
3487
3488
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003489// Uses registers r0 to r4.
3490// Expected input (depending on whether args are in registers or on the stack):
3491// * object: r0 or at sp + 1 * kPointerSize.
3492// * function: r1 or at sp.
3493//
3494// An inlined call site may have been generated before calling this stub.
3495// In this case the offset to the inline site to patch is passed on the stack,
3496// in the safepoint slot for register r4.
3497// (See LCodeGen::DoInstanceOfKnownGlobal)
ricow@chromium.org65fae842010-08-25 15:26:24 +00003498void InstanceofStub::Generate(MacroAssembler* masm) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003499 // Call site inlining and patching implies arguments in registers.
3500 ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck());
3501 // ReturnTrueFalse is only implemented for inlined call sites.
3502 ASSERT(!ReturnTrueFalseObject() || HasCallSiteInlineCheck());
3503
whesse@chromium.org023421e2010-12-21 12:19:12 +00003504 // Fixed register usage throughout the stub:
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003505 const Register object = r0; // Object (lhs).
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003506 Register map = r3; // Map of the object.
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003507 const Register function = r1; // Function (rhs).
whesse@chromium.org023421e2010-12-21 12:19:12 +00003508 const Register prototype = r4; // Prototype of the function.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003509 const Register inline_site = r9;
whesse@chromium.org023421e2010-12-21 12:19:12 +00003510 const Register scratch = r2;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003511
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003512 const int32_t kDeltaToLoadBoolResult = 4 * kPointerSize;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003513
whesse@chromium.org023421e2010-12-21 12:19:12 +00003514 Label slow, loop, is_instance, is_not_instance, not_js_object;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003515
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003516 if (!HasArgsInRegisters()) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003517 __ ldr(object, MemOperand(sp, 1 * kPointerSize));
3518 __ ldr(function, MemOperand(sp, 0));
whesse@chromium.org023421e2010-12-21 12:19:12 +00003519 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003520
whesse@chromium.org023421e2010-12-21 12:19:12 +00003521 // Check that the left hand is a JS object and load map.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003522 __ JumpIfSmi(object, &not_js_object);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003523 __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003524
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003525 // If there is a call site cache don't look in the global cache, but do the
3526 // real lookup and update the call site cache.
3527 if (!HasCallSiteInlineCheck()) {
3528 Label miss;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003529 __ CompareRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003530 __ b(ne, &miss);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003531 __ CompareRoot(map, Heap::kInstanceofCacheMapRootIndex);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003532 __ b(ne, &miss);
3533 __ LoadRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
3534 __ Ret(HasArgsInRegisters() ? 0 : 2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003535
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003536 __ bind(&miss);
3537 }
3538
3539 // Get the prototype of the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003540 __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003541
3542 // Check that the function prototype is a JS object.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003543 __ JumpIfSmi(prototype, &slow);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003544 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003545
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003546 // Update the global instanceof or call site inlined cache with the current
3547 // map and function. The cached answer will be set when it is known below.
3548 if (!HasCallSiteInlineCheck()) {
3549 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
3550 __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);
3551 } else {
3552 ASSERT(HasArgsInRegisters());
3553 // Patch the (relocated) inlined map check.
3554
3555 // The offset was stored in r4 safepoint slot.
3556 // (See LCodeGen::DoDeferredLInstanceOfKnownGlobal)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003557 __ LoadFromSafepointRegisterSlot(scratch, r4);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003558 __ sub(inline_site, lr, scratch);
3559 // Get the map location in scratch and patch it.
3560 __ GetRelocatedValueLocation(inline_site, scratch);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003561 __ ldr(scratch, MemOperand(scratch));
3562 __ str(map, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003563 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003564
3565 // Register mapping: r3 is object map and r4 is function prototype.
3566 // Get prototype of object into r2.
whesse@chromium.org023421e2010-12-21 12:19:12 +00003567 __ ldr(scratch, FieldMemOperand(map, Map::kPrototypeOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003568
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003569 // We don't need map any more. Use it as a scratch register.
3570 Register scratch2 = map;
3571 map = no_reg;
3572
ricow@chromium.org65fae842010-08-25 15:26:24 +00003573 // Loop through the prototype chain looking for the function prototype.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003574 __ LoadRoot(scratch2, Heap::kNullValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003575 __ bind(&loop);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003576 __ cmp(scratch, Operand(prototype));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003577 __ b(eq, &is_instance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003578 __ cmp(scratch, scratch2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003579 __ b(eq, &is_not_instance);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003580 __ ldr(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset));
3581 __ ldr(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003582 __ jmp(&loop);
3583
3584 __ bind(&is_instance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003585 if (!HasCallSiteInlineCheck()) {
3586 __ mov(r0, Operand(Smi::FromInt(0)));
3587 __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
3588 } else {
3589 // Patch the call site to return true.
3590 __ LoadRoot(r0, Heap::kTrueValueRootIndex);
3591 __ add(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
3592 // Get the boolean result location in scratch and patch it.
3593 __ GetRelocatedValueLocation(inline_site, scratch);
3594 __ str(r0, MemOperand(scratch));
3595
3596 if (!ReturnTrueFalseObject()) {
3597 __ mov(r0, Operand(Smi::FromInt(0)));
3598 }
3599 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003600 __ Ret(HasArgsInRegisters() ? 0 : 2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003601
3602 __ bind(&is_not_instance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003603 if (!HasCallSiteInlineCheck()) {
3604 __ mov(r0, Operand(Smi::FromInt(1)));
3605 __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
3606 } else {
3607 // Patch the call site to return false.
3608 __ LoadRoot(r0, Heap::kFalseValueRootIndex);
3609 __ add(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
3610 // Get the boolean result location in scratch and patch it.
3611 __ GetRelocatedValueLocation(inline_site, scratch);
3612 __ str(r0, MemOperand(scratch));
3613
3614 if (!ReturnTrueFalseObject()) {
3615 __ mov(r0, Operand(Smi::FromInt(1)));
3616 }
3617 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003618 __ Ret(HasArgsInRegisters() ? 0 : 2);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003619
3620 Label object_not_null, object_not_null_or_smi;
3621 __ bind(&not_js_object);
3622 // Before null, smi and string value checks, check that the rhs is a function
3623 // as for a non-function rhs an exception needs to be thrown.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003624 __ JumpIfSmi(function, &slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003625 __ CompareObjectType(function, scratch2, scratch, JS_FUNCTION_TYPE);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003626 __ b(ne, &slow);
3627
3628 // Null is not instance of anything.
danno@chromium.org160a7b02011-04-18 15:51:38 +00003629 __ cmp(scratch, Operand(masm->isolate()->factory()->null_value()));
whesse@chromium.org023421e2010-12-21 12:19:12 +00003630 __ b(ne, &object_not_null);
3631 __ mov(r0, Operand(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003632 __ Ret(HasArgsInRegisters() ? 0 : 2);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003633
3634 __ bind(&object_not_null);
3635 // Smi values are not instances of anything.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003636 __ JumpIfNotSmi(object, &object_not_null_or_smi);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003637 __ mov(r0, Operand(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003638 __ Ret(HasArgsInRegisters() ? 0 : 2);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003639
3640 __ bind(&object_not_null_or_smi);
3641 // String values are not instances of anything.
3642 __ IsObjectJSStringType(object, scratch, &slow);
3643 __ mov(r0, Operand(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003644 __ Ret(HasArgsInRegisters() ? 0 : 2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003645
3646 // Slow-case. Tail call builtin.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003647 __ bind(&slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003648 if (!ReturnTrueFalseObject()) {
3649 if (HasArgsInRegisters()) {
3650 __ Push(r0, r1);
3651 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003652 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003653 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003654 {
3655 FrameScope scope(masm, StackFrame::INTERNAL);
3656 __ Push(r0, r1);
3657 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
3658 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003659 __ cmp(r0, Operand::Zero());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003660 __ LoadRoot(r0, Heap::kTrueValueRootIndex, eq);
3661 __ LoadRoot(r0, Heap::kFalseValueRootIndex, ne);
3662 __ Ret(HasArgsInRegisters() ? 0 : 2);
3663 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003664}
3665
3666
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00003667void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
3668 Label miss;
3669 Register receiver;
3670 if (kind() == Code::KEYED_LOAD_IC) {
3671 // ----------- S t a t e -------------
3672 // -- lr : return address
3673 // -- r0 : key
3674 // -- r1 : receiver
3675 // -----------------------------------
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003676 __ cmp(r0, Operand(masm->isolate()->factory()->prototype_string()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00003677 __ b(ne, &miss);
3678 receiver = r1;
3679 } else {
3680 ASSERT(kind() == Code::LOAD_IC);
3681 // ----------- S t a t e -------------
3682 // -- r2 : name
3683 // -- lr : return address
3684 // -- r0 : receiver
3685 // -- sp[0] : receiver
3686 // -----------------------------------
3687 receiver = r0;
3688 }
3689
3690 StubCompiler::GenerateLoadFunctionPrototype(masm, receiver, r3, r4, &miss);
3691 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003692 StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00003693}
3694
3695
3696void StringLengthStub::Generate(MacroAssembler* masm) {
3697 Label miss;
3698 Register receiver;
3699 if (kind() == Code::KEYED_LOAD_IC) {
3700 // ----------- S t a t e -------------
3701 // -- lr : return address
3702 // -- r0 : key
3703 // -- r1 : receiver
3704 // -----------------------------------
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003705 __ cmp(r0, Operand(masm->isolate()->factory()->length_string()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00003706 __ b(ne, &miss);
3707 receiver = r1;
3708 } else {
3709 ASSERT(kind() == Code::LOAD_IC);
3710 // ----------- S t a t e -------------
3711 // -- r2 : name
3712 // -- lr : return address
3713 // -- r0 : receiver
3714 // -- sp[0] : receiver
3715 // -----------------------------------
3716 receiver = r0;
3717 }
3718
3719 StubCompiler::GenerateLoadStringLength(masm, receiver, r3, r4, &miss,
3720 support_wrapper_);
3721
3722 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003723 StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00003724}
3725
3726
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00003727void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
3728 // This accepts as a receiver anything JSArray::SetElementsLength accepts
3729 // (currently anything except for external arrays which means anything with
3730 // elements of FixedArray type). Value must be a number, but only smis are
3731 // accepted as the most common case.
3732 Label miss;
3733
3734 Register receiver;
3735 Register value;
3736 if (kind() == Code::KEYED_STORE_IC) {
3737 // ----------- S t a t e -------------
3738 // -- lr : return address
3739 // -- r0 : value
3740 // -- r1 : key
3741 // -- r2 : receiver
3742 // -----------------------------------
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003743 __ cmp(r1, Operand(masm->isolate()->factory()->length_string()));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00003744 __ b(ne, &miss);
3745 receiver = r2;
3746 value = r0;
3747 } else {
3748 ASSERT(kind() == Code::STORE_IC);
3749 // ----------- S t a t e -------------
3750 // -- lr : return address
3751 // -- r0 : value
3752 // -- r1 : receiver
3753 // -- r2 : key
3754 // -----------------------------------
3755 receiver = r1;
3756 value = r0;
3757 }
3758 Register scratch = r3;
3759
3760 // Check that the receiver isn't a smi.
3761 __ JumpIfSmi(receiver, &miss);
3762
3763 // Check that the object is a JS array.
3764 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
3765 __ b(ne, &miss);
3766
3767 // Check that elements are FixedArray.
3768 // We rely on StoreIC_ArrayLength below to deal with all types of
3769 // fast elements (including COW).
3770 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
3771 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
3772 __ b(ne, &miss);
3773
3774 // Check that the array has fast properties, otherwise the length
3775 // property might have been redefined.
3776 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset));
3777 __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset));
3778 __ CompareRoot(scratch, Heap::kHashTableMapRootIndex);
3779 __ b(eq, &miss);
3780
3781 // Check that value is a smi.
3782 __ JumpIfNotSmi(value, &miss);
3783
3784 // Prepare tail call to StoreIC_ArrayLength.
3785 __ Push(receiver, value);
3786
3787 ExternalReference ref =
3788 ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength), masm->isolate());
3789 __ TailCallExternalReference(ref, 2, 1);
3790
3791 __ bind(&miss);
3792
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003793 StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00003794}
3795
3796
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003797Register InstanceofStub::left() { return r0; }
3798
3799
3800Register InstanceofStub::right() { return r1; }
3801
3802
ricow@chromium.org65fae842010-08-25 15:26:24 +00003803void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
3804 // The displacement is the offset of the last parameter (if any)
3805 // relative to the frame pointer.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00003806 const int kDisplacement =
ricow@chromium.org65fae842010-08-25 15:26:24 +00003807 StandardFrameConstants::kCallerSPOffset - kPointerSize;
3808
3809 // Check that the key is a smi.
3810 Label slow;
ager@chromium.org378b34e2011-01-28 08:04:38 +00003811 __ JumpIfNotSmi(r1, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003812
3813 // Check if the calling frame is an arguments adaptor frame.
3814 Label adaptor;
3815 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3816 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
3817 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3818 __ b(eq, &adaptor);
3819
3820 // Check index against formal parameters count limit passed in
3821 // through register r0. Use unsigned comparison to get negative
3822 // check for free.
3823 __ cmp(r1, r0);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003824 __ b(hs, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003825
3826 // Read the argument from the stack and return it.
3827 __ sub(r3, r0, r1);
3828 __ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
3829 __ ldr(r0, MemOperand(r3, kDisplacement));
3830 __ Jump(lr);
3831
3832 // Arguments adaptor case: Check index against actual arguments
3833 // limit found in the arguments adaptor frame. Use unsigned
3834 // comparison to get negative check for free.
3835 __ bind(&adaptor);
3836 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
3837 __ cmp(r1, r0);
3838 __ b(cs, &slow);
3839
3840 // Read the argument from the adaptor frame and return it.
3841 __ sub(r3, r0, r1);
3842 __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
3843 __ ldr(r0, MemOperand(r3, kDisplacement));
3844 __ Jump(lr);
3845
3846 // Slow-case: Handle non-smi or out-of-bounds access to arguments
3847 // by calling the runtime system.
3848 __ bind(&slow);
3849 __ push(r1);
3850 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
3851}
3852
3853
whesse@chromium.org7b260152011-06-20 15:33:18 +00003854void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003855 // sp[0] : number of parameters
3856 // sp[4] : receiver displacement
3857 // sp[8] : function
3858
3859 // Check if the calling frame is an arguments adaptor frame.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003860 Label runtime;
3861 __ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3862 __ ldr(r2, MemOperand(r3, StandardFrameConstants::kContextOffset));
3863 __ cmp(r2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3864 __ b(ne, &runtime);
3865
3866 // Patch the arguments.length and the parameters pointer in the current frame.
3867 __ ldr(r2, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset));
3868 __ str(r2, MemOperand(sp, 0 * kPointerSize));
3869 __ add(r3, r3, Operand(r2, LSL, 1));
3870 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
3871 __ str(r3, MemOperand(sp, 1 * kPointerSize));
3872
3873 __ bind(&runtime);
3874 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
3875}
3876
3877
3878void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
3879 // Stack layout:
3880 // sp[0] : number of parameters (tagged)
3881 // sp[4] : address of receiver argument
3882 // sp[8] : function
3883 // Registers used over whole function:
3884 // r6 : allocated object (tagged)
3885 // r9 : mapped parameter count (tagged)
3886
3887 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
3888 // r1 = parameter count (tagged)
3889
3890 // Check if the calling frame is an arguments adaptor frame.
3891 Label runtime;
3892 Label adaptor_frame, try_allocate;
3893 __ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3894 __ ldr(r2, MemOperand(r3, StandardFrameConstants::kContextOffset));
3895 __ cmp(r2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3896 __ b(eq, &adaptor_frame);
3897
3898 // No adaptor, parameter count = argument count.
3899 __ mov(r2, r1);
3900 __ b(&try_allocate);
3901
3902 // We have an adaptor frame. Patch the parameters pointer.
3903 __ bind(&adaptor_frame);
3904 __ ldr(r2, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset));
3905 __ add(r3, r3, Operand(r2, LSL, 1));
3906 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
3907 __ str(r3, MemOperand(sp, 1 * kPointerSize));
3908
3909 // r1 = parameter count (tagged)
3910 // r2 = argument count (tagged)
3911 // Compute the mapped parameter count = min(r1, r2) in r1.
3912 __ cmp(r1, Operand(r2));
3913 __ mov(r1, Operand(r2), LeaveCC, gt);
3914
3915 __ bind(&try_allocate);
3916
3917 // Compute the sizes of backing store, parameter map, and arguments object.
3918 // 1. Parameter map, has 2 extra words containing context and backing store.
3919 const int kParameterMapHeaderSize =
3920 FixedArray::kHeaderSize + 2 * kPointerSize;
3921 // If there are no mapped parameters, we do not need the parameter_map.
3922 __ cmp(r1, Operand(Smi::FromInt(0)));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003923 __ mov(r9, Operand::Zero(), LeaveCC, eq);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003924 __ mov(r9, Operand(r1, LSL, 1), LeaveCC, ne);
3925 __ add(r9, r9, Operand(kParameterMapHeaderSize), LeaveCC, ne);
3926
3927 // 2. Backing store.
3928 __ add(r9, r9, Operand(r2, LSL, 1));
3929 __ add(r9, r9, Operand(FixedArray::kHeaderSize));
3930
3931 // 3. Arguments object.
3932 __ add(r9, r9, Operand(Heap::kArgumentsObjectSize));
3933
3934 // Do the allocation of all three objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003935 __ Allocate(r9, r0, r3, r4, &runtime, TAG_OBJECT);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003936
3937 // r0 = address of new object(s) (tagged)
3938 // r2 = argument count (tagged)
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003939 // Get the arguments boilerplate from the current native context into r4.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003940 const int kNormalOffset =
3941 Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
3942 const int kAliasedOffset =
3943 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX);
3944
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003945 __ ldr(r4, MemOperand(r8, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
3946 __ ldr(r4, FieldMemOperand(r4, GlobalObject::kNativeContextOffset));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003947 __ cmp(r1, Operand::Zero());
whesse@chromium.org7b260152011-06-20 15:33:18 +00003948 __ ldr(r4, MemOperand(r4, kNormalOffset), eq);
3949 __ ldr(r4, MemOperand(r4, kAliasedOffset), ne);
3950
3951 // r0 = address of new object (tagged)
3952 // r1 = mapped parameter count (tagged)
3953 // r2 = argument count (tagged)
3954 // r4 = address of boilerplate object (tagged)
3955 // Copy the JS object part.
3956 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
3957 __ ldr(r3, FieldMemOperand(r4, i));
3958 __ str(r3, FieldMemOperand(r0, i));
3959 }
3960
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003961 // Set up the callee in-object property.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003962 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
3963 __ ldr(r3, MemOperand(sp, 2 * kPointerSize));
3964 const int kCalleeOffset = JSObject::kHeaderSize +
3965 Heap::kArgumentsCalleeIndex * kPointerSize;
3966 __ str(r3, FieldMemOperand(r0, kCalleeOffset));
3967
3968 // Use the length (smi tagged) and set that as an in-object property too.
3969 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
3970 const int kLengthOffset = JSObject::kHeaderSize +
3971 Heap::kArgumentsLengthIndex * kPointerSize;
3972 __ str(r2, FieldMemOperand(r0, kLengthOffset));
3973
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003974 // Set up the elements pointer in the allocated arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003975 // If we allocated a parameter map, r4 will point there, otherwise
3976 // it will point to the backing store.
3977 __ add(r4, r0, Operand(Heap::kArgumentsObjectSize));
3978 __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
3979
3980 // r0 = address of new object (tagged)
3981 // r1 = mapped parameter count (tagged)
3982 // r2 = argument count (tagged)
3983 // r4 = address of parameter map or backing store (tagged)
3984 // Initialize parameter map. If there are no mapped arguments, we're done.
3985 Label skip_parameter_map;
3986 __ cmp(r1, Operand(Smi::FromInt(0)));
3987 // Move backing store address to r3, because it is
3988 // expected there when filling in the unmapped arguments.
3989 __ mov(r3, r4, LeaveCC, eq);
3990 __ b(eq, &skip_parameter_map);
3991
3992 __ LoadRoot(r6, Heap::kNonStrictArgumentsElementsMapRootIndex);
3993 __ str(r6, FieldMemOperand(r4, FixedArray::kMapOffset));
3994 __ add(r6, r1, Operand(Smi::FromInt(2)));
3995 __ str(r6, FieldMemOperand(r4, FixedArray::kLengthOffset));
3996 __ str(r8, FieldMemOperand(r4, FixedArray::kHeaderSize + 0 * kPointerSize));
3997 __ add(r6, r4, Operand(r1, LSL, 1));
3998 __ add(r6, r6, Operand(kParameterMapHeaderSize));
3999 __ str(r6, FieldMemOperand(r4, FixedArray::kHeaderSize + 1 * kPointerSize));
4000
4001 // Copy the parameter slots and the holes in the arguments.
4002 // We need to fill in mapped_parameter_count slots. They index the context,
4003 // where parameters are stored in reverse order, at
4004 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
4005 // The mapped parameter thus need to get indices
4006 // MIN_CONTEXT_SLOTS+parameter_count-1 ..
4007 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
4008 // We loop from right to left.
4009 Label parameters_loop, parameters_test;
4010 __ mov(r6, r1);
4011 __ ldr(r9, MemOperand(sp, 0 * kPointerSize));
4012 __ add(r9, r9, Operand(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
4013 __ sub(r9, r9, Operand(r1));
4014 __ LoadRoot(r7, Heap::kTheHoleValueRootIndex);
4015 __ add(r3, r4, Operand(r6, LSL, 1));
4016 __ add(r3, r3, Operand(kParameterMapHeaderSize));
4017
4018 // r6 = loop variable (tagged)
4019 // r1 = mapping index (tagged)
4020 // r3 = address of backing store (tagged)
4021 // r4 = address of parameter map (tagged)
4022 // r5 = temporary scratch (a.o., for address calculation)
4023 // r7 = the hole value
4024 __ jmp(&parameters_test);
4025
4026 __ bind(&parameters_loop);
4027 __ sub(r6, r6, Operand(Smi::FromInt(1)));
4028 __ mov(r5, Operand(r6, LSL, 1));
4029 __ add(r5, r5, Operand(kParameterMapHeaderSize - kHeapObjectTag));
4030 __ str(r9, MemOperand(r4, r5));
4031 __ sub(r5, r5, Operand(kParameterMapHeaderSize - FixedArray::kHeaderSize));
4032 __ str(r7, MemOperand(r3, r5));
4033 __ add(r9, r9, Operand(Smi::FromInt(1)));
4034 __ bind(&parameters_test);
4035 __ cmp(r6, Operand(Smi::FromInt(0)));
4036 __ b(ne, &parameters_loop);
4037
4038 __ bind(&skip_parameter_map);
4039 // r2 = argument count (tagged)
4040 // r3 = address of backing store (tagged)
4041 // r5 = scratch
4042 // Copy arguments header and remaining slots (if there are any).
4043 __ LoadRoot(r5, Heap::kFixedArrayMapRootIndex);
4044 __ str(r5, FieldMemOperand(r3, FixedArray::kMapOffset));
4045 __ str(r2, FieldMemOperand(r3, FixedArray::kLengthOffset));
4046
4047 Label arguments_loop, arguments_test;
4048 __ mov(r9, r1);
4049 __ ldr(r4, MemOperand(sp, 1 * kPointerSize));
4050 __ sub(r4, r4, Operand(r9, LSL, 1));
4051 __ jmp(&arguments_test);
4052
4053 __ bind(&arguments_loop);
4054 __ sub(r4, r4, Operand(kPointerSize));
4055 __ ldr(r6, MemOperand(r4, 0));
4056 __ add(r5, r3, Operand(r9, LSL, 1));
4057 __ str(r6, FieldMemOperand(r5, FixedArray::kHeaderSize));
4058 __ add(r9, r9, Operand(Smi::FromInt(1)));
4059
4060 __ bind(&arguments_test);
4061 __ cmp(r9, Operand(r2));
4062 __ b(lt, &arguments_loop);
4063
4064 // Return and remove the on-stack parameters.
4065 __ add(sp, sp, Operand(3 * kPointerSize));
4066 __ Ret();
4067
4068 // Do the runtime call to allocate the arguments object.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004069 // r2 = argument count (tagged)
whesse@chromium.org7b260152011-06-20 15:33:18 +00004070 __ bind(&runtime);
4071 __ str(r2, MemOperand(sp, 0 * kPointerSize)); // Patch argument count.
4072 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
4073}
4074
4075
4076void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
4077 // sp[0] : number of parameters
4078 // sp[4] : receiver displacement
4079 // sp[8] : function
4080 // Check if the calling frame is an arguments adaptor frame.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004081 Label adaptor_frame, try_allocate, runtime;
4082 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
4083 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
4084 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
4085 __ b(eq, &adaptor_frame);
4086
4087 // Get the length from the frame.
4088 __ ldr(r1, MemOperand(sp, 0));
4089 __ b(&try_allocate);
4090
4091 // Patch the arguments.length and the parameters pointer.
4092 __ bind(&adaptor_frame);
4093 __ ldr(r1, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
4094 __ str(r1, MemOperand(sp, 0));
4095 __ add(r3, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
4096 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
4097 __ str(r3, MemOperand(sp, 1 * kPointerSize));
4098
4099 // Try the new space allocation. Start out with computing the size
4100 // of the arguments object and the elements array in words.
4101 Label add_arguments_object;
4102 __ bind(&try_allocate);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004103 __ cmp(r1, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004104 __ b(eq, &add_arguments_object);
4105 __ mov(r1, Operand(r1, LSR, kSmiTagSize));
4106 __ add(r1, r1, Operand(FixedArray::kHeaderSize / kPointerSize));
4107 __ bind(&add_arguments_object);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004108 __ add(r1, r1, Operand(Heap::kArgumentsObjectSizeStrict / kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004109
4110 // Do the allocation of both objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004111 __ Allocate(r1, r0, r2, r3, &runtime,
4112 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004113
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004114 // Get the arguments boilerplate from the current native context.
4115 __ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
4116 __ ldr(r4, FieldMemOperand(r4, GlobalObject::kNativeContextOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00004117 __ ldr(r4, MemOperand(r4, Context::SlotOffset(
4118 Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004119
4120 // Copy the JS object part.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004121 __ CopyFields(r0, r4, d0, s0, JSObject::kHeaderSize / kPointerSize);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004122
ricow@chromium.org65fae842010-08-25 15:26:24 +00004123 // Get the length (smi tagged) and set that as an in-object property too.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004124 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004125 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004126 __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize +
whesse@chromium.org7b260152011-06-20 15:33:18 +00004127 Heap::kArgumentsLengthIndex * kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004128
4129 // If there are no actual arguments, we're done.
4130 Label done;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004131 __ cmp(r1, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004132 __ b(eq, &done);
4133
4134 // Get the parameters pointer from the stack.
4135 __ ldr(r2, MemOperand(sp, 1 * kPointerSize));
4136
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004137 // Set up the elements pointer in the allocated arguments object and
ricow@chromium.org65fae842010-08-25 15:26:24 +00004138 // initialize the header in the elements fixed array.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004139 __ add(r4, r0, Operand(Heap::kArgumentsObjectSizeStrict));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004140 __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
4141 __ LoadRoot(r3, Heap::kFixedArrayMapRootIndex);
4142 __ str(r3, FieldMemOperand(r4, FixedArray::kMapOffset));
4143 __ str(r1, FieldMemOperand(r4, FixedArray::kLengthOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00004144 // Untag the length for the loop.
4145 __ mov(r1, Operand(r1, LSR, kSmiTagSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004146
4147 // Copy the fixed array slots.
4148 Label loop;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004149 // Set up r4 to point to the first array slot.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004150 __ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4151 __ bind(&loop);
4152 // Pre-decrement r2 with kPointerSize on each iteration.
4153 // Pre-decrement in order to skip receiver.
4154 __ ldr(r3, MemOperand(r2, kPointerSize, NegPreIndex));
4155 // Post-increment r4 with kPointerSize on each iteration.
4156 __ str(r3, MemOperand(r4, kPointerSize, PostIndex));
4157 __ sub(r1, r1, Operand(1));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004158 __ cmp(r1, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004159 __ b(ne, &loop);
4160
4161 // Return and remove the on-stack parameters.
4162 __ bind(&done);
4163 __ add(sp, sp, Operand(3 * kPointerSize));
4164 __ Ret();
4165
4166 // Do the runtime call to allocate the arguments object.
4167 __ bind(&runtime);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004168 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004169}
4170
4171
4172void RegExpExecStub::Generate(MacroAssembler* masm) {
4173 // Just jump directly to runtime if native RegExp is not selected at compile
4174 // time or if regexp entry in generated code is turned off runtime switch or
4175 // at compilation.
4176#ifdef V8_INTERPRETED_REGEXP
4177 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
4178#else // V8_INTERPRETED_REGEXP
ricow@chromium.org65fae842010-08-25 15:26:24 +00004179
4180 // Stack frame on entry.
4181 // sp[0]: last_match_info (expected JSArray)
4182 // sp[4]: previous index
4183 // sp[8]: subject string
4184 // sp[12]: JSRegExp object
4185
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004186 const int kLastMatchInfoOffset = 0 * kPointerSize;
4187 const int kPreviousIndexOffset = 1 * kPointerSize;
4188 const int kSubjectOffset = 2 * kPointerSize;
4189 const int kJSRegExpOffset = 3 * kPointerSize;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004190
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004191 Label runtime;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004192 // Allocation of registers for this function. These are in callee save
4193 // registers and will be preserved by the call to the native RegExp code, as
4194 // this code is called using the normal C calling convention. When calling
4195 // directly from generated code the native RegExp code will not do a GC and
4196 // therefore the content of these registers are safe to use after the call.
4197 Register subject = r4;
4198 Register regexp_data = r5;
4199 Register last_match_info_elements = r6;
4200
4201 // Ensure that a RegExp stack is allocated.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004202 Isolate* isolate = masm->isolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004203 ExternalReference address_of_regexp_stack_memory_address =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004204 ExternalReference::address_of_regexp_stack_memory_address(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004205 ExternalReference address_of_regexp_stack_memory_size =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004206 ExternalReference::address_of_regexp_stack_memory_size(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004207 __ mov(r0, Operand(address_of_regexp_stack_memory_size));
4208 __ ldr(r0, MemOperand(r0, 0));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004209 __ cmp(r0, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004210 __ b(eq, &runtime);
4211
4212 // Check that the first argument is a JSRegExp object.
4213 __ ldr(r0, MemOperand(sp, kJSRegExpOffset));
4214 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004215 __ JumpIfSmi(r0, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004216 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
4217 __ b(ne, &runtime);
4218
4219 // Check that the RegExp has been compiled (data contains a fixed array).
4220 __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset));
4221 if (FLAG_debug_code) {
4222 __ tst(regexp_data, Operand(kSmiTagMask));
ager@chromium.org378b34e2011-01-28 08:04:38 +00004223 __ Check(ne, "Unexpected type for RegExp data, FixedArray expected");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004224 __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE);
4225 __ Check(eq, "Unexpected type for RegExp data, FixedArray expected");
4226 }
4227
4228 // regexp_data: RegExp data (FixedArray)
4229 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
4230 __ ldr(r0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset));
4231 __ cmp(r0, Operand(Smi::FromInt(JSRegExp::IRREGEXP)));
4232 __ b(ne, &runtime);
4233
4234 // regexp_data: RegExp data (FixedArray)
4235 // Check that the number of captures fit in the static offsets vector buffer.
4236 __ ldr(r2,
4237 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004238 // Check (number_of_captures + 1) * 2 <= offsets vector size
4239 // Or number_of_captures * 2 <= offsets vector size - 2
4240 // Multiplying by 2 comes for free since r2 is smi-tagged.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004241 STATIC_ASSERT(kSmiTag == 0);
4242 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004243 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
4244 __ cmp(r2, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize - 2));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004245 __ b(hi, &runtime);
4246
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004247 // Reset offset for possibly sliced string.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004248 __ mov(r9, Operand::Zero());
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004249 __ ldr(subject, MemOperand(sp, kSubjectOffset));
4250 __ JumpIfSmi(subject, &runtime);
4251 __ mov(r3, subject); // Make a copy of the original subject string.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004252 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset));
4253 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004254 // subject: subject string
4255 // r3: subject string
4256 // r0: subject string instance type
4257 // regexp_data: RegExp data (FixedArray)
4258 // Handle subject string according to its encoding and representation:
4259 // (1) Sequential string? If yes, go to (5).
4260 // (2) Anything but sequential or cons? If yes, go to (6).
4261 // (3) Cons string. If the string is flat, replace subject with first string.
4262 // Otherwise bailout.
4263 // (4) Is subject external? If yes, go to (7).
4264 // (5) Sequential string. Load regexp code according to encoding.
4265 // (E) Carry on.
4266 /// [...]
4267
4268 // Deferred code at the end of the stub:
4269 // (6) Not a long external string? If yes, go to (8).
4270 // (7) External string. Make it, offset-wise, look like a sequential string.
4271 // Go to (5).
4272 // (8) Short external string or not a string? If yes, bail out to runtime.
4273 // (9) Sliced string. Replace subject with parent. Go to (4).
4274
4275 Label seq_string /* 5 */, external_string /* 7 */,
4276 check_underlying /* 4 */, not_seq_nor_cons /* 6 */,
4277 not_long_external /* 8 */;
4278
4279 // (1) Sequential string? If yes, go to (5).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004280 __ and_(r1,
4281 r0,
4282 Operand(kIsNotStringMask |
4283 kStringRepresentationMask |
4284 kShortExternalStringMask),
4285 SetCC);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004286 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004287 __ b(eq, &seq_string); // Go to (5).
ricow@chromium.org65fae842010-08-25 15:26:24 +00004288
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004289 // (2) Anything but sequential or cons? If yes, go to (6).
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00004290 STATIC_ASSERT(kConsStringTag < kExternalStringTag);
4291 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004292 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
4293 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004294 __ cmp(r1, Operand(kExternalStringTag));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004295 __ b(ge, &not_seq_nor_cons); // Go to (6).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004296
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004297 // (3) Cons string. Check that it's flat.
4298 // Replace subject with first string and reload instance type.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004299 __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004300 __ CompareRoot(r0, Heap::kempty_stringRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004301 __ b(ne, &runtime);
4302 __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004303
4304 // (4) Is subject external? If yes, go to (7).
4305 __ bind(&check_underlying);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004306 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset));
4307 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004308 STATIC_ASSERT(kSeqStringTag == 0);
4309 __ tst(r0, Operand(kStringRepresentationMask));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004310 // The underlying external string is never a short external string.
4311 STATIC_CHECK(ExternalString::kMaxShortLength < ConsString::kMinLength);
4312 STATIC_CHECK(ExternalString::kMaxShortLength < SlicedString::kMinLength);
4313 __ b(ne, &external_string); // Go to (7).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004314
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004315 // (5) Sequential string. Load regexp code according to encoding.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004316 __ bind(&seq_string);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004317 // subject: sequential subject string (or look-alike, external string)
4318 // r3: original subject string
4319 // Load previous index and check range before r3 is overwritten. We have to
4320 // use r3 instead of subject here because subject might have been only made
4321 // to look like a sequential string when it actually is an external string.
4322 __ ldr(r1, MemOperand(sp, kPreviousIndexOffset));
4323 __ JumpIfNotSmi(r1, &runtime);
4324 __ ldr(r3, FieldMemOperand(r3, String::kLengthOffset));
4325 __ cmp(r3, Operand(r1));
4326 __ b(ls, &runtime);
4327 __ mov(r1, Operand(r1, ASR, kSmiTagSize));
4328
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004329 STATIC_ASSERT(4 == kOneByteStringTag);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004330 STATIC_ASSERT(kTwoByteStringTag == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004331 __ and_(r0, r0, Operand(kStringEncodingMask));
4332 __ mov(r3, Operand(r0, ASR, 2), SetCC);
4333 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne);
4334 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq);
4335
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004336 // (E) Carry on. String handling is done.
4337 // r7: irregexp code
ricow@chromium.org65fae842010-08-25 15:26:24 +00004338 // Check that the irregexp code has been generated for the actual string
4339 // encoding. If it has, the field contains a code object otherwise it contains
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004340 // a smi (code flushing support).
4341 __ JumpIfSmi(r7, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004342
ricow@chromium.org65fae842010-08-25 15:26:24 +00004343 // r1: previous index
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004344 // r3: encoding of subject string (1 if ASCII, 0 if two_byte);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004345 // r7: code
4346 // subject: Subject string
4347 // regexp_data: RegExp data (FixedArray)
4348 // All checks done. Now push arguments for native regexp code.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004349 __ IncrementCounter(isolate->counters()->regexp_entry_native(), 1, r0, r2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004351 // Isolates: note we add an additional parameter here (isolate pointer).
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004352 const int kRegExpExecuteArguments = 9;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004353 const int kParameterRegisters = 4;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004354 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004355
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004356 // Stack pointer now points to cell where return address is to be written.
4357 // Arguments are before that on the stack or in registers.
4358
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004359 // Argument 9 (sp[20]): Pass current isolate address.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004360 __ mov(r0, Operand(ExternalReference::isolate_address(isolate)));
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004361 __ str(r0, MemOperand(sp, 5 * kPointerSize));
4362
4363 // Argument 8 (sp[16]): Indicate that this is a direct call from JavaScript.
4364 __ mov(r0, Operand(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004365 __ str(r0, MemOperand(sp, 4 * kPointerSize));
4366
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004367 // Argument 7 (sp[12]): Start (high end) of backtracking stack memory area.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004368 __ mov(r0, Operand(address_of_regexp_stack_memory_address));
4369 __ ldr(r0, MemOperand(r0, 0));
4370 __ mov(r2, Operand(address_of_regexp_stack_memory_size));
4371 __ ldr(r2, MemOperand(r2, 0));
4372 __ add(r0, r0, Operand(r2));
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004373 __ str(r0, MemOperand(sp, 3 * kPointerSize));
4374
4375 // Argument 6: Set the number of capture registers to zero to force global
4376 // regexps to behave as non-global. This does not affect non-global regexps.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004377 __ mov(r0, Operand::Zero());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004378 __ str(r0, MemOperand(sp, 2 * kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004379
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004380 // Argument 5 (sp[4]): static offsets vector buffer.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004381 __ mov(r0,
4382 Operand(ExternalReference::address_of_static_offsets_vector(isolate)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004383 __ str(r0, MemOperand(sp, 1 * kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004384
4385 // For arguments 4 and 3 get string length, calculate start of string data and
4386 // calculate the shift of the index (0 for ASCII and 1 for two byte).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004387 __ add(r8, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004388 __ eor(r3, r3, Operand(1));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004389 // Load the length from the original subject string from the previous stack
4390 // frame. Therefore we have to use fp, which points exactly to two pointer
4391 // sizes below the previous sp. (Because creating a new stack frame pushes
4392 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.)
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004393 __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004394 // If slice offset is not 0, load the length from the original sliced string.
4395 // Argument 4, r3: End of string data
4396 // Argument 3, r2: Start of string data
4397 // Prepare start and end index of the input.
4398 __ add(r9, r8, Operand(r9, LSL, r3));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004399 __ add(r2, r9, Operand(r1, LSL, r3));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004400
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004401 __ ldr(r8, FieldMemOperand(subject, String::kLengthOffset));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004402 __ mov(r8, Operand(r8, ASR, kSmiTagSize));
4403 __ add(r3, r9, Operand(r8, LSL, r3));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004404
4405 // Argument 2 (r1): Previous index.
4406 // Already there
4407
4408 // Argument 1 (r0): Subject string.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004409 __ mov(r0, subject);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004410
4411 // Locate the code entry and call it.
4412 __ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004413 DirectCEntryStub stub;
4414 stub.GenerateCall(masm, r7);
4415
4416 __ LeaveExitFrame(false, no_reg);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004417
4418 // r0: result
4419 // subject: subject string (callee saved)
4420 // regexp_data: RegExp data (callee saved)
4421 // last_match_info_elements: Last match info elements (callee saved)
ricow@chromium.org65fae842010-08-25 15:26:24 +00004422 // Check the result.
4423 Label success;
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004424 __ cmp(r0, Operand(1));
4425 // We expect exactly one result since we force the called regexp to behave
4426 // as non-global.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004427 __ b(eq, &success);
4428 Label failure;
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004429 __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004430 __ b(eq, &failure);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004431 __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004432 // If not exception it can only be retry. Handle that in the runtime system.
4433 __ b(ne, &runtime);
4434 // Result must now be exception. If there is no pending exception already a
4435 // stack overflow (on the backtrack stack) was detected in RegExp code but
4436 // haven't created the exception yet. Handle that in the runtime system.
4437 // TODO(592): Rerunning the RegExp to get the stack overflow exception.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004438 __ mov(r1, Operand(isolate->factory()->the_hole_value()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004439 __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004440 isolate)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004441 __ ldr(r0, MemOperand(r2, 0));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004442 __ cmp(r0, r1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004443 __ b(eq, &runtime);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004444
4445 __ str(r1, MemOperand(r2, 0)); // Clear pending exception.
4446
4447 // Check if the exception is a termination. If so, throw as uncatchable.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004448 __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex);
4449
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004450 Label termination_exception;
4451 __ b(eq, &termination_exception);
4452
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004453 __ Throw(r0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004454
4455 __ bind(&termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004456 __ ThrowUncatchable(r0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004457
ricow@chromium.org65fae842010-08-25 15:26:24 +00004458 __ bind(&failure);
4459 // For failure and exception return null.
danno@chromium.org160a7b02011-04-18 15:51:38 +00004460 __ mov(r0, Operand(masm->isolate()->factory()->null_value()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004461 __ add(sp, sp, Operand(4 * kPointerSize));
4462 __ Ret();
4463
4464 // Process the result from the native regexp code.
4465 __ bind(&success);
4466 __ ldr(r1,
4467 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
4468 // Calculate number of capture registers (number_of_captures + 1) * 2.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004469 // Multiplying by 2 comes for free since r1 is smi-tagged.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004470 STATIC_ASSERT(kSmiTag == 0);
4471 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
4472 __ add(r1, r1, Operand(2)); // r1 was a smi.
4473
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004474 __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset));
4475 __ JumpIfSmi(r0, &runtime);
4476 __ CompareObjectType(r0, r2, r2, JS_ARRAY_TYPE);
4477 __ b(ne, &runtime);
4478 // Check that the JSArray is in fast case.
4479 __ ldr(last_match_info_elements,
4480 FieldMemOperand(r0, JSArray::kElementsOffset));
4481 __ ldr(r0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
4482 __ CompareRoot(r0, Heap::kFixedArrayMapRootIndex);
4483 __ b(ne, &runtime);
4484 // Check that the last match info has space for the capture registers and the
4485 // additional information.
4486 __ ldr(r0,
4487 FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset));
4488 __ add(r2, r1, Operand(RegExpImpl::kLastMatchOverhead));
4489 __ cmp(r2, Operand(r0, ASR, kSmiTagSize));
4490 __ b(gt, &runtime);
4491
ricow@chromium.org65fae842010-08-25 15:26:24 +00004492 // r1: number of capture registers
4493 // r4: subject string
4494 // Store the capture count.
4495 __ mov(r2, Operand(r1, LSL, kSmiTagSize + kSmiShiftSize)); // To smi.
4496 __ str(r2, FieldMemOperand(last_match_info_elements,
4497 RegExpImpl::kLastCaptureCountOffset));
4498 // Store last subject and last input.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004499 __ str(subject,
4500 FieldMemOperand(last_match_info_elements,
4501 RegExpImpl::kLastSubjectOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004502 __ mov(r2, subject);
4503 __ RecordWriteField(last_match_info_elements,
4504 RegExpImpl::kLastSubjectOffset,
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004505 subject,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004506 r7,
4507 kLRHasNotBeenSaved,
4508 kDontSaveFPRegs);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004509 __ mov(subject, r2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004510 __ str(subject,
4511 FieldMemOperand(last_match_info_elements,
4512 RegExpImpl::kLastInputOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004513 __ RecordWriteField(last_match_info_elements,
4514 RegExpImpl::kLastInputOffset,
4515 subject,
4516 r7,
4517 kLRHasNotBeenSaved,
4518 kDontSaveFPRegs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004519
4520 // Get the static offsets vector filled by the native regexp code.
4521 ExternalReference address_of_static_offsets_vector =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004522 ExternalReference::address_of_static_offsets_vector(isolate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004523 __ mov(r2, Operand(address_of_static_offsets_vector));
4524
4525 // r1: number of capture registers
4526 // r2: offsets vector
4527 Label next_capture, done;
4528 // Capture register counter starts from number of capture registers and
4529 // counts down until wraping after zero.
4530 __ add(r0,
4531 last_match_info_elements,
4532 Operand(RegExpImpl::kFirstCaptureOffset - kHeapObjectTag));
4533 __ bind(&next_capture);
4534 __ sub(r1, r1, Operand(1), SetCC);
4535 __ b(mi, &done);
4536 // Read the value from the static offsets vector buffer.
4537 __ ldr(r3, MemOperand(r2, kPointerSize, PostIndex));
4538 // Store the smi value in the last match info.
4539 __ mov(r3, Operand(r3, LSL, kSmiTagSize));
4540 __ str(r3, MemOperand(r0, kPointerSize, PostIndex));
4541 __ jmp(&next_capture);
4542 __ bind(&done);
4543
4544 // Return last match info.
4545 __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset));
4546 __ add(sp, sp, Operand(4 * kPointerSize));
4547 __ Ret();
4548
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004549 // Do the runtime call to execute the regexp.
4550 __ bind(&runtime);
4551 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
4552
4553 // Deferred code for string handling.
4554 // (6) Not a long external string? If yes, go to (8).
4555 __ bind(&not_seq_nor_cons);
4556 // Compare flags are still set.
4557 __ b(gt, &not_long_external); // Go to (8).
4558
4559 // (7) External string. Make it, offset-wise, look like a sequential string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004560 __ bind(&external_string);
4561 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset));
4562 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
4563 if (FLAG_debug_code) {
4564 // Assert that we do not have a cons or slice (indirect strings) here.
4565 // Sequential strings have already been ruled out.
4566 __ tst(r0, Operand(kIsIndirectStringMask));
4567 __ Assert(eq, "external string expected, but not found");
4568 }
4569 __ ldr(subject,
4570 FieldMemOperand(subject, ExternalString::kResourceDataOffset));
4571 // Move the pointer so that offset-wise, it looks like a sequential string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004572 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004573 __ sub(subject,
4574 subject,
4575 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004576 __ jmp(&seq_string); // Go to (5).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004577
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004578 // (8) Short external string or not a string? If yes, bail out to runtime.
4579 __ bind(&not_long_external);
4580 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
4581 __ tst(r1, Operand(kIsNotStringMask | kShortExternalStringMask));
4582 __ b(ne, &runtime);
4583
4584 // (9) Sliced string. Replace subject with parent. Go to (4).
4585 // Load offset into r9 and replace subject string with parent.
4586 __ ldr(r9, FieldMemOperand(subject, SlicedString::kOffsetOffset));
4587 __ mov(r9, Operand(r9, ASR, kSmiTagSize));
4588 __ ldr(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
4589 __ jmp(&check_underlying); // Go to (4).
ricow@chromium.org65fae842010-08-25 15:26:24 +00004590#endif // V8_INTERPRETED_REGEXP
4591}
4592
4593
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004594void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
4595 const int kMaxInlineLength = 100;
4596 Label slowcase;
4597 Label done;
danno@chromium.org160a7b02011-04-18 15:51:38 +00004598 Factory* factory = masm->isolate()->factory();
4599
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004600 __ ldr(r1, MemOperand(sp, kPointerSize * 2));
4601 STATIC_ASSERT(kSmiTag == 0);
4602 STATIC_ASSERT(kSmiTagSize == 1);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004603 __ JumpIfNotSmi(r1, &slowcase);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004604 __ cmp(r1, Operand(Smi::FromInt(kMaxInlineLength)));
4605 __ b(hi, &slowcase);
4606 // Smi-tagging is equivalent to multiplying by 2.
4607 // Allocate RegExpResult followed by FixedArray with size in ebx.
4608 // JSArray: [Map][empty properties][Elements][Length-smi][index][input]
4609 // Elements: [Map][Length][..elements..]
4610 // Size of JSArray with two in-object properties and the header of a
4611 // FixedArray.
4612 int objects_size =
4613 (JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize;
4614 __ mov(r5, Operand(r1, LSR, kSmiTagSize + kSmiShiftSize));
4615 __ add(r2, r5, Operand(objects_size));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004616 __ Allocate(
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004617 r2, // In: Size, in words.
4618 r0, // Out: Start of allocation (tagged).
4619 r3, // Scratch register.
4620 r4, // Scratch register.
4621 &slowcase,
4622 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
4623 // r0: Start of allocated area, object-tagged.
4624 // r1: Number of elements in array, as smi.
4625 // r5: Number of elements, untagged.
4626
4627 // Set JSArray map to global.regexp_result_map().
4628 // Set empty properties FixedArray.
4629 // Set elements to point to FixedArray allocated right after the JSArray.
4630 // Interleave operations for better latency.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004631 __ ldr(r2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004632 __ add(r3, r0, Operand(JSRegExpResult::kSize));
danno@chromium.org160a7b02011-04-18 15:51:38 +00004633 __ mov(r4, Operand(factory->empty_fixed_array()));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004634 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kNativeContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004635 __ str(r3, FieldMemOperand(r0, JSObject::kElementsOffset));
4636 __ ldr(r2, ContextOperand(r2, Context::REGEXP_RESULT_MAP_INDEX));
4637 __ str(r4, FieldMemOperand(r0, JSObject::kPropertiesOffset));
4638 __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
4639
4640 // Set input, index and length fields from arguments.
4641 __ ldr(r1, MemOperand(sp, kPointerSize * 0));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004642 __ ldr(r2, MemOperand(sp, kPointerSize * 1));
4643 __ ldr(r6, MemOperand(sp, kPointerSize * 2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004644 __ str(r1, FieldMemOperand(r0, JSRegExpResult::kInputOffset));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004645 __ str(r2, FieldMemOperand(r0, JSRegExpResult::kIndexOffset));
4646 __ str(r6, FieldMemOperand(r0, JSArray::kLengthOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004647
4648 // Fill out the elements FixedArray.
4649 // r0: JSArray, tagged.
4650 // r3: FixedArray, tagged.
4651 // r5: Number of elements in array, untagged.
4652
4653 // Set map.
danno@chromium.org160a7b02011-04-18 15:51:38 +00004654 __ mov(r2, Operand(factory->fixed_array_map()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004655 __ str(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
4656 // Set FixedArray length.
4657 __ mov(r6, Operand(r5, LSL, kSmiTagSize));
4658 __ str(r6, FieldMemOperand(r3, FixedArray::kLengthOffset));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004659 // Fill contents of fixed-array with undefined.
4660 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004661 __ add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004662 // Fill fixed array elements with undefined.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004663 // r0: JSArray, tagged.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004664 // r2: undefined.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004665 // r3: Start of elements in FixedArray.
4666 // r5: Number of elements to fill.
4667 Label loop;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004668 __ cmp(r5, Operand::Zero());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004669 __ bind(&loop);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004670 __ b(le, &done); // Jump if r5 is negative or zero.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004671 __ sub(r5, r5, Operand(1), SetCC);
4672 __ str(r2, MemOperand(r3, r5, LSL, kPointerSizeLog2));
4673 __ jmp(&loop);
4674
4675 __ bind(&done);
4676 __ add(sp, sp, Operand(3 * kPointerSize));
4677 __ Ret();
4678
4679 __ bind(&slowcase);
4680 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1);
4681}
4682
4683
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004684static void GenerateRecordCallTargetNoArray(MacroAssembler* masm) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004685 // Cache the called function in a global property cell. Cache states
4686 // are uninitialized, monomorphic (indicated by a JSFunction), and
4687 // megamorphic.
4688 // r1 : the function to call
4689 // r2 : cache cell for call target
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004690 ASSERT(!FLAG_optimize_constructed_arrays);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004691 Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004692
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004693 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
4694 masm->isolate()->heap()->undefined_value());
4695 ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()),
4696 masm->isolate()->heap()->the_hole_value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004697
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004698 // Load the cache state into r3.
4699 __ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004700
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004701 // A monomorphic cache hit or an already megamorphic state: invoke the
4702 // function without changing the state.
4703 __ cmp(r3, r1);
4704 __ b(eq, &done);
4705 __ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
4706 __ b(eq, &done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004707
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004708 // A monomorphic miss (i.e, here the cache is not uninitialized) goes
4709 // megamorphic.
4710 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
4711 // MegamorphicSentinel is an immortal immovable object (undefined) so no
4712 // write-barrier is needed.
4713 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex, ne);
4714 __ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset), ne);
4715
4716 // An uninitialized cache is patched with the function.
4717 __ str(r1, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset), eq);
4718 // No need for a write barrier here - cells are rescanned.
4719
4720 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004721}
4722
4723
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004724static void GenerateRecordCallTarget(MacroAssembler* masm) {
4725 // Cache the called function in a global property cell. Cache states
4726 // are uninitialized, monomorphic (indicated by a JSFunction), and
4727 // megamorphic.
4728 // r1 : the function to call
4729 // r2 : cache cell for call target
4730 ASSERT(FLAG_optimize_constructed_arrays);
4731 Label initialize, done, miss, megamorphic, not_array_function;
4732
4733 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
4734 masm->isolate()->heap()->undefined_value());
4735 ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()),
4736 masm->isolate()->heap()->the_hole_value());
4737
4738 // Load the cache state into r3.
4739 __ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
4740
4741 // A monomorphic cache hit or an already megamorphic state: invoke the
4742 // function without changing the state.
4743 __ cmp(r3, r1);
4744 __ b(eq, &done);
4745 __ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
4746 __ b(eq, &done);
4747
4748 // Special handling of the Array() function, which caches not only the
4749 // monomorphic Array function but the initial ElementsKind with special
4750 // sentinels
4751 Handle<Object> terminal_kind_sentinel =
4752 TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
4753 LAST_FAST_ELEMENTS_KIND);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004754 __ JumpIfNotSmi(r3, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004755 __ cmp(r3, Operand(terminal_kind_sentinel));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004756 __ b(gt, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004757 // Make sure the function is the Array() function
4758 __ LoadArrayFunction(r3);
4759 __ cmp(r1, r3);
4760 __ b(ne, &megamorphic);
4761 __ jmp(&done);
4762
4763 __ bind(&miss);
4764
4765 // A monomorphic miss (i.e, here the cache is not uninitialized) goes
4766 // megamorphic.
4767 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
4768 __ b(eq, &initialize);
4769 // MegamorphicSentinel is an immortal immovable object (undefined) so no
4770 // write-barrier is needed.
4771 __ bind(&megamorphic);
4772 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
4773 __ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
4774
4775 // An uninitialized cache is patched with the function or sentinel to
4776 // indicate the ElementsKind if function is the Array constructor.
4777 __ bind(&initialize);
4778 // Make sure the function is the Array() function
4779 __ LoadArrayFunction(r3);
4780 __ cmp(r1, r3);
4781 __ b(ne, &not_array_function);
4782
4783 // The target function is the Array constructor, install a sentinel value in
4784 // the constructor's type info cell that will track the initial ElementsKind
4785 // that should be used for the array when its constructed.
4786 Handle<Object> initial_kind_sentinel =
4787 TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
4788 GetInitialFastElementsKind());
4789 __ mov(r3, Operand(initial_kind_sentinel));
4790 __ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
4791 __ b(&done);
4792
4793 __ bind(&not_array_function);
4794 __ str(r1, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
4795 // No need for a write barrier here - cells are rescanned.
4796
4797 __ bind(&done);
4798}
4799
4800
ricow@chromium.org65fae842010-08-25 15:26:24 +00004801void CallFunctionStub::Generate(MacroAssembler* masm) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00004802 // r1 : the function to call
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004803 // r2 : cache cell for call target
lrn@chromium.org34e60782011-09-15 07:25:40 +00004804 Label slow, non_function;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004805
danno@chromium.org40cb8782011-05-25 07:58:50 +00004806 // The receiver might implicitly be the global object. This is
4807 // indicated by passing the hole as the receiver to the call
4808 // function stub.
4809 if (ReceiverMightBeImplicit()) {
4810 Label call;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004811 // Get the receiver from the stack.
4812 // function, receiver [, arguments]
danno@chromium.org40cb8782011-05-25 07:58:50 +00004813 __ ldr(r4, MemOperand(sp, argc_ * kPointerSize));
4814 // Call as function is indicated with the hole.
4815 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
4816 __ b(ne, &call);
4817 // Patch the receiver on the stack with the global receiver object.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004818 __ ldr(r3,
4819 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004820 __ ldr(r3, FieldMemOperand(r3, GlobalObject::kGlobalReceiverOffset));
4821 __ str(r3, MemOperand(sp, argc_ * kPointerSize));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004822 __ bind(&call);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004823 }
4824
ricow@chromium.org65fae842010-08-25 15:26:24 +00004825 // Check that the function is really a JavaScript function.
4826 // r1: pushed function (to be verified)
lrn@chromium.org34e60782011-09-15 07:25:40 +00004827 __ JumpIfSmi(r1, &non_function);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004828 // Get the map of the function object.
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004829 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004830 __ b(ne, &slow);
4831
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004832 if (RecordCallTarget()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004833 if (FLAG_optimize_constructed_arrays) {
4834 GenerateRecordCallTarget(masm);
4835 } else {
4836 GenerateRecordCallTargetNoArray(masm);
4837 }
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004838 }
4839
ricow@chromium.org65fae842010-08-25 15:26:24 +00004840 // Fast-case: Invoke the function now.
4841 // r1: pushed function
4842 ParameterCount actual(argc_);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004843
4844 if (ReceiverMightBeImplicit()) {
4845 Label call_as_function;
4846 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
4847 __ b(eq, &call_as_function);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004848 __ InvokeFunction(r1,
4849 actual,
4850 JUMP_FUNCTION,
4851 NullCallWrapper(),
4852 CALL_AS_METHOD);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004853 __ bind(&call_as_function);
4854 }
4855 __ InvokeFunction(r1,
4856 actual,
4857 JUMP_FUNCTION,
4858 NullCallWrapper(),
4859 CALL_AS_FUNCTION);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004860
4861 // Slow-case: Non-function called.
4862 __ bind(&slow);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004863 if (RecordCallTarget()) {
4864 // If there is a call target cache, mark it megamorphic in the
4865 // non-function case. MegamorphicSentinel is an immortal immovable
4866 // object (undefined) so no write barrier is needed.
4867 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
4868 masm->isolate()->heap()->undefined_value());
4869 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
4870 __ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
4871 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00004872 // Check for function proxy.
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004873 __ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE));
lrn@chromium.org34e60782011-09-15 07:25:40 +00004874 __ b(ne, &non_function);
4875 __ push(r1); // put proxy as additional argument
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004876 __ mov(r0, Operand(argc_ + 1, RelocInfo::NONE32));
4877 __ mov(r2, Operand::Zero());
lrn@chromium.org34e60782011-09-15 07:25:40 +00004878 __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
danno@chromium.orgc612e022011-11-10 11:38:15 +00004879 __ SetCallKind(r5, CALL_AS_METHOD);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004880 {
4881 Handle<Code> adaptor =
4882 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
4883 __ Jump(adaptor, RelocInfo::CODE_TARGET);
4884 }
4885
ricow@chromium.org65fae842010-08-25 15:26:24 +00004886 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
4887 // of the original receiver from the call site).
lrn@chromium.org34e60782011-09-15 07:25:40 +00004888 __ bind(&non_function);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004889 __ str(r1, MemOperand(sp, argc_ * kPointerSize));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004890 __ mov(r0, Operand(argc_)); // Set up the number of arguments.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004891 __ mov(r2, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004892 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004893 __ SetCallKind(r5, CALL_AS_METHOD);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004894 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
ricow@chromium.org65fae842010-08-25 15:26:24 +00004895 RelocInfo::CODE_TARGET);
4896}
4897
4898
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004899void CallConstructStub::Generate(MacroAssembler* masm) {
4900 // r0 : number of arguments
4901 // r1 : the function to call
4902 // r2 : cache cell for call target
4903 Label slow, non_function_call;
4904
4905 // Check that the function is not a smi.
4906 __ JumpIfSmi(r1, &non_function_call);
4907 // Check that the function is a JSFunction.
4908 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
4909 __ b(ne, &slow);
4910
4911 if (RecordCallTarget()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004912 if (FLAG_optimize_constructed_arrays) {
4913 GenerateRecordCallTarget(masm);
4914 } else {
4915 GenerateRecordCallTargetNoArray(masm);
4916 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004917 }
4918
4919 // Jump to the function-specific construct stub.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004920 Register jmp_reg = FLAG_optimize_constructed_arrays ? r3 : r2;
4921 __ ldr(jmp_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
4922 __ ldr(jmp_reg, FieldMemOperand(jmp_reg,
4923 SharedFunctionInfo::kConstructStubOffset));
4924 __ add(pc, jmp_reg, Operand(Code::kHeaderSize - kHeapObjectTag));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004925
4926 // r0: number of arguments
4927 // r1: called object
4928 // r3: object type
4929 Label do_call;
4930 __ bind(&slow);
4931 __ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE));
4932 __ b(ne, &non_function_call);
4933 __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
4934 __ jmp(&do_call);
4935
4936 __ bind(&non_function_call);
4937 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
4938 __ bind(&do_call);
4939 // Set expected number of arguments to zero (not changing r0).
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004940 __ mov(r2, Operand::Zero());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004941 __ SetCallKind(r5, CALL_AS_METHOD);
4942 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
4943 RelocInfo::CODE_TARGET);
4944}
4945
4946
ricow@chromium.org65fae842010-08-25 15:26:24 +00004947// StringCharCodeAtGenerator
ricow@chromium.org65fae842010-08-25 15:26:24 +00004948void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
4949 Label flat_string;
4950 Label ascii_string;
4951 Label got_char_code;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004952 Label sliced_string;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004953
4954 // If the receiver is a smi trigger the non-string case.
ager@chromium.org378b34e2011-01-28 08:04:38 +00004955 __ JumpIfSmi(object_, receiver_not_string_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004956
4957 // Fetch the instance type of the receiver into result register.
4958 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
4959 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
4960 // If the receiver is not a string trigger the non-string case.
4961 __ tst(result_, Operand(kIsNotStringMask));
4962 __ b(ne, receiver_not_string_);
4963
4964 // If the index is non-smi trigger the non-smi case.
ager@chromium.org378b34e2011-01-28 08:04:38 +00004965 __ JumpIfNotSmi(index_, &index_not_smi_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004966 __ bind(&got_smi_index_);
4967
4968 // Check for index out of range.
4969 __ ldr(ip, FieldMemOperand(object_, String::kLengthOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00004970 __ cmp(ip, Operand(index_));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004971 __ b(ls, index_out_of_range_);
4972
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004973 __ mov(index_, Operand(index_, ASR, kSmiTagSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004974
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004975 StringCharLoadGenerator::Generate(masm,
4976 object_,
4977 index_,
4978 result_,
4979 &call_runtime_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004980
ricow@chromium.org65fae842010-08-25 15:26:24 +00004981 __ mov(result_, Operand(result_, LSL, kSmiTagSize));
4982 __ bind(&exit_);
4983}
4984
4985
4986void StringCharCodeAtGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004987 MacroAssembler* masm,
4988 const RuntimeCallHelper& call_helper) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004989 __ Abort("Unexpected fallthrough to CharCodeAt slow case");
4990
4991 // Index is not a smi.
4992 __ bind(&index_not_smi_);
4993 // If index is a heap number, try converting it to an integer.
4994 __ CheckMap(index_,
danno@chromium.orgc612e022011-11-10 11:38:15 +00004995 result_,
ricow@chromium.org65fae842010-08-25 15:26:24 +00004996 Heap::kHeapNumberMapRootIndex,
4997 index_not_number_,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004998 DONT_DO_SMI_CHECK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004999 call_helper.BeforeCall(masm);
danno@chromium.orgc612e022011-11-10 11:38:15 +00005000 __ push(object_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005001 __ push(index_); // Consumed by runtime conversion function.
5002 if (index_flags_ == STRING_INDEX_IS_NUMBER) {
5003 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
5004 } else {
5005 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
5006 // NumberToSmi discards numbers that are not exact integers.
5007 __ CallRuntime(Runtime::kNumberToSmi, 1);
5008 }
5009 // Save the conversion result before the pop instructions below
5010 // have a chance to overwrite it.
danno@chromium.orgc612e022011-11-10 11:38:15 +00005011 __ Move(index_, r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005012 __ pop(object_);
5013 // Reload the instance type.
5014 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
5015 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
5016 call_helper.AfterCall(masm);
5017 // If index is still not a smi, it must be out of range.
danno@chromium.orgc612e022011-11-10 11:38:15 +00005018 __ JumpIfNotSmi(index_, index_out_of_range_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005019 // Otherwise, return to the fast path.
5020 __ jmp(&got_smi_index_);
5021
5022 // Call runtime. We get here when the receiver is a string and the
5023 // index is a number, but the code of getting the actual character
5024 // is too complex (e.g., when the string needs to be flattened).
5025 __ bind(&call_runtime_);
5026 call_helper.BeforeCall(masm);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005027 __ mov(index_, Operand(index_, LSL, kSmiTagSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005028 __ Push(object_, index_);
5029 __ CallRuntime(Runtime::kStringCharCodeAt, 2);
5030 __ Move(result_, r0);
5031 call_helper.AfterCall(masm);
5032 __ jmp(&exit_);
5033
5034 __ Abort("Unexpected fallthrough from CharCodeAt slow case");
5035}
5036
5037
5038// -------------------------------------------------------------------------
5039// StringCharFromCodeGenerator
5040
5041void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
5042 // Fast case of Heap::LookupSingleCharacterStringFromCode.
5043 STATIC_ASSERT(kSmiTag == 0);
5044 STATIC_ASSERT(kSmiShiftSize == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005045 ASSERT(IsPowerOf2(String::kMaxOneByteCharCode + 1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005046 __ tst(code_,
5047 Operand(kSmiTagMask |
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005048 ((~String::kMaxOneByteCharCode) << kSmiTagSize)));
ager@chromium.org378b34e2011-01-28 08:04:38 +00005049 __ b(ne, &slow_case_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005050
5051 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005052 // At this point code register contains smi tagged ASCII char code.
ricow@chromium.org65fae842010-08-25 15:26:24 +00005053 STATIC_ASSERT(kSmiTag == 0);
5054 __ add(result_, result_, Operand(code_, LSL, kPointerSizeLog2 - kSmiTagSize));
5055 __ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005056 __ CompareRoot(result_, Heap::kUndefinedValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005057 __ b(eq, &slow_case_);
5058 __ bind(&exit_);
5059}
5060
5061
5062void StringCharFromCodeGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005063 MacroAssembler* masm,
5064 const RuntimeCallHelper& call_helper) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00005065 __ Abort("Unexpected fallthrough to CharFromCode slow case");
5066
5067 __ bind(&slow_case_);
5068 call_helper.BeforeCall(masm);
5069 __ push(code_);
5070 __ CallRuntime(Runtime::kCharFromCode, 1);
5071 __ Move(result_, r0);
5072 call_helper.AfterCall(masm);
5073 __ jmp(&exit_);
5074
5075 __ Abort("Unexpected fallthrough from CharFromCode slow case");
5076}
5077
5078
ricow@chromium.org65fae842010-08-25 15:26:24 +00005079void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
5080 Register dest,
5081 Register src,
5082 Register count,
5083 Register scratch,
5084 bool ascii) {
5085 Label loop;
5086 Label done;
5087 // This loop just copies one character at a time, as it is only used for very
5088 // short strings.
5089 if (!ascii) {
5090 __ add(count, count, Operand(count), SetCC);
5091 } else {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005092 __ cmp(count, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00005093 }
5094 __ b(eq, &done);
5095
5096 __ bind(&loop);
5097 __ ldrb(scratch, MemOperand(src, 1, PostIndex));
5098 // Perform sub between load and dependent store to get the load time to
5099 // complete.
5100 __ sub(count, count, Operand(1), SetCC);
5101 __ strb(scratch, MemOperand(dest, 1, PostIndex));
5102 // last iteration.
5103 __ b(gt, &loop);
5104
5105 __ bind(&done);
5106}
5107
5108
5109enum CopyCharactersFlags {
5110 COPY_ASCII = 1,
5111 DEST_ALWAYS_ALIGNED = 2
5112};
5113
5114
5115void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm,
5116 Register dest,
5117 Register src,
5118 Register count,
5119 Register scratch1,
5120 Register scratch2,
5121 Register scratch3,
5122 Register scratch4,
5123 Register scratch5,
5124 int flags) {
5125 bool ascii = (flags & COPY_ASCII) != 0;
5126 bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0;
5127
5128 if (dest_always_aligned && FLAG_debug_code) {
5129 // Check that destination is actually word aligned if the flag says
5130 // that it is.
5131 __ tst(dest, Operand(kPointerAlignmentMask));
5132 __ Check(eq, "Destination of copy not aligned.");
5133 }
5134
5135 const int kReadAlignment = 4;
5136 const int kReadAlignmentMask = kReadAlignment - 1;
5137 // Ensure that reading an entire aligned word containing the last character
5138 // of a string will not read outside the allocated area (because we pad up
5139 // to kObjectAlignment).
5140 STATIC_ASSERT(kObjectAlignment >= kReadAlignment);
5141 // Assumes word reads and writes are little endian.
5142 // Nothing to do for zero characters.
5143 Label done;
5144 if (!ascii) {
5145 __ add(count, count, Operand(count), SetCC);
5146 } else {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005147 __ cmp(count, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00005148 }
5149 __ b(eq, &done);
5150
5151 // Assume that you cannot read (or write) unaligned.
5152 Label byte_loop;
5153 // Must copy at least eight bytes, otherwise just do it one byte at a time.
5154 __ cmp(count, Operand(8));
5155 __ add(count, dest, Operand(count));
5156 Register limit = count; // Read until src equals this.
5157 __ b(lt, &byte_loop);
5158
5159 if (!dest_always_aligned) {
5160 // Align dest by byte copying. Copies between zero and three bytes.
5161 __ and_(scratch4, dest, Operand(kReadAlignmentMask), SetCC);
5162 Label dest_aligned;
5163 __ b(eq, &dest_aligned);
5164 __ cmp(scratch4, Operand(2));
5165 __ ldrb(scratch1, MemOperand(src, 1, PostIndex));
5166 __ ldrb(scratch2, MemOperand(src, 1, PostIndex), le);
5167 __ ldrb(scratch3, MemOperand(src, 1, PostIndex), lt);
5168 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
5169 __ strb(scratch2, MemOperand(dest, 1, PostIndex), le);
5170 __ strb(scratch3, MemOperand(dest, 1, PostIndex), lt);
5171 __ bind(&dest_aligned);
5172 }
5173
5174 Label simple_loop;
5175
5176 __ sub(scratch4, dest, Operand(src));
5177 __ and_(scratch4, scratch4, Operand(0x03), SetCC);
5178 __ b(eq, &simple_loop);
5179 // Shift register is number of bits in a source word that
5180 // must be combined with bits in the next source word in order
5181 // to create a destination word.
5182
5183 // Complex loop for src/dst that are not aligned the same way.
5184 {
5185 Label loop;
5186 __ mov(scratch4, Operand(scratch4, LSL, 3));
5187 Register left_shift = scratch4;
5188 __ and_(src, src, Operand(~3)); // Round down to load previous word.
5189 __ ldr(scratch1, MemOperand(src, 4, PostIndex));
5190 // Store the "shift" most significant bits of scratch in the least
5191 // signficant bits (i.e., shift down by (32-shift)).
5192 __ rsb(scratch2, left_shift, Operand(32));
5193 Register right_shift = scratch2;
5194 __ mov(scratch1, Operand(scratch1, LSR, right_shift));
5195
5196 __ bind(&loop);
5197 __ ldr(scratch3, MemOperand(src, 4, PostIndex));
5198 __ sub(scratch5, limit, Operand(dest));
5199 __ orr(scratch1, scratch1, Operand(scratch3, LSL, left_shift));
5200 __ str(scratch1, MemOperand(dest, 4, PostIndex));
5201 __ mov(scratch1, Operand(scratch3, LSR, right_shift));
5202 // Loop if four or more bytes left to copy.
5203 // Compare to eight, because we did the subtract before increasing dst.
5204 __ sub(scratch5, scratch5, Operand(8), SetCC);
5205 __ b(ge, &loop);
5206 }
5207 // There is now between zero and three bytes left to copy (negative that
5208 // number is in scratch5), and between one and three bytes already read into
5209 // scratch1 (eight times that number in scratch4). We may have read past
5210 // the end of the string, but because objects are aligned, we have not read
5211 // past the end of the object.
5212 // Find the minimum of remaining characters to move and preloaded characters
5213 // and write those as bytes.
5214 __ add(scratch5, scratch5, Operand(4), SetCC);
5215 __ b(eq, &done);
5216 __ cmp(scratch4, Operand(scratch5, LSL, 3), ne);
5217 // Move minimum of bytes read and bytes left to copy to scratch4.
5218 __ mov(scratch5, Operand(scratch4, LSR, 3), LeaveCC, lt);
5219 // Between one and three (value in scratch5) characters already read into
5220 // scratch ready to write.
5221 __ cmp(scratch5, Operand(2));
5222 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
5223 __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, ge);
5224 __ strb(scratch1, MemOperand(dest, 1, PostIndex), ge);
5225 __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, gt);
5226 __ strb(scratch1, MemOperand(dest, 1, PostIndex), gt);
5227 // Copy any remaining bytes.
5228 __ b(&byte_loop);
5229
5230 // Simple loop.
5231 // Copy words from src to dst, until less than four bytes left.
5232 // Both src and dest are word aligned.
5233 __ bind(&simple_loop);
5234 {
5235 Label loop;
5236 __ bind(&loop);
5237 __ ldr(scratch1, MemOperand(src, 4, PostIndex));
5238 __ sub(scratch3, limit, Operand(dest));
5239 __ str(scratch1, MemOperand(dest, 4, PostIndex));
5240 // Compare to 8, not 4, because we do the substraction before increasing
5241 // dest.
5242 __ cmp(scratch3, Operand(8));
5243 __ b(ge, &loop);
5244 }
5245
5246 // Copy bytes from src to dst until dst hits limit.
5247 __ bind(&byte_loop);
5248 __ cmp(dest, Operand(limit));
5249 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt);
5250 __ b(ge, &done);
5251 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
5252 __ b(&byte_loop);
5253
5254 __ bind(&done);
5255}
5256
5257
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005258void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
ricow@chromium.org65fae842010-08-25 15:26:24 +00005259 Register c1,
5260 Register c2,
5261 Register scratch1,
5262 Register scratch2,
5263 Register scratch3,
5264 Register scratch4,
5265 Register scratch5,
5266 Label* not_found) {
5267 // Register scratch3 is the general scratch register in this function.
5268 Register scratch = scratch3;
5269
5270 // Make sure that both characters are not digits as such strings has a
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005271 // different hash algorithm. Don't try to look for these in the string table.
ricow@chromium.org65fae842010-08-25 15:26:24 +00005272 Label not_array_index;
5273 __ sub(scratch, c1, Operand(static_cast<int>('0')));
5274 __ cmp(scratch, Operand(static_cast<int>('9' - '0')));
5275 __ b(hi, &not_array_index);
5276 __ sub(scratch, c2, Operand(static_cast<int>('0')));
5277 __ cmp(scratch, Operand(static_cast<int>('9' - '0')));
5278
5279 // If check failed combine both characters into single halfword.
5280 // This is required by the contract of the method: code at the
5281 // not_found branch expects this combination in c1 register
5282 __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls);
5283 __ b(ls, not_found);
5284
5285 __ bind(&not_array_index);
5286 // Calculate the two character string hash.
5287 Register hash = scratch1;
5288 StringHelper::GenerateHashInit(masm, hash, c1);
5289 StringHelper::GenerateHashAddCharacter(masm, hash, c2);
5290 StringHelper::GenerateHashGetHash(masm, hash);
5291
5292 // Collect the two characters in a register.
5293 Register chars = c1;
5294 __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte));
5295
5296 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
5297 // hash: hash of two character string.
5298
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005299 // Load string table
5300 // Load address of first element of the string table.
5301 Register string_table = c2;
5302 __ LoadRoot(string_table, Heap::kStringTableRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005303
ricow@chromium.org65fae842010-08-25 15:26:24 +00005304 Register undefined = scratch4;
5305 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
5306
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005307 // Calculate capacity mask from the string table capacity.
ricow@chromium.org65fae842010-08-25 15:26:24 +00005308 Register mask = scratch2;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005309 __ ldr(mask, FieldMemOperand(string_table, StringTable::kCapacityOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005310 __ mov(mask, Operand(mask, ASR, 1));
5311 __ sub(mask, mask, Operand(1));
5312
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005313 // Calculate untagged address of the first element of the string table.
5314 Register first_string_table_element = string_table;
5315 __ add(first_string_table_element, string_table,
5316 Operand(StringTable::kElementsStartOffset - kHeapObjectTag));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005317
5318 // Registers
5319 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
5320 // hash: hash of two character string
5321 // mask: capacity mask
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005322 // first_string_table_element: address of the first element of
5323 // the string table
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005324 // undefined: the undefined object
ricow@chromium.org65fae842010-08-25 15:26:24 +00005325 // scratch: -
5326
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005327 // Perform a number of probes in the string table.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005328 const int kProbes = 4;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005329 Label found_in_string_table;
ricow@chromium.org65fae842010-08-25 15:26:24 +00005330 Label next_probe[kProbes];
danno@chromium.org2c456792011-11-11 12:00:53 +00005331 Register candidate = scratch5; // Scratch register contains candidate.
ricow@chromium.org65fae842010-08-25 15:26:24 +00005332 for (int i = 0; i < kProbes; i++) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005333 // Calculate entry in string table.
ricow@chromium.org65fae842010-08-25 15:26:24 +00005334 if (i > 0) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005335 __ add(candidate, hash, Operand(StringTable::GetProbeOffset(i)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005336 } else {
5337 __ mov(candidate, hash);
5338 }
5339
5340 __ and_(candidate, candidate, Operand(mask));
5341
5342 // Load the entry from the symble table.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005343 STATIC_ASSERT(StringTable::kEntrySize == 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005344 __ ldr(candidate,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005345 MemOperand(first_string_table_element,
ricow@chromium.org65fae842010-08-25 15:26:24 +00005346 candidate,
5347 LSL,
5348 kPointerSizeLog2));
5349
5350 // If entry is undefined no string with this hash can be found.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005351 Label is_string;
5352 __ CompareObjectType(candidate, scratch, scratch, ODDBALL_TYPE);
5353 __ b(ne, &is_string);
5354
5355 __ cmp(undefined, candidate);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005356 __ b(eq, not_found);
danno@chromium.org2c456792011-11-11 12:00:53 +00005357 // Must be the hole (deleted entry).
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005358 if (FLAG_debug_code) {
danno@chromium.org2c456792011-11-11 12:00:53 +00005359 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005360 __ cmp(ip, candidate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005361 __ Assert(eq, "oddball in string table is not undefined or the hole");
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005362 }
5363 __ jmp(&next_probe[i]);
5364
5365 __ bind(&is_string);
5366
5367 // Check that the candidate is a non-external ASCII string. The instance
5368 // type is still in the scratch register from the CompareObjectType
5369 // operation.
5370 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &next_probe[i]);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005371
5372 // If length is not 2 the string is not a candidate.
5373 __ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset));
5374 __ cmp(scratch, Operand(Smi::FromInt(2)));
5375 __ b(ne, &next_probe[i]);
5376
ricow@chromium.org65fae842010-08-25 15:26:24 +00005377 // Check if the two characters match.
5378 // Assumes that word load is little endian.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005379 __ ldrh(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005380 __ cmp(chars, scratch);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005381 __ b(eq, &found_in_string_table);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005382 __ bind(&next_probe[i]);
5383 }
5384
5385 // No matching 2 character string found by probing.
5386 __ jmp(not_found);
5387
5388 // Scratch register contains result when we fall through to here.
danno@chromium.org2c456792011-11-11 12:00:53 +00005389 Register result = candidate;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005390 __ bind(&found_in_string_table);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005391 __ Move(r0, result);
5392}
5393
5394
5395void StringHelper::GenerateHashInit(MacroAssembler* masm,
5396 Register hash,
5397 Register character) {
5398 // hash = character + (character << 10);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005399 __ LoadRoot(hash, Heap::kHashSeedRootIndex);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00005400 // Untag smi seed and add the character.
5401 __ add(hash, character, Operand(hash, LSR, kSmiTagSize));
5402 // hash += hash << 10;
5403 __ add(hash, hash, Operand(hash, LSL, 10));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005404 // hash ^= hash >> 6;
danno@chromium.org2c456792011-11-11 12:00:53 +00005405 __ eor(hash, hash, Operand(hash, LSR, 6));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005406}
5407
5408
5409void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
5410 Register hash,
5411 Register character) {
5412 // hash += character;
5413 __ add(hash, hash, Operand(character));
5414 // hash += hash << 10;
5415 __ add(hash, hash, Operand(hash, LSL, 10));
5416 // hash ^= hash >> 6;
danno@chromium.org2c456792011-11-11 12:00:53 +00005417 __ eor(hash, hash, Operand(hash, LSR, 6));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005418}
5419
5420
5421void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
5422 Register hash) {
5423 // hash += hash << 3;
5424 __ add(hash, hash, Operand(hash, LSL, 3));
5425 // hash ^= hash >> 11;
danno@chromium.org2c456792011-11-11 12:00:53 +00005426 __ eor(hash, hash, Operand(hash, LSR, 11));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005427 // hash += hash << 15;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005428 __ add(hash, hash, Operand(hash, LSL, 15));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005429
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005430 __ and_(hash, hash, Operand(String::kHashBitMask), SetCC);
danno@chromium.org2c456792011-11-11 12:00:53 +00005431
ricow@chromium.org65fae842010-08-25 15:26:24 +00005432 // if (hash == 0) hash = 27;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005433 __ mov(hash, Operand(StringHasher::kZeroHash), LeaveCC, eq);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005434}
5435
5436
5437void SubStringStub::Generate(MacroAssembler* masm) {
5438 Label runtime;
5439
5440 // Stack frame on entry.
5441 // lr: return address
5442 // sp[0]: to
5443 // sp[4]: from
5444 // sp[8]: string
5445
5446 // This stub is called from the native-call %_SubString(...), so
5447 // nothing can be assumed about the arguments. It is tested that:
5448 // "string" is a sequential string,
5449 // both "from" and "to" are smis, and
5450 // 0 <= from <= to <= string.length.
5451 // If any of these assumptions fail, we call the runtime system.
5452
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005453 const int kToOffset = 0 * kPointerSize;
5454 const int kFromOffset = 1 * kPointerSize;
5455 const int kStringOffset = 2 * kPointerSize;
ricow@chromium.org65fae842010-08-25 15:26:24 +00005456
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005457 __ Ldrd(r2, r3, MemOperand(sp, kToOffset));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005458 STATIC_ASSERT(kFromOffset == kToOffset + 4);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005459 STATIC_ASSERT(kSmiTag == 0);
5460 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00005461
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005462 // Arithmetic shift right by one un-smi-tags. In this case we rotate right
5463 // instead because we bail out on non-smi values: ROR and ASR are equivalent
5464 // for smis but they set the flags in a way that's easier to optimize.
5465 __ mov(r2, Operand(r2, ROR, 1), SetCC);
5466 __ mov(r3, Operand(r3, ROR, 1), SetCC, cc);
5467 // If either to or from had the smi tag bit set, then C is set now, and N
5468 // 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 +00005469 // We want to bailout to runtime here if From is negative. In that case, the
5470 // next instruction is not executed and we fall through to bailing out to
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005471 // runtime.
5472 // Executed if both r2 and r3 are untagged integers.
5473 __ sub(r2, r2, Operand(r3), SetCC, cc);
5474 // One of the above un-smis or the above SUB could have set N==1.
5475 __ b(mi, &runtime); // Either "from" or "to" is not an smi, or from > to.
ricow@chromium.org65fae842010-08-25 15:26:24 +00005476
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005477 // Make sure first argument is a string.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00005478 __ ldr(r0, MemOperand(sp, kStringOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005479 STATIC_ASSERT(kSmiTag == 0);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005480 // Do a JumpIfSmi, but fold its jump into the subsequent string test.
5481 __ tst(r0, Operand(kSmiTagMask));
5482 Condition is_string = masm->IsObjectStringType(r0, r1, ne);
5483 ASSERT(is_string == eq);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005484 __ b(NegateCondition(is_string), &runtime);
5485
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005486 Label single_char;
5487 __ cmp(r2, Operand(1));
5488 __ b(eq, &single_char);
5489
fschneider@chromium.org1805e212011-09-05 10:49:12 +00005490 // Short-cut for the case of trivial substring.
5491 Label return_r0;
5492 // r0: original string
5493 // r2: result string length
5494 __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset));
5495 __ cmp(r2, Operand(r4, ASR, 1));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005496 // Return original string.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00005497 __ b(eq, &return_r0);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005498 // Longer than original string's length or negative: unsafe arguments.
5499 __ b(hi, &runtime);
5500 // Shorter than original string's length: an actual substring.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00005501
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005502 // Deal with different string types: update the index if necessary
5503 // and put the underlying string into r5.
5504 // r0: original string
5505 // r1: instance type
5506 // r2: length
5507 // r3: from index (untagged)
5508 Label underlying_unpacked, sliced_string, seq_or_external_string;
5509 // If the string is not indirect, it can only be sequential or external.
5510 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
5511 STATIC_ASSERT(kIsIndirectStringMask != 0);
5512 __ tst(r1, Operand(kIsIndirectStringMask));
5513 __ b(eq, &seq_or_external_string);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005514
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005515 __ tst(r1, Operand(kSlicedNotConsMask));
5516 __ b(ne, &sliced_string);
5517 // Cons string. Check whether it is flat, then fetch first part.
5518 __ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005519 __ CompareRoot(r5, Heap::kempty_stringRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005520 __ b(ne, &runtime);
5521 __ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset));
5522 // Update instance type.
5523 __ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset));
5524 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
5525 __ jmp(&underlying_unpacked);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00005526
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005527 __ bind(&sliced_string);
5528 // Sliced string. Fetch parent and correct start index by offset.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005529 __ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005530 __ ldr(r4, FieldMemOperand(r0, SlicedString::kOffsetOffset));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005531 __ add(r3, r3, Operand(r4, ASR, 1)); // Add offset to index.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005532 // Update instance type.
5533 __ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset));
5534 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
5535 __ jmp(&underlying_unpacked);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005536
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005537 __ bind(&seq_or_external_string);
5538 // Sequential or external string. Just move string to the expected register.
5539 __ mov(r5, r0);
5540
5541 __ bind(&underlying_unpacked);
5542
5543 if (FLAG_string_slices) {
5544 Label copy_routine;
5545 // r5: underlying subject string
5546 // r1: instance type of underlying subject string
5547 // r2: length
5548 // r3: adjusted start index (untagged)
5549 __ cmp(r2, Operand(SlicedString::kMinLength));
5550 // Short slice. Copy instead of slicing.
5551 __ b(lt, &copy_routine);
5552 // Allocate new sliced string. At this point we do not reload the instance
5553 // type including the string encoding because we simply rely on the info
5554 // provided by the original string. It does not matter if the original
5555 // string's encoding is wrong because we always have to recheck encoding of
5556 // the newly created string's parent anyways due to externalized strings.
5557 Label two_byte_slice, set_slice_header;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005558 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005559 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
5560 __ tst(r1, Operand(kStringEncodingMask));
5561 __ b(eq, &two_byte_slice);
5562 __ AllocateAsciiSlicedString(r0, r2, r6, r7, &runtime);
5563 __ jmp(&set_slice_header);
5564 __ bind(&two_byte_slice);
5565 __ AllocateTwoByteSlicedString(r0, r2, r6, r7, &runtime);
5566 __ bind(&set_slice_header);
5567 __ mov(r3, Operand(r3, LSL, 1));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005568 __ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005569 __ str(r3, FieldMemOperand(r0, SlicedString::kOffsetOffset));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005570 __ jmp(&return_r0);
5571
5572 __ bind(&copy_routine);
5573 }
5574
5575 // r5: underlying subject string
5576 // r1: instance type of underlying subject string
5577 // r2: length
5578 // r3: adjusted start index (untagged)
5579 Label two_byte_sequential, sequential_string, allocate_result;
5580 STATIC_ASSERT(kExternalStringTag != 0);
5581 STATIC_ASSERT(kSeqStringTag == 0);
5582 __ tst(r1, Operand(kExternalStringTag));
5583 __ b(eq, &sequential_string);
5584
5585 // Handle external string.
5586 // Rule out short external strings.
5587 STATIC_CHECK(kShortExternalStringTag != 0);
5588 __ tst(r1, Operand(kShortExternalStringTag));
5589 __ b(ne, &runtime);
5590 __ ldr(r5, FieldMemOperand(r5, ExternalString::kResourceDataOffset));
5591 // r5 already points to the first character of underlying string.
5592 __ jmp(&allocate_result);
5593
5594 __ bind(&sequential_string);
5595 // Locate first character of underlying subject string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005596 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
5597 __ add(r5, r5, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005598
5599 __ bind(&allocate_result);
5600 // Sequential acii string. Allocate the result.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005601 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005602 __ tst(r1, Operand(kStringEncodingMask));
5603 __ b(eq, &two_byte_sequential);
5604
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005605 // Allocate and copy the resulting ASCII string.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005606 __ AllocateAsciiString(r0, r2, r4, r6, r7, &runtime);
5607
5608 // Locate first character of substring to copy.
5609 __ add(r5, r5, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005610 // Locate first character of result.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005611 __ add(r1, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005612
fschneider@chromium.org1805e212011-09-05 10:49:12 +00005613 // r0: result string
5614 // r1: first character of result string
5615 // r2: result string length
5616 // r5: first character of substring to copy
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005617 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005618 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
5619 COPY_ASCII | DEST_ALWAYS_ALIGNED);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00005620 __ jmp(&return_r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005621
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005622 // Allocate and copy the resulting two-byte string.
5623 __ bind(&two_byte_sequential);
5624 __ AllocateTwoByteString(r0, r2, r4, r6, r7, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005625
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005626 // Locate first character of substring to copy.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00005627 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005628 __ add(r5, r5, Operand(r3, LSL, 1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005629 // Locate first character of result.
5630 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00005631
ricow@chromium.org65fae842010-08-25 15:26:24 +00005632 // r0: result string.
5633 // r1: first character of result.
5634 // r2: result length.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00005635 // r5: first character of substring to copy.
ricow@chromium.org65fae842010-08-25 15:26:24 +00005636 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005637 StringHelper::GenerateCopyCharactersLong(
5638 masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00005639
5640 __ bind(&return_r0);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005641 Counters* counters = masm->isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005642 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005643 __ Drop(3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005644 __ Ret();
5645
5646 // Just jump to runtime to create the sub string.
5647 __ bind(&runtime);
5648 __ TailCallRuntime(Runtime::kSubString, 3, 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005649
5650 __ bind(&single_char);
5651 // r0: original string
5652 // r1: instance type
5653 // r2: length
5654 // r3: from index (untagged)
5655 __ SmiTag(r3, r3);
5656 StringCharAtGenerator generator(
5657 r0, r3, r2, r0, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
5658 generator.GenerateFast(masm);
5659 __ Drop(3);
5660 __ Ret();
5661 generator.SkipSlow(masm, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005662}
5663
5664
lrn@chromium.org1c092762011-05-09 09:42:16 +00005665void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
5666 Register left,
5667 Register right,
5668 Register scratch1,
5669 Register scratch2,
5670 Register scratch3) {
5671 Register length = scratch1;
5672
5673 // Compare lengths.
5674 Label strings_not_equal, check_zero_length;
5675 __ ldr(length, FieldMemOperand(left, String::kLengthOffset));
5676 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset));
5677 __ cmp(length, scratch2);
5678 __ b(eq, &check_zero_length);
5679 __ bind(&strings_not_equal);
5680 __ mov(r0, Operand(Smi::FromInt(NOT_EQUAL)));
5681 __ Ret();
5682
5683 // Check if the length is zero.
5684 Label compare_chars;
5685 __ bind(&check_zero_length);
5686 STATIC_ASSERT(kSmiTag == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005687 __ cmp(length, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00005688 __ b(ne, &compare_chars);
5689 __ mov(r0, Operand(Smi::FromInt(EQUAL)));
5690 __ Ret();
5691
5692 // Compare characters.
5693 __ bind(&compare_chars);
5694 GenerateAsciiCharsCompareLoop(masm,
5695 left, right, length, scratch2, scratch3,
5696 &strings_not_equal);
5697
5698 // Characters are equal.
5699 __ mov(r0, Operand(Smi::FromInt(EQUAL)));
5700 __ Ret();
5701}
5702
5703
ricow@chromium.org65fae842010-08-25 15:26:24 +00005704void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
5705 Register left,
5706 Register right,
5707 Register scratch1,
5708 Register scratch2,
5709 Register scratch3,
5710 Register scratch4) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00005711 Label result_not_equal, compare_lengths;
ricow@chromium.org65fae842010-08-25 15:26:24 +00005712 // Find minimum length and length difference.
5713 __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset));
5714 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset));
5715 __ sub(scratch3, scratch1, Operand(scratch2), SetCC);
5716 Register length_delta = scratch3;
5717 __ mov(scratch1, scratch2, LeaveCC, gt);
5718 Register min_length = scratch1;
5719 STATIC_ASSERT(kSmiTag == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005720 __ cmp(min_length, Operand::Zero());
ricow@chromium.org65fae842010-08-25 15:26:24 +00005721 __ b(eq, &compare_lengths);
5722
lrn@chromium.org1c092762011-05-09 09:42:16 +00005723 // Compare loop.
5724 GenerateAsciiCharsCompareLoop(masm,
5725 left, right, min_length, scratch2, scratch4,
5726 &result_not_equal);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005727
lrn@chromium.org1c092762011-05-09 09:42:16 +00005728 // Compare lengths - strings up to min-length are equal.
ricow@chromium.org65fae842010-08-25 15:26:24 +00005729 __ bind(&compare_lengths);
5730 ASSERT(Smi::FromInt(EQUAL) == static_cast<Smi*>(0));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005731 // Use length_delta as result if it's zero.
5732 __ mov(r0, Operand(length_delta), SetCC);
5733 __ bind(&result_not_equal);
5734 // Conditionally update the result based either on length_delta or
5735 // the last comparion performed in the loop above.
ricow@chromium.org65fae842010-08-25 15:26:24 +00005736 __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt);
5737 __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt);
5738 __ Ret();
5739}
5740
5741
lrn@chromium.org1c092762011-05-09 09:42:16 +00005742void StringCompareStub::GenerateAsciiCharsCompareLoop(
5743 MacroAssembler* masm,
5744 Register left,
5745 Register right,
5746 Register length,
5747 Register scratch1,
5748 Register scratch2,
5749 Label* chars_not_equal) {
5750 // Change index to run from -length to -1 by adding length to string
5751 // start. This means that loop ends when index reaches zero, which
5752 // doesn't need an additional compare.
5753 __ SmiUntag(length);
5754 __ add(scratch1, length,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005755 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
lrn@chromium.org1c092762011-05-09 09:42:16 +00005756 __ add(left, left, Operand(scratch1));
5757 __ add(right, right, Operand(scratch1));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005758 __ rsb(length, length, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00005759 Register index = length; // index = -length;
5760
5761 // Compare loop.
5762 Label loop;
5763 __ bind(&loop);
5764 __ ldrb(scratch1, MemOperand(left, index));
5765 __ ldrb(scratch2, MemOperand(right, index));
5766 __ cmp(scratch1, scratch2);
5767 __ b(ne, chars_not_equal);
5768 __ add(index, index, Operand(1), SetCC);
5769 __ b(ne, &loop);
5770}
5771
5772
ricow@chromium.org65fae842010-08-25 15:26:24 +00005773void StringCompareStub::Generate(MacroAssembler* masm) {
5774 Label runtime;
5775
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005776 Counters* counters = masm->isolate()->counters();
5777
ricow@chromium.org65fae842010-08-25 15:26:24 +00005778 // Stack frame on entry.
5779 // sp[0]: right string
5780 // sp[4]: left string
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005781 __ Ldrd(r0 , r1, MemOperand(sp)); // Load right in r0, left in r1.
ricow@chromium.org65fae842010-08-25 15:26:24 +00005782
5783 Label not_same;
5784 __ cmp(r0, r1);
5785 __ b(ne, &not_same);
5786 STATIC_ASSERT(EQUAL == 0);
5787 STATIC_ASSERT(kSmiTag == 0);
5788 __ mov(r0, Operand(Smi::FromInt(EQUAL)));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005789 __ IncrementCounter(counters->string_compare_native(), 1, r1, r2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005790 __ add(sp, sp, Operand(2 * kPointerSize));
5791 __ Ret();
5792
5793 __ bind(&not_same);
5794
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005795 // Check that both objects are sequential ASCII strings.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005796 __ JumpIfNotBothSequentialAsciiStrings(r1, r0, r2, r3, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005797
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005798 // Compare flat ASCII strings natively. Remove arguments from stack first.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005799 __ IncrementCounter(counters->string_compare_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005800 __ add(sp, sp, Operand(2 * kPointerSize));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005801 GenerateCompareFlatAsciiStrings(masm, r1, r0, r2, r3, r4, r5);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005802
5803 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
5804 // tagged as a small integer.
5805 __ bind(&runtime);
5806 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
5807}
5808
5809
5810void StringAddStub::Generate(MacroAssembler* masm) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005811 Label call_runtime, call_builtin;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005812 Builtins::JavaScript builtin_id = Builtins::ADD;
5813
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005814 Counters* counters = masm->isolate()->counters();
5815
ricow@chromium.org65fae842010-08-25 15:26:24 +00005816 // Stack on entry:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005817 // sp[0]: second argument (right).
5818 // sp[4]: first argument (left).
ricow@chromium.org65fae842010-08-25 15:26:24 +00005819
5820 // Load the two arguments.
5821 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument.
5822 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument.
5823
5824 // Make sure that both arguments are strings if not known in advance.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005825 if (flags_ == NO_STRING_ADD_FLAGS) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005826 __ JumpIfEitherSmi(r0, r1, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005827 // Load instance types.
5828 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
5829 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
5830 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
5831 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
5832 STATIC_ASSERT(kStringTag == 0);
5833 // If either is not a string, go to runtime.
5834 __ tst(r4, Operand(kIsNotStringMask));
5835 __ tst(r5, Operand(kIsNotStringMask), eq);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005836 __ b(ne, &call_runtime);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005837 } else {
5838 // Here at least one of the arguments is definitely a string.
5839 // We convert the one that is not known to be a string.
5840 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) {
5841 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0);
5842 GenerateConvertArgument(
5843 masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &call_builtin);
5844 builtin_id = Builtins::STRING_ADD_RIGHT;
5845 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) {
5846 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0);
5847 GenerateConvertArgument(
5848 masm, 0 * kPointerSize, r1, r2, r3, r4, r5, &call_builtin);
5849 builtin_id = Builtins::STRING_ADD_LEFT;
5850 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00005851 }
5852
5853 // Both arguments are strings.
5854 // r0: first string
5855 // r1: second string
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005856 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
5857 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
ricow@chromium.org65fae842010-08-25 15:26:24 +00005858 {
5859 Label strings_not_empty;
5860 // Check if either of the strings are empty. In that case return the other.
5861 __ ldr(r2, FieldMemOperand(r0, String::kLengthOffset));
5862 __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset));
5863 STATIC_ASSERT(kSmiTag == 0);
5864 __ cmp(r2, Operand(Smi::FromInt(0))); // Test if first string is empty.
5865 __ mov(r0, Operand(r1), LeaveCC, eq); // If first is empty, return second.
5866 STATIC_ASSERT(kSmiTag == 0);
5867 // Else test if second string is empty.
5868 __ cmp(r3, Operand(Smi::FromInt(0)), ne);
5869 __ b(ne, &strings_not_empty); // If either string was empty, return r0.
5870
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005871 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005872 __ add(sp, sp, Operand(2 * kPointerSize));
5873 __ Ret();
5874
5875 __ bind(&strings_not_empty);
5876 }
5877
5878 __ mov(r2, Operand(r2, ASR, kSmiTagSize));
5879 __ mov(r3, Operand(r3, ASR, kSmiTagSize));
5880 // Both strings are non-empty.
5881 // r0: first string
5882 // r1: second string
5883 // r2: length of first string
5884 // r3: length of second string
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005885 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
5886 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
ricow@chromium.org65fae842010-08-25 15:26:24 +00005887 // Look at the length of the result of adding the two strings.
5888 Label string_add_flat_result, longer_than_two;
5889 // Adding two lengths can't overflow.
5890 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2);
5891 __ add(r6, r2, Operand(r3));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005892 // Use the string table when adding two one character strings, as it
5893 // helps later optimizations to return a string here.
ricow@chromium.org65fae842010-08-25 15:26:24 +00005894 __ cmp(r6, Operand(2));
5895 __ b(ne, &longer_than_two);
5896
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005897 // Check that both strings are non-external ASCII strings.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005898 if (flags_ != NO_STRING_ADD_FLAGS) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00005899 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
5900 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
5901 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
5902 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
5903 }
5904 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7,
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005905 &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005906
5907 // Get the two characters forming the sub string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005908 __ ldrb(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize));
5909 __ ldrb(r3, FieldMemOperand(r1, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005910
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005911 // Try to lookup two character string in string table. If it is not found
ricow@chromium.org65fae842010-08-25 15:26:24 +00005912 // just allocate a new one.
5913 Label make_two_character_string;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005914 StringHelper::GenerateTwoCharacterStringTableProbe(
ricow@chromium.org65fae842010-08-25 15:26:24 +00005915 masm, r2, r3, r6, r7, r4, r5, r9, &make_two_character_string);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005916 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005917 __ add(sp, sp, Operand(2 * kPointerSize));
5918 __ Ret();
5919
5920 __ bind(&make_two_character_string);
5921 // Resulting string has length 2 and first chars of two strings
5922 // are combined into single halfword in r2 register.
5923 // So we can fill resulting string without two loops by a single
5924 // halfword store instruction (which assumes that processor is
5925 // in a little endian mode)
5926 __ mov(r6, Operand(2));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005927 __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005928 __ strh(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005929 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005930 __ add(sp, sp, Operand(2 * kPointerSize));
5931 __ Ret();
5932
5933 __ bind(&longer_than_two);
5934 // Check if resulting string will be flat.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005935 __ cmp(r6, Operand(ConsString::kMinLength));
ricow@chromium.org65fae842010-08-25 15:26:24 +00005936 __ b(lt, &string_add_flat_result);
5937 // Handle exceptionally long strings in the runtime system.
5938 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
5939 ASSERT(IsPowerOf2(String::kMaxLength + 1));
5940 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not.
5941 __ cmp(r6, Operand(String::kMaxLength + 1));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005942 __ b(hs, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005943
5944 // If result is not supposed to be flat, allocate a cons string object.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005945 // If both strings are ASCII the result is an ASCII cons string.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005946 if (flags_ != NO_STRING_ADD_FLAGS) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00005947 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
5948 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
5949 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
5950 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
5951 }
5952 Label non_ascii, allocated, ascii_data;
5953 STATIC_ASSERT(kTwoByteStringTag == 0);
5954 __ tst(r4, Operand(kStringEncodingMask));
5955 __ tst(r5, Operand(kStringEncodingMask), ne);
5956 __ b(eq, &non_ascii);
5957
5958 // Allocate an ASCII cons string.
5959 __ bind(&ascii_data);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005960 __ AllocateAsciiConsString(r7, r6, r4, r5, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005961 __ bind(&allocated);
5962 // Fill the fields of the cons string.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005963 Label skip_write_barrier, after_writing;
5964 ExternalReference high_promotion_mode = ExternalReference::
5965 new_space_high_promotion_mode_active_address(masm->isolate());
5966 __ mov(r4, Operand(high_promotion_mode));
5967 __ ldr(r4, MemOperand(r4, 0));
5968 __ cmp(r4, Operand::Zero());
5969 __ b(eq, &skip_write_barrier);
5970
5971 __ str(r0, FieldMemOperand(r7, ConsString::kFirstOffset));
5972 __ RecordWriteField(r7,
5973 ConsString::kFirstOffset,
5974 r0,
5975 r4,
5976 kLRHasNotBeenSaved,
5977 kDontSaveFPRegs);
5978 __ str(r1, FieldMemOperand(r7, ConsString::kSecondOffset));
5979 __ RecordWriteField(r7,
5980 ConsString::kSecondOffset,
5981 r1,
5982 r4,
5983 kLRHasNotBeenSaved,
5984 kDontSaveFPRegs);
5985 __ jmp(&after_writing);
5986
5987 __ bind(&skip_write_barrier);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005988 __ str(r0, FieldMemOperand(r7, ConsString::kFirstOffset));
5989 __ str(r1, FieldMemOperand(r7, ConsString::kSecondOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005990
5991 __ bind(&after_writing);
5992
ricow@chromium.org65fae842010-08-25 15:26:24 +00005993 __ mov(r0, Operand(r7));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005994 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00005995 __ add(sp, sp, Operand(2 * kPointerSize));
5996 __ Ret();
5997
5998 __ bind(&non_ascii);
5999 // At least one of the strings is two-byte. Check whether it happens
danno@chromium.orgca29dd82013-04-26 11:59:48 +00006000 // to contain only one byte characters.
ricow@chromium.org65fae842010-08-25 15:26:24 +00006001 // r4: first instance type.
6002 // r5: second instance type.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00006003 __ tst(r4, Operand(kOneByteDataHintMask));
6004 __ tst(r5, Operand(kOneByteDataHintMask), ne);
ricow@chromium.org65fae842010-08-25 15:26:24 +00006005 __ b(ne, &ascii_data);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006006 __ eor(r4, r4, Operand(r5));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00006007 STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0);
6008 __ and_(r4, r4, Operand(kOneByteStringTag | kOneByteDataHintTag));
6009 __ cmp(r4, Operand(kOneByteStringTag | kOneByteDataHintTag));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006010 __ b(eq, &ascii_data);
ricow@chromium.org65fae842010-08-25 15:26:24 +00006011
6012 // Allocate a two byte cons string.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006013 __ AllocateTwoByteConsString(r7, r6, r4, r5, &call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00006014 __ jmp(&allocated);
6015
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006016 // We cannot encounter sliced strings or cons strings here since:
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006017 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006018 // Handle creating a flat result from either external or sequential strings.
6019 // Locate the first characters' locations.
ricow@chromium.org65fae842010-08-25 15:26:24 +00006020 // r0: first string
6021 // r1: second string
6022 // r2: length of first string
6023 // r3: length of second string
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006024 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
6025 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
ricow@chromium.org65fae842010-08-25 15:26:24 +00006026 // r6: sum of lengths.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006027 Label first_prepared, second_prepared;
ricow@chromium.org65fae842010-08-25 15:26:24 +00006028 __ bind(&string_add_flat_result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006029 if (flags_ != NO_STRING_ADD_FLAGS) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00006030 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
6031 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
6032 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
6033 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
6034 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006035
6036 // Check whether both strings have same encoding
ricow@chromium.org65fae842010-08-25 15:26:24 +00006037 __ eor(r7, r4, Operand(r5));
6038 __ tst(r7, Operand(kStringEncodingMask));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006039 __ b(ne, &call_runtime);
6040
6041 STATIC_ASSERT(kSeqStringTag == 0);
6042 __ tst(r4, Operand(kStringRepresentationMask));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006043 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006044 __ add(r7,
6045 r0,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006046 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag),
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006047 LeaveCC,
6048 eq);
6049 __ b(eq, &first_prepared);
6050 // External string: rule out short external string and load string resource.
6051 STATIC_ASSERT(kShortExternalStringTag != 0);
6052 __ tst(r4, Operand(kShortExternalStringMask));
6053 __ b(ne, &call_runtime);
6054 __ ldr(r7, FieldMemOperand(r0, ExternalString::kResourceDataOffset));
6055 __ bind(&first_prepared);
6056
6057 STATIC_ASSERT(kSeqStringTag == 0);
6058 __ tst(r5, Operand(kStringRepresentationMask));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006059 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006060 __ add(r1,
6061 r1,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006062 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag),
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006063 LeaveCC,
6064 eq);
6065 __ b(eq, &second_prepared);
6066 // External string: rule out short external string and load string resource.
6067 STATIC_ASSERT(kShortExternalStringTag != 0);
6068 __ tst(r5, Operand(kShortExternalStringMask));
6069 __ b(ne, &call_runtime);
6070 __ ldr(r1, FieldMemOperand(r1, ExternalString::kResourceDataOffset));
6071 __ bind(&second_prepared);
6072
6073 Label non_ascii_string_add_flat_result;
6074 // r7: first character of first string
6075 // r1: first character of second string
6076 // r2: length of first string.
6077 // r3: length of second string.
6078 // r6: sum of lengths.
6079 // Both strings have the same encoding.
6080 STATIC_ASSERT(kTwoByteStringTag == 0);
6081 __ tst(r5, Operand(kStringEncodingMask));
ricow@chromium.org65fae842010-08-25 15:26:24 +00006082 __ b(eq, &non_ascii_string_add_flat_result);
6083
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006084 __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006085 __ add(r6, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006086 // r0: result string.
6087 // r7: first character of first string.
6088 // r1: first character of second string.
ricow@chromium.org65fae842010-08-25 15:26:24 +00006089 // r2: length of first string.
6090 // r3: length of second string.
6091 // r6: first character of result.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006092 StringHelper::GenerateCopyCharacters(masm, r6, r7, r2, r4, true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00006093 // r6: next character of result.
ricow@chromium.org65fae842010-08-25 15:26:24 +00006094 StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, true);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006095 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00006096 __ add(sp, sp, Operand(2 * kPointerSize));
6097 __ Ret();
6098
6099 __ bind(&non_ascii_string_add_flat_result);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006100 __ AllocateTwoByteString(r0, r6, r4, r5, r9, &call_runtime);
6101 __ add(r6, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
6102 // r0: result string.
6103 // r7: first character of first string.
6104 // r1: first character of second string.
ricow@chromium.org65fae842010-08-25 15:26:24 +00006105 // r2: length of first string.
6106 // r3: length of second string.
6107 // r6: first character of result.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006108 StringHelper::GenerateCopyCharacters(masm, r6, r7, r2, r4, false);
6109 // r6: next character of result.
ricow@chromium.org65fae842010-08-25 15:26:24 +00006110 StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006111 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
ricow@chromium.org65fae842010-08-25 15:26:24 +00006112 __ add(sp, sp, Operand(2 * kPointerSize));
6113 __ Ret();
6114
6115 // Just jump to runtime to add the two strings.
ricow@chromium.org7ad65222011-12-19 12:13:11 +00006116 __ bind(&call_runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00006117 __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006118
6119 if (call_builtin.is_linked()) {
6120 __ bind(&call_builtin);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006121 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006122 }
6123}
6124
6125
6126void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
6127 int stack_offset,
6128 Register arg,
6129 Register scratch1,
6130 Register scratch2,
6131 Register scratch3,
6132 Register scratch4,
6133 Label* slow) {
6134 // First check if the argument is already a string.
6135 Label not_string, done;
6136 __ JumpIfSmi(arg, &not_string);
6137 __ CompareObjectType(arg, scratch1, scratch1, FIRST_NONSTRING_TYPE);
6138 __ b(lt, &done);
6139
6140 // Check the number to string cache.
6141 Label not_cached;
6142 __ bind(&not_string);
6143 // Puts the cached result into scratch1.
6144 NumberToStringStub::GenerateLookupNumberStringCache(masm,
6145 arg,
6146 scratch1,
6147 scratch2,
6148 scratch3,
6149 scratch4,
6150 false,
6151 &not_cached);
6152 __ mov(arg, scratch1);
6153 __ str(arg, MemOperand(sp, stack_offset));
6154 __ jmp(&done);
6155
6156 // Check if the argument is a safe string wrapper.
6157 __ bind(&not_cached);
6158 __ JumpIfSmi(arg, slow);
6159 __ CompareObjectType(
6160 arg, scratch1, scratch2, JS_VALUE_TYPE); // map -> scratch1.
6161 __ b(ne, slow);
6162 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset));
6163 __ and_(scratch2,
6164 scratch2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
6165 __ cmp(scratch2,
6166 Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
6167 __ b(ne, slow);
6168 __ ldr(arg, FieldMemOperand(arg, JSValue::kValueOffset));
6169 __ str(arg, MemOperand(sp, stack_offset));
6170
6171 __ bind(&done);
ricow@chromium.org65fae842010-08-25 15:26:24 +00006172}
6173
6174
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006175void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006176 ASSERT(state_ == CompareIC::SMI);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006177 Label miss;
6178 __ orr(r2, r1, r0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00006179 __ JumpIfNotSmi(r2, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006180
6181 if (GetCondition() == eq) {
6182 // For equality we do not care about the sign of the result.
6183 __ sub(r0, r0, r1, SetCC);
6184 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00006185 // Untag before subtracting to avoid handling overflow.
6186 __ SmiUntag(r1);
6187 __ sub(r0, r1, SmiUntagOperand(r0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006188 }
6189 __ Ret();
6190
6191 __ bind(&miss);
6192 GenerateMiss(masm);
6193}
6194
6195
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006196void ICCompareStub::GenerateNumbers(MacroAssembler* masm) {
6197 ASSERT(state_ == CompareIC::NUMBER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006198
6199 Label generic_stub;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00006200 Label unordered, maybe_undefined1, maybe_undefined2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006201 Label miss;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006202
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006203 if (left_ == CompareIC::SMI) {
6204 __ JumpIfNotSmi(r1, &miss);
6205 }
6206 if (right_ == CompareIC::SMI) {
6207 __ JumpIfNotSmi(r0, &miss);
6208 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006209
6210 // Inlining the double comparison and falling back to the general compare
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006211 // stub if NaN is involved.
6212 // Load left and right operand.
6213 Label done, left, left_smi, right_smi;
6214 __ JumpIfSmi(r0, &right_smi);
6215 __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
6216 DONT_DO_SMI_CHECK);
6217 __ sub(r2, r0, Operand(kHeapObjectTag));
6218 __ vldr(d1, r2, HeapNumber::kValueOffset);
6219 __ b(&left);
6220 __ bind(&right_smi);
6221 __ SmiUntag(r2, r0); // Can't clobber r0 yet.
6222 SwVfpRegister single_scratch = d2.low();
6223 __ vmov(single_scratch, r2);
6224 __ vcvt_f64_s32(d1, single_scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006225
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006226 __ bind(&left);
6227 __ JumpIfSmi(r1, &left_smi);
6228 __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
6229 DONT_DO_SMI_CHECK);
6230 __ sub(r2, r1, Operand(kHeapObjectTag));
6231 __ vldr(d0, r2, HeapNumber::kValueOffset);
6232 __ b(&done);
6233 __ bind(&left_smi);
6234 __ SmiUntag(r2, r1); // Can't clobber r1 yet.
6235 single_scratch = d3.low();
6236 __ vmov(single_scratch, r2);
6237 __ vcvt_f64_s32(d0, single_scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006238
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006239 __ bind(&done);
6240 // Compare operands.
6241 __ VFPCompareAndSetFlags(d0, d1);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006242
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006243 // Don't base result on status bits when a NaN is involved.
6244 __ b(vs, &unordered);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006245
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006246 // Return a result of -1, 0, or 1, based on status bits.
6247 __ mov(r0, Operand(EQUAL), LeaveCC, eq);
6248 __ mov(r0, Operand(LESS), LeaveCC, lt);
6249 __ mov(r0, Operand(GREATER), LeaveCC, gt);
6250 __ Ret();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006251
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00006252 __ bind(&unordered);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006253 __ bind(&generic_stub);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006254 ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
6255 CompareIC::GENERIC);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006256 __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006257
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00006258 __ bind(&maybe_undefined1);
6259 if (Token::IsOrderedRelationalCompareOp(op_)) {
6260 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
6261 __ b(ne, &miss);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006262 __ JumpIfSmi(r1, &unordered);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00006263 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
6264 __ b(ne, &maybe_undefined2);
6265 __ jmp(&unordered);
6266 }
6267
6268 __ bind(&maybe_undefined2);
6269 if (Token::IsOrderedRelationalCompareOp(op_)) {
6270 __ CompareRoot(r1, Heap::kUndefinedValueRootIndex);
6271 __ b(eq, &unordered);
6272 }
6273
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006274 __ bind(&miss);
6275 GenerateMiss(masm);
6276}
6277
6278
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006279void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) {
6280 ASSERT(state_ == CompareIC::INTERNALIZED_STRING);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006281 Label miss;
6282
6283 // Registers containing left and right operands respectively.
6284 Register left = r1;
6285 Register right = r0;
6286 Register tmp1 = r2;
6287 Register tmp2 = r3;
6288
6289 // Check that both operands are heap objects.
6290 __ JumpIfEitherSmi(left, right, &miss);
6291
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006292 // Check that both operands are internalized strings.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006293 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
6294 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
6295 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
6296 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006297 STATIC_ASSERT(kInternalizedTag != 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006298 __ and_(tmp1, tmp1, Operand(tmp2));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006299 __ tst(tmp1, Operand(kIsInternalizedMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006300 __ b(eq, &miss);
6301
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006302 // Internalized strings are compared by identity.
6303 __ cmp(left, right);
6304 // Make sure r0 is non-zero. At this point input operands are
6305 // guaranteed to be non-zero.
6306 ASSERT(right.is(r0));
6307 STATIC_ASSERT(EQUAL == 0);
6308 STATIC_ASSERT(kSmiTag == 0);
6309 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
6310 __ Ret();
6311
6312 __ bind(&miss);
6313 GenerateMiss(masm);
6314}
6315
6316
6317void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) {
6318 ASSERT(state_ == CompareIC::UNIQUE_NAME);
6319 ASSERT(GetCondition() == eq);
6320 Label miss;
6321
6322 // Registers containing left and right operands respectively.
6323 Register left = r1;
6324 Register right = r0;
6325 Register tmp1 = r2;
6326 Register tmp2 = r3;
6327
6328 // Check that both operands are heap objects.
6329 __ JumpIfEitherSmi(left, right, &miss);
6330
6331 // Check that both operands are unique names. This leaves the instance
6332 // types loaded in tmp1 and tmp2.
6333 STATIC_ASSERT(kInternalizedTag != 0);
6334 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
6335 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
6336 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
6337 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
6338
6339 Label succeed1;
6340 __ tst(tmp1, Operand(kIsInternalizedMask));
6341 __ b(ne, &succeed1);
6342 __ cmp(tmp1, Operand(SYMBOL_TYPE));
6343 __ b(ne, &miss);
6344 __ bind(&succeed1);
6345
6346 Label succeed2;
6347 __ tst(tmp2, Operand(kIsInternalizedMask));
6348 __ b(ne, &succeed2);
6349 __ cmp(tmp2, Operand(SYMBOL_TYPE));
6350 __ b(ne, &miss);
6351 __ bind(&succeed2);
6352
6353 // Unique names are compared by identity.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006354 __ cmp(left, right);
6355 // Make sure r0 is non-zero. At this point input operands are
6356 // guaranteed to be non-zero.
6357 ASSERT(right.is(r0));
6358 STATIC_ASSERT(EQUAL == 0);
6359 STATIC_ASSERT(kSmiTag == 0);
6360 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
6361 __ Ret();
6362
6363 __ bind(&miss);
6364 GenerateMiss(masm);
6365}
6366
6367
lrn@chromium.org1c092762011-05-09 09:42:16 +00006368void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006369 ASSERT(state_ == CompareIC::STRING);
lrn@chromium.org1c092762011-05-09 09:42:16 +00006370 Label miss;
6371
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00006372 bool equality = Token::IsEqualityOp(op_);
6373
lrn@chromium.org1c092762011-05-09 09:42:16 +00006374 // Registers containing left and right operands respectively.
6375 Register left = r1;
6376 Register right = r0;
6377 Register tmp1 = r2;
6378 Register tmp2 = r3;
6379 Register tmp3 = r4;
6380 Register tmp4 = r5;
6381
6382 // Check that both operands are heap objects.
6383 __ JumpIfEitherSmi(left, right, &miss);
6384
6385 // Check that both operands are strings. This leaves the instance
6386 // types loaded in tmp1 and tmp2.
6387 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
6388 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
6389 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
6390 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
6391 STATIC_ASSERT(kNotStringTag != 0);
6392 __ orr(tmp3, tmp1, tmp2);
6393 __ tst(tmp3, Operand(kIsNotStringMask));
6394 __ b(ne, &miss);
6395
6396 // Fast check for identical strings.
6397 __ cmp(left, right);
6398 STATIC_ASSERT(EQUAL == 0);
6399 STATIC_ASSERT(kSmiTag == 0);
6400 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
6401 __ Ret(eq);
6402
6403 // Handle not identical strings.
6404
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006405 // Check that both strings are internalized strings. If they are, we're done
lrn@chromium.org1c092762011-05-09 09:42:16 +00006406 // because we already know they are not identical.
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00006407 if (equality) {
6408 ASSERT(GetCondition() == eq);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006409 STATIC_ASSERT(kInternalizedTag != 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00006410 __ and_(tmp3, tmp1, Operand(tmp2));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006411 __ tst(tmp3, Operand(kIsInternalizedMask));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00006412 // Make sure r0 is non-zero. At this point input operands are
6413 // guaranteed to be non-zero.
6414 ASSERT(right.is(r0));
6415 __ Ret(ne);
6416 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00006417
6418 // Check that both strings are sequential ASCII.
6419 Label runtime;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00006420 __ JumpIfBothInstanceTypesAreNotSequentialAscii(
6421 tmp1, tmp2, tmp3, tmp4, &runtime);
lrn@chromium.org1c092762011-05-09 09:42:16 +00006422
6423 // Compare flat ASCII strings. Returns when done.
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00006424 if (equality) {
6425 StringCompareStub::GenerateFlatAsciiStringEquals(
6426 masm, left, right, tmp1, tmp2, tmp3);
6427 } else {
6428 StringCompareStub::GenerateCompareFlatAsciiStrings(
6429 masm, left, right, tmp1, tmp2, tmp3, tmp4);
6430 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00006431
6432 // Handle more complex cases in runtime.
6433 __ bind(&runtime);
6434 __ Push(left, right);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00006435 if (equality) {
6436 __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
6437 } else {
6438 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
6439 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00006440
6441 __ bind(&miss);
6442 GenerateMiss(masm);
6443}
6444
6445
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006446void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006447 ASSERT(state_ == CompareIC::OBJECT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006448 Label miss;
6449 __ and_(r2, r1, Operand(r0));
whesse@chromium.org7b260152011-06-20 15:33:18 +00006450 __ JumpIfSmi(r2, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006451
6452 __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE);
6453 __ b(ne, &miss);
6454 __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE);
6455 __ b(ne, &miss);
6456
6457 ASSERT(GetCondition() == eq);
6458 __ sub(r0, r0, Operand(r1));
6459 __ Ret();
6460
6461 __ bind(&miss);
6462 GenerateMiss(masm);
6463}
6464
6465
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006466void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
6467 Label miss;
6468 __ and_(r2, r1, Operand(r0));
6469 __ JumpIfSmi(r2, &miss);
6470 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
6471 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
6472 __ cmp(r2, Operand(known_map_));
6473 __ b(ne, &miss);
6474 __ cmp(r3, Operand(known_map_));
6475 __ b(ne, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006476
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006477 __ sub(r0, r0, Operand(r1));
6478 __ Ret();
6479
6480 __ bind(&miss);
6481 GenerateMiss(masm);
6482}
6483
6484
6485
6486void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006487 {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006488 // Call the runtime system in a fresh internal frame.
6489 ExternalReference miss =
6490 ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
6491
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006492 FrameScope scope(masm, StackFrame::INTERNAL);
6493 __ Push(r1, r0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006494 __ push(lr);
6495 __ Push(r1, r0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006496 __ mov(ip, Operand(Smi::FromInt(op_)));
6497 __ push(ip);
6498 __ CallExternalReference(miss, 3);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006499 // Compute the entry point of the rewritten stub.
6500 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
6501 // Restore registers.
6502 __ pop(lr);
6503 __ pop(r0);
6504 __ pop(r1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006505 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006506
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006507 __ Jump(r2);
6508}
6509
6510
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006511void DirectCEntryStub::Generate(MacroAssembler* masm) {
6512 __ ldr(pc, MemOperand(sp, 0));
6513}
6514
6515
6516void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00006517 ExternalReference function) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00006518 __ mov(r2, Operand(function));
danno@chromium.orgb6451162011-08-17 14:33:23 +00006519 GenerateCall(masm, r2);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006520}
6521
6522
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006523void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
6524 Register target) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006525 intptr_t code =
6526 reinterpret_cast<intptr_t>(GetCode(masm->isolate()).location());
6527 __ mov(lr, Operand(code, RelocInfo::CODE_TARGET));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00006528
6529 // Prevent literal pool emission during calculation of return address.
6530 Assembler::BlockConstPoolScope block_const_pool(masm);
6531
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006532 // Push return address (accessible to GC through exit frame pc).
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006533 // Note that using pc with str is deprecated.
danno@chromium.orgb6451162011-08-17 14:33:23 +00006534 Label start;
6535 __ bind(&start);
6536 __ add(ip, pc, Operand(Assembler::kInstrSize));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006537 __ str(ip, MemOperand(sp, 0));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006538 __ Jump(target); // Call the C++ function.
danno@chromium.orgb6451162011-08-17 14:33:23 +00006539 ASSERT_EQ(Assembler::kInstrSize + Assembler::kPcLoadDelta,
6540 masm->SizeOfCodeGeneratedSince(&start));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006541 __ VFPEnsureFPSCRState(r2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006542}
6543
6544
ulan@chromium.org750145a2013-03-07 15:14:13 +00006545void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
6546 Label* miss,
6547 Label* done,
6548 Register receiver,
6549 Register properties,
6550 Handle<Name> name,
6551 Register scratch0) {
6552 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006553 // If names of slots in range from 1 to kProbes - 1 for the hash value are
6554 // not equal to the name and kProbes-th slot is not used (its name is the
6555 // undefined value), it guarantees the hash table doesn't contain the
6556 // property. It's true even if some slots represent deleted properties
ulan@chromium.org967e2702012-02-28 09:49:15 +00006557 // (their names are the hole value).
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006558 for (int i = 0; i < kInlinedProbes; i++) {
6559 // scratch0 points to properties hash.
6560 // Compute the masked index: (hash + i + i * i) & mask.
6561 Register index = scratch0;
6562 // Capacity is smi 2^n.
6563 __ ldr(index, FieldMemOperand(properties, kCapacityOffset));
6564 __ sub(index, index, Operand(1));
6565 __ and_(index, index, Operand(
ulan@chromium.org750145a2013-03-07 15:14:13 +00006566 Smi::FromInt(name->Hash() + NameDictionary::GetProbeOffset(i))));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006567
6568 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00006569 ASSERT(NameDictionary::kEntrySize == 3);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006570 __ add(index, index, Operand(index, LSL, 1)); // index *= 3.
6571
6572 Register entity_name = scratch0;
6573 // Having undefined at this place means the name is not contained.
6574 ASSERT_EQ(kSmiTagSize, 1);
6575 Register tmp = properties;
6576 __ add(tmp, properties, Operand(index, LSL, 1));
6577 __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
6578
6579 ASSERT(!tmp.is(entity_name));
6580 __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
6581 __ cmp(entity_name, tmp);
6582 __ b(eq, done);
6583
ulan@chromium.org77802e82013-03-26 11:54:42 +00006584 // Load the hole ready for use below:
6585 __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex);
ulan@chromium.org967e2702012-02-28 09:49:15 +00006586
ulan@chromium.org77802e82013-03-26 11:54:42 +00006587 // Stop if found the property.
6588 __ cmp(entity_name, Operand(Handle<Name>(name)));
6589 __ b(eq, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006590
ulan@chromium.org77802e82013-03-26 11:54:42 +00006591 Label good;
6592 __ cmp(entity_name, tmp);
6593 __ b(eq, &good);
ulan@chromium.org967e2702012-02-28 09:49:15 +00006594
ulan@chromium.org77802e82013-03-26 11:54:42 +00006595 // Check if the entry name is not a unique name.
6596 __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
6597 __ ldrb(entity_name,
6598 FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
6599 __ tst(entity_name, Operand(kIsInternalizedMask));
6600 __ b(ne, &good);
6601 __ cmp(entity_name, Operand(SYMBOL_TYPE));
6602 __ b(ne, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006603
ulan@chromium.org77802e82013-03-26 11:54:42 +00006604 __ bind(&good);
ulan@chromium.org967e2702012-02-28 09:49:15 +00006605
ulan@chromium.org77802e82013-03-26 11:54:42 +00006606 // Restore the properties.
6607 __ ldr(properties,
6608 FieldMemOperand(receiver, JSObject::kPropertiesOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006609 }
6610
6611 const int spill_mask =
6612 (lr.bit() | r6.bit() | r5.bit() | r4.bit() | r3.bit() |
6613 r2.bit() | r1.bit() | r0.bit());
6614
6615 __ stm(db_w, sp, spill_mask);
6616 __ ldr(r0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +00006617 __ mov(r1, Operand(Handle<Name>(name)));
6618 NameDictionaryLookupStub stub(NEGATIVE_LOOKUP);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006619 __ CallStub(&stub);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006620 __ cmp(r0, Operand::Zero());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006621 __ ldm(ia_w, sp, spill_mask);
6622
6623 __ b(eq, done);
6624 __ b(ne, miss);
6625}
6626
6627
ulan@chromium.org750145a2013-03-07 15:14:13 +00006628// Probe the name dictionary in the |elements| register. Jump to the
lrn@chromium.org1c092762011-05-09 09:42:16 +00006629// |done| label if a property with the given name is found. Jump to
6630// the |miss| label otherwise.
6631// If lookup was successful |scratch2| will be equal to elements + 4 * index.
ulan@chromium.org750145a2013-03-07 15:14:13 +00006632void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
6633 Label* miss,
6634 Label* done,
6635 Register elements,
6636 Register name,
6637 Register scratch1,
6638 Register scratch2) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00006639 ASSERT(!elements.is(scratch1));
6640 ASSERT(!elements.is(scratch2));
6641 ASSERT(!name.is(scratch1));
6642 ASSERT(!name.is(scratch2));
6643
ulan@chromium.org750145a2013-03-07 15:14:13 +00006644 __ AssertName(name);
lrn@chromium.org1c092762011-05-09 09:42:16 +00006645
6646 // Compute the capacity mask.
6647 __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
6648 __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize)); // convert smi to int
6649 __ sub(scratch1, scratch1, Operand(1));
6650
6651 // Generate an unrolled loop that performs a few probes before
6652 // giving up. Measurements done on Gmail indicate that 2 probes
6653 // cover ~93% of loads from dictionaries.
6654 for (int i = 0; i < kInlinedProbes; i++) {
6655 // Compute the masked index: (hash + i + i * i) & mask.
ulan@chromium.org750145a2013-03-07 15:14:13 +00006656 __ ldr(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00006657 if (i > 0) {
6658 // Add the probe offset (i + i * i) left shifted to avoid right shifting
6659 // the hash in a separate instruction. The value hash + i + i * i is right
6660 // shifted in the following and instruction.
ulan@chromium.org750145a2013-03-07 15:14:13 +00006661 ASSERT(NameDictionary::GetProbeOffset(i) <
6662 1 << (32 - Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00006663 __ add(scratch2, scratch2, Operand(
ulan@chromium.org750145a2013-03-07 15:14:13 +00006664 NameDictionary::GetProbeOffset(i) << Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00006665 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00006666 __ and_(scratch2, scratch1, Operand(scratch2, LSR, Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00006667
6668 // Scale the index by multiplying by the element size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00006669 ASSERT(NameDictionary::kEntrySize == 3);
lrn@chromium.org1c092762011-05-09 09:42:16 +00006670 // scratch2 = scratch2 * 3.
6671 __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
6672
6673 // Check if the key is identical to the name.
6674 __ add(scratch2, elements, Operand(scratch2, LSL, 2));
6675 __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
6676 __ cmp(name, Operand(ip));
6677 __ b(eq, done);
6678 }
6679
6680 const int spill_mask =
6681 (lr.bit() | r6.bit() | r5.bit() | r4.bit() |
6682 r3.bit() | r2.bit() | r1.bit() | r0.bit()) &
6683 ~(scratch1.bit() | scratch2.bit());
6684
6685 __ stm(db_w, sp, spill_mask);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00006686 if (name.is(r0)) {
6687 ASSERT(!elements.is(r1));
6688 __ Move(r1, name);
6689 __ Move(r0, elements);
6690 } else {
6691 __ Move(r0, elements);
6692 __ Move(r1, name);
6693 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00006694 NameDictionaryLookupStub stub(POSITIVE_LOOKUP);
lrn@chromium.org1c092762011-05-09 09:42:16 +00006695 __ CallStub(&stub);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006696 __ cmp(r0, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00006697 __ mov(scratch2, Operand(r2));
6698 __ ldm(ia_w, sp, spill_mask);
6699
6700 __ b(ne, done);
6701 __ b(eq, miss);
6702}
6703
6704
ulan@chromium.org750145a2013-03-07 15:14:13 +00006705void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006706 // This stub overrides SometimesSetsUpAFrame() to return false. That means
6707 // we cannot call anything that could cause a GC from this stub.
lrn@chromium.org1c092762011-05-09 09:42:16 +00006708 // Registers:
ulan@chromium.org750145a2013-03-07 15:14:13 +00006709 // result: NameDictionary to probe
lrn@chromium.org1c092762011-05-09 09:42:16 +00006710 // r1: key
ulan@chromium.org750145a2013-03-07 15:14:13 +00006711 // dictionary: NameDictionary to probe.
6712 // index: will hold an index of entry if lookup is successful.
6713 // might alias with result_.
lrn@chromium.org1c092762011-05-09 09:42:16 +00006714 // Returns:
6715 // result_ is zero if lookup failed, non zero otherwise.
6716
6717 Register result = r0;
6718 Register dictionary = r0;
6719 Register key = r1;
6720 Register index = r2;
6721 Register mask = r3;
6722 Register hash = r4;
6723 Register undefined = r5;
6724 Register entry_key = r6;
6725
6726 Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
6727
6728 __ ldr(mask, FieldMemOperand(dictionary, kCapacityOffset));
6729 __ mov(mask, Operand(mask, ASR, kSmiTagSize));
6730 __ sub(mask, mask, Operand(1));
6731
ulan@chromium.org750145a2013-03-07 15:14:13 +00006732 __ ldr(hash, FieldMemOperand(key, Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00006733
6734 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
6735
6736 for (int i = kInlinedProbes; i < kTotalProbes; i++) {
6737 // Compute the masked index: (hash + i + i * i) & mask.
6738 // Capacity is smi 2^n.
6739 if (i > 0) {
6740 // Add the probe offset (i + i * i) left shifted to avoid right shifting
6741 // the hash in a separate instruction. The value hash + i + i * i is right
6742 // shifted in the following and instruction.
ulan@chromium.org750145a2013-03-07 15:14:13 +00006743 ASSERT(NameDictionary::GetProbeOffset(i) <
6744 1 << (32 - Name::kHashFieldOffset));
lrn@chromium.org1c092762011-05-09 09:42:16 +00006745 __ add(index, hash, Operand(
ulan@chromium.org750145a2013-03-07 15:14:13 +00006746 NameDictionary::GetProbeOffset(i) << Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00006747 } else {
6748 __ mov(index, Operand(hash));
6749 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00006750 __ and_(index, mask, Operand(index, LSR, Name::kHashShift));
lrn@chromium.org1c092762011-05-09 09:42:16 +00006751
6752 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00006753 ASSERT(NameDictionary::kEntrySize == 3);
lrn@chromium.org1c092762011-05-09 09:42:16 +00006754 __ add(index, index, Operand(index, LSL, 1)); // index *= 3.
6755
6756 ASSERT_EQ(kSmiTagSize, 1);
6757 __ add(index, dictionary, Operand(index, LSL, 2));
6758 __ ldr(entry_key, FieldMemOperand(index, kElementsStartOffset));
6759
6760 // Having undefined at this place means the name is not contained.
6761 __ cmp(entry_key, Operand(undefined));
6762 __ b(eq, &not_in_dictionary);
6763
6764 // Stop if found the property.
6765 __ cmp(entry_key, Operand(key));
6766 __ b(eq, &in_dictionary);
6767
6768 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00006769 // Check if the entry name is not a unique name.
6770 Label cont;
lrn@chromium.org1c092762011-05-09 09:42:16 +00006771 __ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
6772 __ ldrb(entry_key,
6773 FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006774 __ tst(entry_key, Operand(kIsInternalizedMask));
ulan@chromium.org750145a2013-03-07 15:14:13 +00006775 __ b(ne, &cont);
6776 __ cmp(entry_key, Operand(SYMBOL_TYPE));
6777 __ b(ne, &maybe_in_dictionary);
6778 __ bind(&cont);
lrn@chromium.org1c092762011-05-09 09:42:16 +00006779 }
6780 }
6781
6782 __ bind(&maybe_in_dictionary);
6783 // If we are doing negative lookup then probing failure should be
6784 // treated as a lookup success. For positive lookup probing failure
6785 // should be treated as lookup failure.
6786 if (mode_ == POSITIVE_LOOKUP) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006787 __ mov(result, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00006788 __ Ret();
6789 }
6790
6791 __ bind(&in_dictionary);
6792 __ mov(result, Operand(1));
6793 __ Ret();
6794
6795 __ bind(&not_in_dictionary);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006796 __ mov(result, Operand::Zero());
lrn@chromium.org1c092762011-05-09 09:42:16 +00006797 __ Ret();
6798}
6799
6800
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006801struct AheadOfTimeWriteBarrierStubList {
6802 Register object, value, address;
6803 RememberedSetAction action;
6804};
6805
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006806#define REG(Name) { kRegister_ ## Name ## _Code }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006807
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006808static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006809 // Used in RegExpExecStub.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006810 { REG(r6), REG(r4), REG(r7), EMIT_REMEMBERED_SET },
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006811 // Used in CompileArrayPushCall.
6812 // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore.
6813 // Also used in KeyedStoreIC::GenerateGeneric.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006814 { REG(r3), REG(r4), REG(r5), EMIT_REMEMBERED_SET },
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006815 // Used in CompileStoreGlobal.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006816 { REG(r4), REG(r1), REG(r2), OMIT_REMEMBERED_SET },
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006817 // Used in StoreStubCompiler::CompileStoreField via GenerateStoreField.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006818 { REG(r1), REG(r2), REG(r3), EMIT_REMEMBERED_SET },
6819 { REG(r3), REG(r2), REG(r1), EMIT_REMEMBERED_SET },
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006820 // Used in KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006821 { REG(r2), REG(r1), REG(r3), EMIT_REMEMBERED_SET },
6822 { REG(r3), REG(r1), REG(r2), EMIT_REMEMBERED_SET },
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006823 // KeyedStoreStubCompiler::GenerateStoreFastElement.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006824 { REG(r3), REG(r2), REG(r4), EMIT_REMEMBERED_SET },
6825 { REG(r2), REG(r3), REG(r4), EMIT_REMEMBERED_SET },
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006826 // ElementsTransitionGenerator::GenerateMapChangeElementTransition
6827 // and ElementsTransitionGenerator::GenerateSmiToDouble
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006828 // and ElementsTransitionGenerator::GenerateDoubleToObject
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006829 { REG(r2), REG(r3), REG(r9), EMIT_REMEMBERED_SET },
6830 { REG(r2), REG(r3), REG(r9), OMIT_REMEMBERED_SET },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006831 // ElementsTransitionGenerator::GenerateDoubleToObject
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006832 { REG(r6), REG(r2), REG(r0), EMIT_REMEMBERED_SET },
6833 { REG(r2), REG(r6), REG(r9), EMIT_REMEMBERED_SET },
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006834 // StoreArrayLiteralElementStub::Generate
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006835 { REG(r5), REG(r0), REG(r6), EMIT_REMEMBERED_SET },
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006836 // FastNewClosureStub::Generate
6837 { REG(r2), REG(r4), REG(r1), EMIT_REMEMBERED_SET },
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006838 // StringAddStub::Generate
6839 { REG(r7), REG(r1), REG(r4), EMIT_REMEMBERED_SET },
6840 { REG(r7), REG(r0), REG(r4), EMIT_REMEMBERED_SET },
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006841 // Null termination.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006842 { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET}
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006843};
6844
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006845#undef REG
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006846
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006847
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006848bool RecordWriteStub::IsPregenerated() {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006849 for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006850 !entry->object.is(no_reg);
6851 entry++) {
6852 if (object_.is(entry->object) &&
6853 value_.is(entry->value) &&
6854 address_.is(entry->address) &&
6855 remembered_set_action_ == entry->action &&
6856 save_fp_regs_mode_ == kDontSaveFPRegs) {
6857 return true;
6858 }
6859 }
6860 return false;
6861}
6862
6863
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006864void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
6865 Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006866 StoreBufferOverflowStub stub1(kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006867 stub1.GetCode(isolate)->set_is_pregenerated(true);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00006868 // Hydrogen code stubs need stub2 at snapshot time.
6869 StoreBufferOverflowStub stub2(kSaveFPRegs);
6870 stub2.GetCode(isolate)->set_is_pregenerated(true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006871}
6872
6873
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006874void RecordWriteStub::GenerateFixedRegStubsAheadOfTime(Isolate* isolate) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00006875 for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006876 !entry->object.is(no_reg);
6877 entry++) {
6878 RecordWriteStub stub(entry->object,
6879 entry->value,
6880 entry->address,
6881 entry->action,
6882 kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006883 stub.GetCode(isolate)->set_is_pregenerated(true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006884 }
6885}
6886
6887
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006888bool CodeStub::CanUseFPRegisters() {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006889 return true; // VFP2 is a base requirement for V8
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006890}
6891
6892
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006893// Takes the input in 3 registers: address_ value_ and object_. A pointer to
6894// the value has just been written into the object, now this stub makes sure
6895// we keep the GC informed. The word in the object where the value has been
6896// written is in the address register.
6897void RecordWriteStub::Generate(MacroAssembler* masm) {
6898 Label skip_to_incremental_noncompacting;
6899 Label skip_to_incremental_compacting;
6900
6901 // The first two instructions are generated with labels so as to get the
6902 // offset fixed up correctly by the bind(Label*) call. We patch it back and
6903 // forth between a compare instructions (a nop in this position) and the
6904 // real branch when we start and stop incremental heap marking.
6905 // See RecordWriteStub::Patch for details.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00006906 {
6907 // Block literal pool emission, as the position of these two instructions
6908 // is assumed by the patching code.
6909 Assembler::BlockConstPoolScope block_const_pool(masm);
6910 __ b(&skip_to_incremental_noncompacting);
6911 __ b(&skip_to_incremental_compacting);
6912 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006913
6914 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
6915 __ RememberedSetHelper(object_,
6916 address_,
6917 value_,
6918 save_fp_regs_mode_,
6919 MacroAssembler::kReturnAtEnd);
6920 }
6921 __ Ret();
6922
6923 __ bind(&skip_to_incremental_noncompacting);
6924 GenerateIncremental(masm, INCREMENTAL);
6925
6926 __ bind(&skip_to_incremental_compacting);
6927 GenerateIncremental(masm, INCREMENTAL_COMPACTION);
6928
6929 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
6930 // Will be checked in IncrementalMarking::ActivateGeneratedStub.
6931 ASSERT(Assembler::GetBranchOffset(masm->instr_at(0)) < (1 << 12));
6932 ASSERT(Assembler::GetBranchOffset(masm->instr_at(4)) < (1 << 12));
6933 PatchBranchIntoNop(masm, 0);
6934 PatchBranchIntoNop(masm, Assembler::kInstrSize);
6935}
6936
6937
6938void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
6939 regs_.Save(masm);
6940
6941 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
6942 Label dont_need_remembered_set;
6943
6944 __ ldr(regs_.scratch0(), MemOperand(regs_.address(), 0));
6945 __ JumpIfNotInNewSpace(regs_.scratch0(), // Value.
6946 regs_.scratch0(),
6947 &dont_need_remembered_set);
6948
6949 __ CheckPageFlag(regs_.object(),
6950 regs_.scratch0(),
6951 1 << MemoryChunk::SCAN_ON_SCAVENGE,
6952 ne,
6953 &dont_need_remembered_set);
6954
6955 // First notify the incremental marker if necessary, then update the
6956 // remembered set.
6957 CheckNeedsToInformIncrementalMarker(
6958 masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
6959 InformIncrementalMarker(masm, mode);
6960 regs_.Restore(masm);
6961 __ RememberedSetHelper(object_,
6962 address_,
6963 value_,
6964 save_fp_regs_mode_,
6965 MacroAssembler::kReturnAtEnd);
6966
6967 __ bind(&dont_need_remembered_set);
6968 }
6969
6970 CheckNeedsToInformIncrementalMarker(
6971 masm, kReturnOnNoNeedToInformIncrementalMarker, mode);
6972 InformIncrementalMarker(masm, mode);
6973 regs_.Restore(masm);
6974 __ Ret();
6975}
6976
6977
6978void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) {
6979 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_);
6980 int argument_count = 3;
6981 __ PrepareCallCFunction(argument_count, regs_.scratch0());
6982 Register address =
6983 r0.is(regs_.address()) ? regs_.scratch0() : regs_.address();
6984 ASSERT(!address.is(regs_.object()));
6985 ASSERT(!address.is(r0));
6986 __ Move(address, regs_.address());
6987 __ Move(r0, regs_.object());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006988 __ Move(r1, address);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00006989 __ mov(r2, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006990
6991 AllowExternalCallThatCantCauseGC scope(masm);
6992 if (mode == INCREMENTAL_COMPACTION) {
6993 __ CallCFunction(
6994 ExternalReference::incremental_evacuation_record_write_function(
6995 masm->isolate()),
6996 argument_count);
6997 } else {
6998 ASSERT(mode == INCREMENTAL);
6999 __ CallCFunction(
7000 ExternalReference::incremental_marking_record_write_function(
7001 masm->isolate()),
7002 argument_count);
7003 }
7004 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_);
7005}
7006
7007
7008void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
7009 MacroAssembler* masm,
7010 OnNoNeedToInformIncrementalMarker on_no_need,
7011 Mode mode) {
7012 Label on_black;
7013 Label need_incremental;
7014 Label need_incremental_pop_scratch;
7015
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007016 __ and_(regs_.scratch0(), regs_.object(), Operand(~Page::kPageAlignmentMask));
7017 __ ldr(regs_.scratch1(),
7018 MemOperand(regs_.scratch0(),
7019 MemoryChunk::kWriteBarrierCounterOffset));
7020 __ sub(regs_.scratch1(), regs_.scratch1(), Operand(1), SetCC);
7021 __ str(regs_.scratch1(),
7022 MemOperand(regs_.scratch0(),
7023 MemoryChunk::kWriteBarrierCounterOffset));
7024 __ b(mi, &need_incremental);
7025
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007026 // Let's look at the color of the object: If it is not black we don't have
7027 // to inform the incremental marker.
7028 __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black);
7029
7030 regs_.Restore(masm);
7031 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
7032 __ RememberedSetHelper(object_,
7033 address_,
7034 value_,
7035 save_fp_regs_mode_,
7036 MacroAssembler::kReturnAtEnd);
7037 } else {
7038 __ Ret();
7039 }
7040
7041 __ bind(&on_black);
7042
7043 // Get the value from the slot.
7044 __ ldr(regs_.scratch0(), MemOperand(regs_.address(), 0));
7045
7046 if (mode == INCREMENTAL_COMPACTION) {
7047 Label ensure_not_white;
7048
7049 __ CheckPageFlag(regs_.scratch0(), // Contains value.
7050 regs_.scratch1(), // Scratch.
7051 MemoryChunk::kEvacuationCandidateMask,
7052 eq,
7053 &ensure_not_white);
7054
7055 __ CheckPageFlag(regs_.object(),
7056 regs_.scratch1(), // Scratch.
7057 MemoryChunk::kSkipEvacuationSlotsRecordingMask,
7058 eq,
7059 &need_incremental);
7060
7061 __ bind(&ensure_not_white);
7062 }
7063
7064 // We need extra registers for this, so we push the object and the address
7065 // register temporarily.
7066 __ Push(regs_.object(), regs_.address());
7067 __ EnsureNotWhite(regs_.scratch0(), // The value.
7068 regs_.scratch1(), // Scratch.
7069 regs_.object(), // Scratch.
7070 regs_.address(), // Scratch.
7071 &need_incremental_pop_scratch);
7072 __ Pop(regs_.object(), regs_.address());
7073
7074 regs_.Restore(masm);
7075 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
7076 __ RememberedSetHelper(object_,
7077 address_,
7078 value_,
7079 save_fp_regs_mode_,
7080 MacroAssembler::kReturnAtEnd);
7081 } else {
7082 __ Ret();
7083 }
7084
7085 __ bind(&need_incremental_pop_scratch);
7086 __ Pop(regs_.object(), regs_.address());
7087
7088 __ bind(&need_incremental);
7089
7090 // Fall through when we need to inform the incremental marker.
7091}
7092
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007093
7094void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
7095 // ----------- S t a t e -------------
7096 // -- r0 : element value to store
7097 // -- r1 : array literal
7098 // -- r2 : map of array literal
7099 // -- r3 : element index as smi
7100 // -- r4 : array literal index in function as smi
7101 // -----------------------------------
7102
7103 Label element_done;
7104 Label double_elements;
7105 Label smi_element;
7106 Label slow_elements;
7107 Label fast_elements;
7108
7109 __ CheckFastElements(r2, r5, &double_elements);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007110 // FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007111 __ JumpIfSmi(r0, &smi_element);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007112 __ CheckFastSmiElements(r2, r5, &fast_elements);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007113
7114 // Store into the array literal requires a elements transition. Call into
7115 // the runtime.
7116 __ bind(&slow_elements);
7117 // call.
7118 __ Push(r1, r3, r0);
7119 __ ldr(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
7120 __ ldr(r5, FieldMemOperand(r5, JSFunction::kLiteralsOffset));
7121 __ Push(r5, r4);
7122 __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
7123
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007124 // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007125 __ bind(&fast_elements);
7126 __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
7127 __ add(r6, r5, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
7128 __ add(r6, r6, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
7129 __ str(r0, MemOperand(r6, 0));
7130 // Update the write barrier for the array store.
7131 __ RecordWrite(r5, r6, r0, kLRHasNotBeenSaved, kDontSaveFPRegs,
7132 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
7133 __ Ret();
7134
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007135 // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
7136 // and value is Smi.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007137 __ bind(&smi_element);
7138 __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
7139 __ add(r6, r5, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
7140 __ str(r0, FieldMemOperand(r6, FixedArray::kHeaderSize));
7141 __ Ret();
7142
7143 // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
7144 __ bind(&double_elements);
7145 __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00007146 __ StoreNumberToDoubleElements(r0, r3, r5, r6, &slow_elements);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007147 __ Ret();
7148}
7149
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007150
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00007151void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00007152 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00007153 __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00007154 int parameter_count_offset =
7155 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
7156 __ ldr(r1, MemOperand(fp, parameter_count_offset));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00007157 if (function_mode_ == JS_FUNCTION_STUB_MODE) {
7158 __ add(r1, r1, Operand(1));
7159 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00007160 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00007161 __ mov(r1, Operand(r1, LSL, kPointerSizeLog2));
7162 __ add(sp, sp, r1);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00007163 __ Ret();
7164}
7165
7166
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007167void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
7168 if (entry_hook_ != NULL) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007169 PredictableCodeSizeScope predictable(masm, 4 * Assembler::kInstrSize);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007170 ProfileEntryHookStub stub;
7171 __ push(lr);
7172 __ CallStub(&stub);
7173 __ pop(lr);
7174 }
7175}
7176
7177
7178void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
7179 // The entry hook is a "push lr" instruction, followed by a call.
7180 const int32_t kReturnAddressDistanceFromFunctionStart =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00007181 3 * Assembler::kInstrSize;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007182
7183 // Save live volatile registers.
7184 __ Push(lr, r5, r1);
7185 const int32_t kNumSavedRegs = 3;
7186
7187 // Compute the function's address for the first argument.
7188 __ sub(r0, lr, Operand(kReturnAddressDistanceFromFunctionStart));
7189
7190 // The caller's return address is above the saved temporaries.
7191 // Grab that for the second argument to the hook.
7192 __ add(r1, sp, Operand(kNumSavedRegs * kPointerSize));
7193
7194 // Align the stack if necessary.
7195 int frame_alignment = masm->ActivationFrameAlignment();
7196 if (frame_alignment > kPointerSize) {
7197 __ mov(r5, sp);
7198 ASSERT(IsPowerOf2(frame_alignment));
7199 __ and_(sp, sp, Operand(-frame_alignment));
7200 }
7201
7202#if defined(V8_HOST_ARCH_ARM)
7203 __ mov(ip, Operand(reinterpret_cast<int32_t>(&entry_hook_)));
7204 __ ldr(ip, MemOperand(ip));
7205#else
7206 // Under the simulator we need to indirect the entry hook through a
7207 // trampoline function at a known address.
7208 Address trampoline_address = reinterpret_cast<Address>(
7209 reinterpret_cast<intptr_t>(EntryHookTrampoline));
7210 ApiFunction dispatcher(trampoline_address);
7211 __ mov(ip, Operand(ExternalReference(&dispatcher,
7212 ExternalReference::BUILTIN_CALL,
7213 masm->isolate())));
7214#endif
7215 __ Call(ip);
7216
7217 // Restore the stack pointer if needed.
7218 if (frame_alignment > kPointerSize) {
7219 __ mov(sp, r5);
7220 }
7221
7222 __ Pop(lr, r5, r1);
7223 __ Ret();
7224}
7225
danno@chromium.orgca29dd82013-04-26 11:59:48 +00007226
7227template<class T>
7228static void CreateArrayDispatch(MacroAssembler* masm) {
7229 int last_index = GetSequenceIndexFromFastElementsKind(
7230 TERMINAL_FAST_ELEMENTS_KIND);
7231 for (int i = 0; i <= last_index; ++i) {
7232 Label next;
7233 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
7234 __ cmp(r3, Operand(kind));
7235 __ b(ne, &next);
7236 T stub(kind);
7237 __ TailCallStub(&stub);
7238 __ bind(&next);
7239 }
7240
7241 // If we reached this point there is a problem.
7242 __ Abort("Unexpected ElementsKind in array constructor");
7243}
7244
7245
7246static void CreateArrayDispatchOneArgument(MacroAssembler* masm) {
7247 // r2 - type info cell
7248 // r3 - kind
7249 // r0 - number of arguments
7250 // r1 - constructor?
7251 // sp[0] - last argument
7252 ASSERT(FAST_SMI_ELEMENTS == 0);
7253 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
7254 ASSERT(FAST_ELEMENTS == 2);
7255 ASSERT(FAST_HOLEY_ELEMENTS == 3);
7256 ASSERT(FAST_DOUBLE_ELEMENTS == 4);
7257 ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
7258
7259 Handle<Object> undefined_sentinel(
7260 masm->isolate()->heap()->undefined_value(),
7261 masm->isolate());
7262
7263 // is the low bit set? If so, we are holey and that is good.
7264 __ tst(r3, Operand(1));
7265 Label normal_sequence;
7266 __ b(ne, &normal_sequence);
7267
7268 // look at the first argument
7269 __ ldr(r5, MemOperand(sp, 0));
7270 __ cmp(r5, Operand::Zero());
7271 __ b(eq, &normal_sequence);
7272
7273 // We are going to create a holey array, but our kind is non-holey.
7274 // Fix kind and retry
7275 __ add(r3, r3, Operand(1));
7276 __ cmp(r2, Operand(undefined_sentinel));
7277 __ b(eq, &normal_sequence);
7278
7279 // Save the resulting elements kind in type info
7280 __ SmiTag(r3);
7281 __ str(r3, FieldMemOperand(r2, kPointerSize));
7282 __ SmiUntag(r3);
7283
7284 __ bind(&normal_sequence);
7285 int last_index = GetSequenceIndexFromFastElementsKind(
7286 TERMINAL_FAST_ELEMENTS_KIND);
7287 for (int i = 0; i <= last_index; ++i) {
7288 Label next;
7289 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
7290 __ cmp(r3, Operand(kind));
7291 __ b(ne, &next);
7292 ArraySingleArgumentConstructorStub stub(kind);
7293 __ TailCallStub(&stub);
7294 __ bind(&next);
7295 }
7296
7297 // If we reached this point there is a problem.
7298 __ Abort("Unexpected ElementsKind in array constructor");
7299}
7300
7301
7302template<class T>
7303static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
7304 int to_index = GetSequenceIndexFromFastElementsKind(
7305 TERMINAL_FAST_ELEMENTS_KIND);
7306 for (int i = 0; i <= to_index; ++i) {
7307 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
7308 T stub(kind);
7309 stub.GetCode(isolate)->set_is_pregenerated(true);
7310 }
7311}
7312
7313
7314void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) {
7315 ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
7316 isolate);
7317 ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
7318 isolate);
7319 ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
7320 isolate);
7321}
7322
7323
7324void ArrayConstructorStub::Generate(MacroAssembler* masm) {
7325 // ----------- S t a t e -------------
7326 // -- r0 : argc (only if argument_count_ == ANY)
7327 // -- r1 : constructor
7328 // -- r2 : type info cell
7329 // -- sp[0] : return address
7330 // -- sp[4] : last argument
7331 // -----------------------------------
7332 Handle<Object> undefined_sentinel(
7333 masm->isolate()->heap()->undefined_value(),
7334 masm->isolate());
7335
7336 if (FLAG_debug_code) {
7337 // The array construct code is only set for the global and natives
7338 // builtin Array functions which always have maps.
7339
7340 // Initial map for the builtin Array function should be a map.
7341 __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
7342 // Will both indicate a NULL and a Smi.
7343 __ tst(r3, Operand(kSmiTagMask));
7344 __ Assert(ne, "Unexpected initial map for Array function");
7345 __ CompareObjectType(r3, r3, r4, MAP_TYPE);
7346 __ Assert(eq, "Unexpected initial map for Array function");
7347
7348 // We should either have undefined in ebx or a valid jsglobalpropertycell
7349 Label okay_here;
7350 Handle<Map> global_property_cell_map(
7351 masm->isolate()->heap()->global_property_cell_map());
7352 __ cmp(r2, Operand(undefined_sentinel));
7353 __ b(eq, &okay_here);
7354 __ ldr(r3, FieldMemOperand(r2, 0));
7355 __ cmp(r3, Operand(global_property_cell_map));
7356 __ Assert(eq, "Expected property cell in register ebx");
7357 __ bind(&okay_here);
7358 }
7359
7360 if (FLAG_optimize_constructed_arrays) {
7361 Label no_info, switch_ready;
7362 // Get the elements kind and case on that.
7363 __ cmp(r2, Operand(undefined_sentinel));
7364 __ b(eq, &no_info);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00007365 __ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
7366 __ JumpIfNotSmi(r3, &no_info);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00007367 __ SmiUntag(r3);
7368 __ jmp(&switch_ready);
7369 __ bind(&no_info);
7370 __ mov(r3, Operand(GetInitialFastElementsKind()));
7371 __ bind(&switch_ready);
7372
7373 if (argument_count_ == ANY) {
7374 Label not_zero_case, not_one_case;
7375 __ tst(r0, r0);
7376 __ b(ne, &not_zero_case);
7377 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
7378
7379 __ bind(&not_zero_case);
7380 __ cmp(r0, Operand(1));
7381 __ b(gt, &not_one_case);
7382 CreateArrayDispatchOneArgument(masm);
7383
7384 __ bind(&not_one_case);
7385 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
7386 } else if (argument_count_ == NONE) {
7387 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
7388 } else if (argument_count_ == ONE) {
7389 CreateArrayDispatchOneArgument(masm);
7390 } else if (argument_count_ == MORE_THAN_ONE) {
7391 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
7392 } else {
7393 UNREACHABLE();
7394 }
7395 } else {
7396 Label generic_constructor;
7397 // Run the native code for the Array function called as a constructor.
7398 ArrayNativeCode(masm, &generic_constructor);
7399
7400 // Jump to the generic construct code in case the specialized code cannot
7401 // handle the construction.
7402 __ bind(&generic_constructor);
7403 Handle<Code> generic_construct_stub =
7404 masm->isolate()->builtins()->JSConstructStubGeneric();
7405 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
7406 }
7407}
7408
7409
ricow@chromium.org65fae842010-08-25 15:26:24 +00007410#undef __
7411
7412} } // namespace v8::internal
7413
7414#endif // V8_TARGET_ARCH_ARM