blob: 7b652d30f58fbde0da9b53b37f7822031923f184 [file] [log] [blame]
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_ARM)
31
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "ic-inl.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000033#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000034#include "stub-cache.h"
35
kasperl@chromium.org71affb52009-05-26 05:44:31 +000036namespace v8 {
37namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
ager@chromium.org65dad4b2009-04-23 08:48:43 +000039#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040
41
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044 Code::Flags flags,
45 StubCache::Table table,
46 Register name,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000047 Register offset,
48 Register scratch,
49 Register scratch2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000050 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
51 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000053 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
54 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000056 // Check the relative positions of the address fields.
57 ASSERT(value_off_addr > key_off_addr);
58 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
59 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
60
61 Label miss;
62 Register offsets_base_addr = scratch;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64 // Check that the key in the entry matches the name.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000065 __ mov(offsets_base_addr, Operand(key_offset));
66 __ ldr(ip, MemOperand(offsets_base_addr, offset, LSL, 1));
fschneider@chromium.org013f3e12010-04-26 13:27:52 +000067 __ cmp(name, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068 __ b(ne, &miss);
69
70 // Get the code entry from the cache.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000071 __ add(offsets_base_addr, offsets_base_addr,
72 Operand(value_off_addr - key_off_addr));
73 __ ldr(scratch2, MemOperand(offsets_base_addr, offset, LSL, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074
75 // Check that the flags match what we're looking for.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000076 __ ldr(scratch2, FieldMemOperand(scratch2, Code::kFlagsOffset));
77 __ bic(scratch2, scratch2, Operand(Code::kFlagsNotUsedInLookup));
78 __ cmp(scratch2, Operand(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 __ b(ne, &miss);
80
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000081 // Re-load code entry from cache.
82 __ ldr(offset, MemOperand(offsets_base_addr, offset, LSL, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000083
84 // Jump to the first instruction in the code stub.
85 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
86 __ Jump(offset);
87
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000088 // Miss: fall through.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090}
91
92
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000093// Helper function used to check that the dictionary doesn't contain
94// the property. This function may return false negatives, so miss_label
95// must always call a backup property check that is complete.
96// This function is safe to call if the receiver has fast properties.
97// Name must be a symbol and receiver must be a heap object.
karlklose@chromium.org83a47282011-05-11 11:54:09 +000098MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup(
99 MacroAssembler* masm,
100 Label* miss_label,
101 Register receiver,
102 String* name,
103 Register scratch0,
104 Register scratch1) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000105 ASSERT(name->IsSymbol());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000106 Counters* counters = masm->isolate()->counters();
107 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
108 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000109
110 Label done;
111
112 const int kInterceptorOrAccessCheckNeededMask =
113 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
114
115 // Bail out if the receiver has a named interceptor or requires access checks.
116 Register map = scratch1;
117 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
118 __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
119 __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
120 __ b(ne, miss_label);
121
122 // Check that receiver is a JSObject.
123 __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000124 __ cmp(scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000125 __ b(lt, miss_label);
126
127 // Load properties array.
128 Register properties = scratch0;
129 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
130 // Check that the properties array is a dictionary.
131 __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
132 Register tmp = properties;
133 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
134 __ cmp(map, tmp);
135 __ b(ne, miss_label);
136
137 // Restore the temporarily used register.
138 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
139
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000140
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000141 MaybeObject* result = StringDictionaryLookupStub::GenerateNegativeLookup(
142 masm,
143 miss_label,
144 &done,
145 receiver,
146 properties,
147 name,
148 scratch1);
149 if (result->IsFailure()) return result;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000150
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000151 __ bind(&done);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000152 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000153
154 return result;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000155}
156
157
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158void StubCache::GenerateProbe(MacroAssembler* masm,
159 Code::Flags flags,
160 Register receiver,
161 Register name,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000162 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000163 Register extra,
164 Register extra2) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000165 Isolate* isolate = masm->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166 Label miss;
167
168 // Make sure that code is valid. The shifting code relies on the
169 // entry size being 8.
170 ASSERT(sizeof(Entry) == 8);
171
172 // Make sure the flags does not name a specific type.
173 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
174
175 // Make sure that there are no register conflicts.
176 ASSERT(!scratch.is(receiver));
177 ASSERT(!scratch.is(name));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000178 ASSERT(!extra.is(receiver));
179 ASSERT(!extra.is(name));
180 ASSERT(!extra.is(scratch));
181 ASSERT(!extra2.is(receiver));
182 ASSERT(!extra2.is(name));
183 ASSERT(!extra2.is(scratch));
184 ASSERT(!extra2.is(extra));
185
186 // Check scratch, extra and extra2 registers are valid.
187 ASSERT(!scratch.is(no_reg));
188 ASSERT(!extra.is(no_reg));
189 ASSERT(!extra2.is(no_reg));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000190
191 // Check that the receiver isn't a smi.
192 __ tst(receiver, Operand(kSmiTagMask));
193 __ b(eq, &miss);
194
195 // Get the map of the receiver and compute the hash.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000196 __ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000197 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000198 __ add(scratch, scratch, Operand(ip));
199 __ eor(scratch, scratch, Operand(flags));
200 __ and_(scratch,
201 scratch,
202 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
203
204 // Probe the primary table.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000205 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra, extra2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206
207 // Primary miss: Compute hash for secondary probe.
208 __ sub(scratch, scratch, Operand(name));
209 __ add(scratch, scratch, Operand(flags));
210 __ and_(scratch,
211 scratch,
212 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
213
214 // Probe the secondary table.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000215 ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra, extra2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216
217 // Cache miss: Fall-through and let caller handle the miss by
218 // entering the runtime system.
219 __ bind(&miss);
220}
221
222
223void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
224 int index,
225 Register prototype) {
226 // Load the global or builtins object from the current context.
227 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
228 // Load the global context from the global or builtins object.
229 __ ldr(prototype,
230 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
231 // Load the function from the global context.
232 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
233 // Load the initial map. The global functions all have initial maps.
234 __ ldr(prototype,
235 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
236 // Load the prototype from the initial map.
237 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
238}
239
240
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000241void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000242 MacroAssembler* masm, int index, Register prototype, Label* miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000243 Isolate* isolate = masm->isolate();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000244 // Check we're still in the same context.
245 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000246 __ Move(ip, isolate->global());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000247 __ cmp(prototype, ip);
248 __ b(ne, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000249 // Get the global function with the given index.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000250 JSFunction* function =
251 JSFunction::cast(isolate->global_context()->get(index));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000252 // Load its initial map. The global functions all have initial maps.
253 __ Move(prototype, Handle<Map>(function->initial_map()));
254 // Load the prototype from the initial map.
255 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
256}
257
258
ager@chromium.org7c537e22008-10-16 08:43:32 +0000259// Load a fast property out of a holder object (src). In-object properties
260// are loaded directly otherwise the property is loaded from the properties
261// fixed array.
262void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
263 Register dst, Register src,
264 JSObject* holder, int index) {
265 // Adjust for the number of properties stored in the holder.
266 index -= holder->map()->inobject_properties();
267 if (index < 0) {
268 // Get the property straight out of the holder.
269 int offset = holder->map()->instance_size() + (index * kPointerSize);
270 __ ldr(dst, FieldMemOperand(src, offset));
271 } else {
272 // Calculate the offset into the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000273 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000274 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
275 __ ldr(dst, FieldMemOperand(dst, offset));
276 }
277}
278
279
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000280void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
281 Register receiver,
282 Register scratch,
283 Label* miss_label) {
284 // Check that the receiver isn't a smi.
285 __ tst(receiver, Operand(kSmiTagMask));
286 __ b(eq, miss_label);
287
288 // Check that the object is a JS array.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000289 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000290 __ b(ne, miss_label);
291
292 // Load length directly from the JS array.
293 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
294 __ Ret();
295}
296
297
ager@chromium.org5c838252010-02-19 08:53:10 +0000298// Generate code to check if an object is a string. If the object is a
299// heap object, its map's instance type is left in the scratch1 register.
300// If this is not needed, scratch1 and scratch2 may be the same register.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000301static void GenerateStringCheck(MacroAssembler* masm,
302 Register receiver,
303 Register scratch1,
304 Register scratch2,
305 Label* smi,
306 Label* non_string_object) {
307 // Check that the receiver isn't a smi.
308 __ tst(receiver, Operand(kSmiTagMask));
309 __ b(eq, smi);
310
311 // Check that the object is a string.
312 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
313 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
314 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
315 // The cast is to resolve the overload for the argument of 0x0.
316 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
317 __ b(ne, non_string_object);
318}
319
320
ager@chromium.org32912102009-01-16 10:38:43 +0000321// Generate code to load the length from a string object and return the length.
322// If the receiver object is not a string or a wrapped string object the
323// execution continues at the miss label. The register containing the
324// receiver is potentially clobbered.
ager@chromium.org5c838252010-02-19 08:53:10 +0000325void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
326 Register receiver,
327 Register scratch1,
328 Register scratch2,
ager@chromium.org378b34e2011-01-28 08:04:38 +0000329 Label* miss,
330 bool support_wrappers) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000331 Label check_wrapper;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000332
333 // Check if the object is a string leaving the instance type in the
334 // scratch1 register.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000335 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
336 support_wrappers ? &check_wrapper : miss);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000337
338 // Load length directly from the string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000339 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000340 __ Ret();
341
ager@chromium.org378b34e2011-01-28 08:04:38 +0000342 if (support_wrappers) {
343 // Check if the object is a JSValue wrapper.
344 __ bind(&check_wrapper);
345 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
346 __ b(ne, miss);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000347
ager@chromium.org378b34e2011-01-28 08:04:38 +0000348 // Unwrap the value and check if the wrapped value is a string.
349 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
350 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
351 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
352 __ Ret();
353 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000354}
355
356
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000357void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
358 Register receiver,
359 Register scratch1,
360 Register scratch2,
361 Label* miss_label) {
362 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
363 __ mov(r0, scratch1);
364 __ Ret();
365}
366
367
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000368// Generate StoreField code, value is passed in r0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000369// When leaving generated code after success, the receiver_reg and name_reg
370// may be clobbered. Upon branch to miss_label, the receiver and name
371// registers have their original values.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000372void StubCompiler::GenerateStoreField(MacroAssembler* masm,
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000373 JSObject* object,
374 int index,
375 Map* transition,
376 Register receiver_reg,
377 Register name_reg,
378 Register scratch,
379 Label* miss_label) {
380 // r0 : value
381 Label exit;
382
383 // Check that the receiver isn't a smi.
384 __ tst(receiver_reg, Operand(kSmiTagMask));
385 __ b(eq, miss_label);
386
387 // Check that the map of the receiver hasn't changed.
388 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
389 __ cmp(scratch, Operand(Handle<Map>(object->map())));
390 __ b(ne, miss_label);
391
392 // Perform global security token check if needed.
393 if (object->IsJSGlobalProxy()) {
394 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
395 }
396
397 // Stub never generated for non-global objects that require access
398 // checks.
399 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
400
401 // Perform map transition for the receiver if necessary.
402 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
403 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000404 // We jump to a runtime call that extends the properties array.
ager@chromium.org5c838252010-02-19 08:53:10 +0000405 __ push(receiver_reg);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000406 __ mov(r2, Operand(Handle<Map>(transition)));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000407 __ Push(r2, r0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000408 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000409 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
410 masm->isolate()),
411 3,
412 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000413 return;
414 }
415
416 if (transition != NULL) {
417 // Update the map of the object; no write barrier updating is
418 // needed because the map is never in new space.
419 __ mov(ip, Operand(Handle<Map>(transition)));
420 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
421 }
422
423 // Adjust for the number of properties stored in the object. Even in the
424 // face of a transition we can use the old map here because the size of the
425 // object and the number of in-object properties is not going to change.
426 index -= object->map()->inobject_properties();
427
428 if (index < 0) {
429 // Set the property straight into the object.
430 int offset = object->map()->instance_size() + (index * kPointerSize);
431 __ str(r0, FieldMemOperand(receiver_reg, offset));
432
433 // Skip updating write barrier if storing a smi.
434 __ tst(r0, Operand(kSmiTagMask));
435 __ b(eq, &exit);
436
437 // Update the write barrier for the array address.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000438 // Pass the now unused name_reg as a scratch register.
439 __ RecordWrite(receiver_reg, Operand(offset), name_reg, scratch);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000440 } else {
441 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000442 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000443 // Get the properties array
444 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
445 __ str(r0, FieldMemOperand(scratch, offset));
446
447 // Skip updating write barrier if storing a smi.
448 __ tst(r0, Operand(kSmiTagMask));
449 __ b(eq, &exit);
450
451 // Update the write barrier for the array address.
452 // Ok to clobber receiver_reg and name_reg, since we return.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000453 __ RecordWrite(scratch, Operand(offset), name_reg, receiver_reg);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000454 }
455
456 // Return the value (register r0).
457 __ bind(&exit);
458 __ Ret();
459}
460
461
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000462void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
463 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
464 Code* code = NULL;
465 if (kind == Code::LOAD_IC) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000466 code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000467 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000468 code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000469 }
470
471 Handle<Code> ic(code);
472 __ Jump(ic, RelocInfo::CODE_TARGET);
473}
474
475
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000476static void GenerateCallFunction(MacroAssembler* masm,
477 Object* object,
478 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000479 Label* miss,
480 Code::ExtraICState extra_ic_state) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000481 // ----------- S t a t e -------------
482 // -- r0: receiver
483 // -- r1: function to call
484 // -----------------------------------
485
486 // Check that the function really is a function.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000487 __ JumpIfSmi(r1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000488 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000489 __ b(ne, miss);
490
491 // Patch the receiver on the stack with the global proxy if
492 // necessary.
493 if (object->IsGlobalObject()) {
494 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
495 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
496 }
497
498 // Invoke the function.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000499 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
500 ? CALL_AS_FUNCTION
501 : CALL_AS_METHOD;
502 __ InvokeFunction(r1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000503}
504
505
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000506static void PushInterceptorArguments(MacroAssembler* masm,
507 Register receiver,
508 Register holder,
509 Register name,
510 JSObject* holder_obj) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000511 __ push(name);
512 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000513 ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000514 Register scratch = name;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000515 __ mov(scratch, Operand(Handle<Object>(interceptor)));
516 __ push(scratch);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000517 __ push(receiver);
518 __ push(holder);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000519 __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
520 __ push(scratch);
521}
522
523
524static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
525 Register receiver,
526 Register holder,
527 Register name,
528 JSObject* holder_obj) {
529 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
530
531 ExternalReference ref =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000532 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
533 masm->isolate());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000534 __ mov(r0, Operand(5));
535 __ mov(r1, Operand(ref));
536
537 CEntryStub stub(1);
538 __ CallStub(&stub);
539}
540
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000541static const int kFastApiCallArguments = 3;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000542
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000543// Reserves space for the extra arguments to FastHandleApiCall in the
544// caller's frame.
545//
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000546// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000547static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
548 Register scratch) {
549 __ mov(scratch, Operand(Smi::FromInt(0)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000550 for (int i = 0; i < kFastApiCallArguments; i++) {
551 __ push(scratch);
552 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000553}
554
555
556// Undoes the effects of ReserveSpaceForFastApiCall.
557static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000558 __ Drop(kFastApiCallArguments);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000559}
560
561
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000562static MaybeObject* GenerateFastApiDirectCall(MacroAssembler* masm,
563 const CallOptimization& optimization,
564 int argc) {
565 // ----------- S t a t e -------------
566 // -- sp[0] : holder (set by CheckPrototypes)
567 // -- sp[4] : callee js function
568 // -- sp[8] : call data
569 // -- sp[12] : last js argument
570 // -- ...
571 // -- sp[(argc + 3) * 4] : first js argument
572 // -- sp[(argc + 4) * 4] : receiver
573 // -----------------------------------
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000574 // Get the function and setup the context.
575 JSFunction* function = optimization.constant_function();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000576 __ mov(r5, Operand(Handle<JSFunction>(function)));
577 __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000578
579 // Pass the additional arguments FastHandleApiCall expects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000580 Object* call_data = optimization.api_call_info()->data();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000581 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000582 if (masm->isolate()->heap()->InNewSpace(call_data)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000583 __ Move(r0, api_call_info_handle);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000584 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000585 } else {
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000586 __ Move(r6, Handle<Object>(call_data));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000587 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000588 // Store js function and call data.
589 __ stm(ib, sp, r5.bit() | r6.bit());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000590
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000591 // r2 points to call data as expected by Arguments
592 // (refer to layout above).
593 __ add(r2, sp, Operand(2 * kPointerSize));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000594
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000595 Object* callback = optimization.api_call_info()->callback();
596 Address api_function_address = v8::ToCData<Address>(callback);
597 ApiFunction fun(api_function_address);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000598
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000599 const int kApiStackSpace = 4;
600 __ EnterExitFrame(false, kApiStackSpace);
601
602 // r0 = v8::Arguments&
603 // Arguments is after the return address.
604 __ add(r0, sp, Operand(1 * kPointerSize));
605 // v8::Arguments::implicit_args = data
606 __ str(r2, MemOperand(r0, 0 * kPointerSize));
607 // v8::Arguments::values = last argument
608 __ add(ip, r2, Operand(argc * kPointerSize));
609 __ str(ip, MemOperand(r0, 1 * kPointerSize));
610 // v8::Arguments::length_ = argc
611 __ mov(ip, Operand(argc));
612 __ str(ip, MemOperand(r0, 2 * kPointerSize));
613 // v8::Arguments::is_construct_call = 0
614 __ mov(ip, Operand(0));
615 __ str(ip, MemOperand(r0, 3 * kPointerSize));
616
617 // Emitting a stub call may try to allocate (if the code is not
618 // already generated). Do not allow the assembler to perform a
619 // garbage collection but instead return the allocation failure
620 // object.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000621 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000622 ExternalReference ref = ExternalReference(&fun,
623 ExternalReference::DIRECT_API_CALL,
624 masm->isolate());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000625 return masm->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000626}
627
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000628class CallInterceptorCompiler BASE_EMBEDDED {
629 public:
630 CallInterceptorCompiler(StubCompiler* stub_compiler,
631 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000632 Register name,
633 Code::ExtraICState extra_ic_state)
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000634 : stub_compiler_(stub_compiler),
635 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000636 name_(name),
637 extra_ic_state_(extra_ic_state) {}
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000638
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000639 MaybeObject* Compile(MacroAssembler* masm,
640 JSObject* object,
641 JSObject* holder,
642 String* name,
643 LookupResult* lookup,
644 Register receiver,
645 Register scratch1,
646 Register scratch2,
647 Register scratch3,
648 Label* miss) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000649 ASSERT(holder->HasNamedInterceptor());
650 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
651
652 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000653 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000654
655 CallOptimization optimization(lookup);
656
657 if (optimization.is_constant_call()) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000658 return CompileCacheable(masm,
659 object,
660 receiver,
661 scratch1,
662 scratch2,
663 scratch3,
664 holder,
665 lookup,
666 name,
667 optimization,
668 miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000669 } else {
670 CompileRegular(masm,
671 object,
672 receiver,
673 scratch1,
674 scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000675 scratch3,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000676 name,
677 holder,
678 miss);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000679 return masm->isolate()->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000680 }
681 }
682
683 private:
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000684 MaybeObject* CompileCacheable(MacroAssembler* masm,
685 JSObject* object,
686 Register receiver,
687 Register scratch1,
688 Register scratch2,
689 Register scratch3,
690 JSObject* interceptor_holder,
691 LookupResult* lookup,
692 String* name,
693 const CallOptimization& optimization,
694 Label* miss_label) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000695 ASSERT(optimization.is_constant_call());
696 ASSERT(!lookup->holder()->IsGlobalObject());
697
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000698 Counters* counters = masm->isolate()->counters();
699
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000700 int depth1 = kInvalidProtoDepth;
701 int depth2 = kInvalidProtoDepth;
702 bool can_do_fast_api_call = false;
703 if (optimization.is_simple_api_call() &&
704 !lookup->holder()->IsGlobalObject()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000705 depth1 =
706 optimization.GetPrototypeDepthOfExpectedType(object,
707 interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000708 if (depth1 == kInvalidProtoDepth) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000709 depth2 =
710 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
711 lookup->holder());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000712 }
713 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
714 (depth2 != kInvalidProtoDepth);
715 }
716
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000717 __ IncrementCounter(counters->call_const_interceptor(), 1,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000718 scratch1, scratch2);
719
720 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000721 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000722 scratch1, scratch2);
723 ReserveSpaceForFastApiCall(masm, scratch1);
724 }
725
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000726 // Check that the maps from receiver to interceptor's holder
727 // haven't changed and thus we can invoke interceptor.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000728 Label miss_cleanup;
729 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
730 Register holder =
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000731 stub_compiler_->CheckPrototypes(object, receiver,
732 interceptor_holder, scratch1,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000733 scratch2, scratch3, name, depth1, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000734
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000735 // Invoke an interceptor and if it provides a value,
736 // branch to |regular_invoke|.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000737 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000738 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000739 &regular_invoke);
740
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000741 // Interceptor returned nothing for this property. Try to use cached
742 // constant function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000743
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000744 // Check that the maps from interceptor's holder to constant function's
745 // holder haven't changed and thus we can use cached constant function.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000746 if (interceptor_holder != lookup->holder()) {
747 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
748 lookup->holder(), scratch1,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000749 scratch2, scratch3, name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000750 } else {
751 // CheckPrototypes has a side effect of fetching a 'holder'
752 // for API (object which is instanceof for the signature). It's
753 // safe to omit it here, as if present, it should be fetched
754 // by the previous CheckPrototypes.
755 ASSERT(depth2 == kInvalidProtoDepth);
756 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000757
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000758 // Invoke function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000759 if (can_do_fast_api_call) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000760 MaybeObject* result = GenerateFastApiDirectCall(masm,
761 optimization,
762 arguments_.immediate());
763 if (result->IsFailure()) return result;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000764 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000765 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
766 ? CALL_AS_FUNCTION
767 : CALL_AS_METHOD;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000768 __ InvokeFunction(optimization.constant_function(), arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000769 JUMP_FUNCTION, call_kind);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000770 }
771
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000772 // Deferred code for fast API call case---clean preallocated space.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000773 if (can_do_fast_api_call) {
774 __ bind(&miss_cleanup);
775 FreeSpaceForFastApiCall(masm);
776 __ b(miss_label);
777 }
778
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000779 // Invoke a regular function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000780 __ bind(&regular_invoke);
781 if (can_do_fast_api_call) {
782 FreeSpaceForFastApiCall(masm);
783 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000784
lrn@chromium.org7516f052011-03-30 08:52:27 +0000785 return masm->isolate()->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000786 }
787
788 void CompileRegular(MacroAssembler* masm,
789 JSObject* object,
790 Register receiver,
791 Register scratch1,
792 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000793 Register scratch3,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000794 String* name,
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000795 JSObject* interceptor_holder,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000796 Label* miss_label) {
797 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000798 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000799 scratch1, scratch2, scratch3, name,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000800 miss_label);
801
802 // Call a runtime function to load the interceptor property.
803 __ EnterInternalFrame();
804 // Save the name_ register across the call.
805 __ push(name_);
806
807 PushInterceptorArguments(masm,
808 receiver,
809 holder,
810 name_,
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000811 interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000812
813 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000814 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
815 masm->isolate()),
816 5);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000817
818 // Restore the name_ register.
819 __ pop(name_);
820 __ LeaveInternalFrame();
821 }
822
823 void LoadWithInterceptor(MacroAssembler* masm,
824 Register receiver,
825 Register holder,
826 JSObject* holder_obj,
827 Register scratch,
828 Label* interceptor_succeeded) {
829 __ EnterInternalFrame();
830 __ Push(holder, name_);
831
832 CompileCallLoadPropertyWithInterceptor(masm,
833 receiver,
834 holder,
835 name_,
836 holder_obj);
837
838 __ pop(name_); // Restore the name.
839 __ pop(receiver); // Restore the holder.
840 __ LeaveInternalFrame();
841
842 // If interceptor returns no-result sentinel, call the constant function.
843 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
844 __ cmp(r0, scratch);
845 __ b(ne, interceptor_succeeded);
846 }
847
848 StubCompiler* stub_compiler_;
849 const ParameterCount& arguments_;
850 Register name_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000851 Code::ExtraICState extra_ic_state_;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000852};
853
854
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000855// Generate code to check that a global property cell is empty. Create
856// the property cell at compilation time if no cell exists for the
857// property.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000858MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
859 MacroAssembler* masm,
860 GlobalObject* global,
861 String* name,
862 Register scratch,
863 Label* miss) {
864 Object* probe;
865 { MaybeObject* maybe_probe = global->EnsurePropertyCell(name);
866 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
867 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000868 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
869 ASSERT(cell->value()->IsTheHole());
870 __ mov(scratch, Operand(Handle<Object>(cell)));
871 __ ldr(scratch,
872 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
873 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
874 __ cmp(scratch, ip);
875 __ b(ne, miss);
876 return cell;
877}
878
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000879// Calls GenerateCheckPropertyCell for each global object in the prototype chain
880// from object to (but not including) holder.
881MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells(
882 MacroAssembler* masm,
883 JSObject* object,
884 JSObject* holder,
885 String* name,
886 Register scratch,
887 Label* miss) {
888 JSObject* current = object;
889 while (current != holder) {
890 if (current->IsGlobalObject()) {
891 // Returns a cell or a failure.
892 MaybeObject* result = GenerateCheckPropertyCell(
893 masm,
894 GlobalObject::cast(current),
895 name,
896 scratch,
897 miss);
898 if (result->IsFailure()) return result;
899 }
900 ASSERT(current->IsJSObject());
901 current = JSObject::cast(current->GetPrototype());
902 }
903 return NULL;
904}
905
906
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000907// Convert and store int passed in register ival to IEEE 754 single precision
908// floating point value at memory location (dst + 4 * wordoffset)
909// If VFP3 is available use it for conversion.
910static void StoreIntAsFloat(MacroAssembler* masm,
911 Register dst,
912 Register wordoffset,
913 Register ival,
914 Register fval,
915 Register scratch1,
916 Register scratch2) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000917 if (CpuFeatures::IsSupported(VFP3)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000918 CpuFeatures::Scope scope(VFP3);
919 __ vmov(s0, ival);
920 __ add(scratch1, dst, Operand(wordoffset, LSL, 2));
921 __ vcvt_f32_s32(s0, s0);
922 __ vstr(s0, scratch1, 0);
923 } else {
924 Label not_special, done;
925 // Move sign bit from source to destination. This works because the sign
926 // bit in the exponent word of the double has the same position and polarity
927 // as the 2's complement sign bit in a Smi.
928 ASSERT(kBinary32SignMask == 0x80000000u);
929
930 __ and_(fval, ival, Operand(kBinary32SignMask), SetCC);
931 // Negate value if it is negative.
932 __ rsb(ival, ival, Operand(0, RelocInfo::NONE), LeaveCC, ne);
933
934 // We have -1, 0 or 1, which we treat specially. Register ival contains
935 // absolute value: it is either equal to 1 (special case of -1 and 1),
936 // greater than 1 (not a special case) or less than 1 (special case of 0).
937 __ cmp(ival, Operand(1));
938 __ b(gt, &not_special);
939
940 // For 1 or -1 we need to or in the 0 exponent (biased).
941 static const uint32_t exponent_word_for_1 =
942 kBinary32ExponentBias << kBinary32ExponentShift;
943
944 __ orr(fval, fval, Operand(exponent_word_for_1), LeaveCC, eq);
945 __ b(&done);
946
947 __ bind(&not_special);
948 // Count leading zeros.
949 // Gets the wrong answer for 0, but we already checked for that case above.
950 Register zeros = scratch2;
951 __ CountLeadingZeros(zeros, ival, scratch1);
952
953 // Compute exponent and or it into the exponent register.
954 __ rsb(scratch1,
955 zeros,
956 Operand((kBitsPerInt - 1) + kBinary32ExponentBias));
957
958 __ orr(fval,
959 fval,
960 Operand(scratch1, LSL, kBinary32ExponentShift));
961
962 // Shift up the source chopping the top bit off.
963 __ add(zeros, zeros, Operand(1));
964 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
965 __ mov(ival, Operand(ival, LSL, zeros));
966 // And the top (top 20 bits).
967 __ orr(fval,
968 fval,
969 Operand(ival, LSR, kBitsPerInt - kBinary32MantissaBits));
970
971 __ bind(&done);
972 __ str(fval, MemOperand(dst, wordoffset, LSL, 2));
973 }
974}
975
976
977// Convert unsigned integer with specified number of leading zeroes in binary
978// representation to IEEE 754 double.
979// Integer to convert is passed in register hiword.
980// Resulting double is returned in registers hiword:loword.
981// This functions does not work correctly for 0.
982static void GenerateUInt2Double(MacroAssembler* masm,
983 Register hiword,
984 Register loword,
985 Register scratch,
986 int leading_zeroes) {
987 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
988 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
989
990 const int mantissa_shift_for_hi_word =
991 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
992
993 const int mantissa_shift_for_lo_word =
994 kBitsPerInt - mantissa_shift_for_hi_word;
995
996 __ mov(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
997 if (mantissa_shift_for_hi_word > 0) {
998 __ mov(loword, Operand(hiword, LSL, mantissa_shift_for_lo_word));
999 __ orr(hiword, scratch, Operand(hiword, LSR, mantissa_shift_for_hi_word));
1000 } else {
1001 __ mov(loword, Operand(0, RelocInfo::NONE));
1002 __ orr(hiword, scratch, Operand(hiword, LSL, mantissa_shift_for_hi_word));
1003 }
1004
1005 // If least significant bit of biased exponent was not 1 it was corrupted
1006 // by most significant bit of mantissa so we should fix that.
1007 if (!(biased_exponent & 1)) {
1008 __ bic(hiword, hiword, Operand(1 << HeapNumber::kExponentShift));
1009 }
1010}
1011
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001012
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001014#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015
1016
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001017Register StubCompiler::CheckPrototypes(JSObject* object,
1018 Register object_reg,
1019 JSObject* holder,
1020 Register holder_reg,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001021 Register scratch1,
1022 Register scratch2,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001023 String* name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001024 int save_at_depth,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001025 Label* miss) {
1026 // Make sure there's no overlap between holder and object registers.
1027 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1028 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1029 && !scratch2.is(scratch1));
1030
1031 // Keep track of the current object in register reg.
1032 Register reg = object_reg;
1033 int depth = 0;
1034
1035 if (save_at_depth == depth) {
1036 __ str(reg, MemOperand(sp));
1037 }
1038
1039 // Check the maps in the prototype chain.
1040 // Traverse the prototype chain from the object and do map checks.
1041 JSObject* current = object;
1042 while (current != holder) {
1043 depth++;
1044
1045 // Only global objects and objects that do not require access
1046 // checks are allowed in stubs.
1047 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1048
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001049 ASSERT(current->GetPrototype()->IsJSObject());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001050 JSObject* prototype = JSObject::cast(current->GetPrototype());
1051 if (!current->HasFastProperties() &&
1052 !current->IsJSGlobalObject() &&
1053 !current->IsJSGlobalProxy()) {
1054 if (!name->IsSymbol()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001055 MaybeObject* maybe_lookup_result = heap()->LookupSymbol(name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001056 Object* lookup_result = NULL; // Initialization to please compiler.
1057 if (!maybe_lookup_result->ToObject(&lookup_result)) {
1058 set_failure(Failure::cast(maybe_lookup_result));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001059 return reg;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001060 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001061 name = String::cast(lookup_result);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001062 }
1063 ASSERT(current->property_dictionary()->FindEntry(name) ==
1064 StringDictionary::kNotFound);
1065
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001066 MaybeObject* negative_lookup = GenerateDictionaryNegativeLookup(masm(),
1067 miss,
1068 reg,
1069 name,
1070 scratch1,
1071 scratch2);
1072 if (negative_lookup->IsFailure()) {
1073 set_failure(Failure::cast(negative_lookup));
1074 return reg;
1075 }
1076
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001077 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1078 reg = holder_reg; // from now the object is in holder_reg
1079 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001080 } else if (heap()->InNewSpace(prototype)) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001081 // Get the map of the current object.
1082 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1083 __ cmp(scratch1, Operand(Handle<Map>(current->map())));
1084
1085 // Branch on the result of the map check.
1086 __ b(ne, miss);
1087
1088 // Check access rights to the global object. This has to happen
1089 // after the map check so that we know that the object is
1090 // actually a global object.
1091 if (current->IsJSGlobalProxy()) {
1092 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1093 // Restore scratch register to be the map of the object. In the
1094 // new space case below, we load the prototype from the map in
1095 // the scratch register.
1096 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1097 }
1098
1099 reg = holder_reg; // from now the object is in holder_reg
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001100 // The prototype is in new space; we cannot store a reference
1101 // to it in the code. Load it from the map.
1102 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1103 } else {
1104 // Check the map of the current object.
1105 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1106 __ cmp(scratch1, Operand(Handle<Map>(current->map())));
1107 // Branch on the result of the map check.
1108 __ b(ne, miss);
1109 // Check access rights to the global object. This has to happen
1110 // after the map check so that we know that the object is
1111 // actually a global object.
1112 if (current->IsJSGlobalProxy()) {
1113 __ CheckAccessGlobalProxy(reg, scratch1, miss);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001114 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001115 // The prototype is in old space; load it directly.
1116 reg = holder_reg; // from now the object is in holder_reg
1117 __ mov(reg, Operand(Handle<JSObject>(prototype)));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001118 }
1119
1120 if (save_at_depth == depth) {
1121 __ str(reg, MemOperand(sp));
1122 }
1123
1124 // Go to the next object in the prototype chain.
1125 current = prototype;
1126 }
1127
1128 // Check the holder map.
1129 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1130 __ cmp(scratch1, Operand(Handle<Map>(current->map())));
1131 __ b(ne, miss);
1132
1133 // Log the check depth.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001134 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001135
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001136 // Perform security check for access to the global object.
1137 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1138 if (holder->IsJSGlobalProxy()) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001139 __ CheckAccessGlobalProxy(reg, scratch1, miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001140 };
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001141
1142 // If we've skipped any global objects, it's not enough to verify
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001143 // that their maps haven't changed. We also need to check that the
1144 // property cell for the property is still empty.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001145 MaybeObject* result = GenerateCheckPropertyCells(masm(),
1146 object,
1147 holder,
1148 name,
1149 scratch1,
1150 miss);
1151 if (result->IsFailure()) set_failure(Failure::cast(result));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001152
ager@chromium.org5c838252010-02-19 08:53:10 +00001153 // Return the register containing the holder.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001154 return reg;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001155}
1156
1157
1158void StubCompiler::GenerateLoadField(JSObject* object,
1159 JSObject* holder,
1160 Register receiver,
1161 Register scratch1,
1162 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001163 Register scratch3,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001164 int index,
1165 String* name,
1166 Label* miss) {
1167 // Check that the receiver isn't a smi.
1168 __ tst(receiver, Operand(kSmiTagMask));
1169 __ b(eq, miss);
1170
1171 // Check that the maps haven't changed.
1172 Register reg =
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001173 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1174 name, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001175 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
1176 __ Ret();
1177}
1178
1179
1180void StubCompiler::GenerateLoadConstant(JSObject* object,
1181 JSObject* holder,
1182 Register receiver,
1183 Register scratch1,
1184 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001185 Register scratch3,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001186 Object* value,
1187 String* name,
1188 Label* miss) {
1189 // Check that the receiver isn't a smi.
1190 __ tst(receiver, Operand(kSmiTagMask));
1191 __ b(eq, miss);
1192
1193 // Check that the maps haven't changed.
1194 Register reg =
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001195 CheckPrototypes(object, receiver, holder,
1196 scratch1, scratch2, scratch3, name, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001197
1198 // Return the constant value.
1199 __ mov(r0, Operand(Handle<Object>(value)));
1200 __ Ret();
1201}
1202
1203
ager@chromium.org378b34e2011-01-28 08:04:38 +00001204MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
1205 JSObject* holder,
1206 Register receiver,
1207 Register name_reg,
1208 Register scratch1,
1209 Register scratch2,
1210 Register scratch3,
1211 AccessorInfo* callback,
1212 String* name,
1213 Label* miss) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001214 // Check that the receiver isn't a smi.
1215 __ tst(receiver, Operand(kSmiTagMask));
1216 __ b(eq, miss);
1217
1218 // Check that the maps haven't changed.
1219 Register reg =
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001220 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1221 name, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001222
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001223 // Build AccessorInfo::args_ list on the stack and push property name below
1224 // the exit frame to make GC aware of them and store pointers to them.
1225 __ push(receiver);
1226 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
1227 Handle<AccessorInfo> callback_handle(callback);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001228 if (heap()->InNewSpace(callback_handle->data())) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001229 __ Move(scratch3, callback_handle);
1230 __ ldr(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1231 } else {
1232 __ Move(scratch3, Handle<Object>(callback_handle->data()));
1233 }
1234 __ Push(reg, scratch3, name_reg);
1235 __ mov(r0, sp); // r0 = Handle<String>
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001236
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001237 Address getter_address = v8::ToCData<Address>(callback->getter());
1238 ApiFunction fun(getter_address);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001239
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001240 const int kApiStackSpace = 1;
1241 __ EnterExitFrame(false, kApiStackSpace);
1242 // Create AccessorInfo instance on the stack above the exit frame with
1243 // scratch2 (internal::Object **args_) as the data.
1244 __ str(scratch2, MemOperand(sp, 1 * kPointerSize));
1245 __ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo&
1246
1247 // Emitting a stub call may try to allocate (if the code is not
1248 // already generated). Do not allow the assembler to perform a
1249 // garbage collection but instead return the allocation failure
1250 // object.
1251 const int kStackUnwindSpace = 4;
1252 ExternalReference ref =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001253 ExternalReference(&fun,
1254 ExternalReference::DIRECT_GETTER_CALL,
1255 masm()->isolate());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001256 return masm()->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001257}
1258
1259
1260void StubCompiler::GenerateLoadInterceptor(JSObject* object,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001261 JSObject* interceptor_holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001262 LookupResult* lookup,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001263 Register receiver,
1264 Register name_reg,
1265 Register scratch1,
1266 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001267 Register scratch3,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001268 String* name,
1269 Label* miss) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001270 ASSERT(interceptor_holder->HasNamedInterceptor());
1271 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1272
1273 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001274 __ JumpIfSmi(receiver, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001275
1276 // So far the most popular follow ups for interceptor loads are FIELD
1277 // and CALLBACKS, so inline only them, other cases may be added
1278 // later.
1279 bool compile_followup_inline = false;
1280 if (lookup->IsProperty() && lookup->IsCacheable()) {
1281 if (lookup->type() == FIELD) {
1282 compile_followup_inline = true;
1283 } else if (lookup->type() == CALLBACKS &&
1284 lookup->GetCallbackObject()->IsAccessorInfo() &&
1285 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
1286 compile_followup_inline = true;
1287 }
1288 }
1289
1290 if (compile_followup_inline) {
1291 // Compile the interceptor call, followed by inline code to load the
1292 // property from further up the prototype chain if the call fails.
1293 // Check that the maps haven't changed.
1294 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001295 scratch1, scratch2, scratch3,
1296 name, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001297 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1298
1299 // Save necessary data before invoking an interceptor.
1300 // Requires a frame to make GC aware of pushed pointers.
1301 __ EnterInternalFrame();
1302
1303 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1304 // CALLBACKS case needs a receiver to be passed into C++ callback.
1305 __ Push(receiver, holder_reg, name_reg);
1306 } else {
1307 __ Push(holder_reg, name_reg);
1308 }
1309
1310 // Invoke an interceptor. Note: map checks from receiver to
1311 // interceptor's holder has been compiled before (see a caller
1312 // of this method.)
1313 CompileCallLoadPropertyWithInterceptor(masm(),
1314 receiver,
1315 holder_reg,
1316 name_reg,
1317 interceptor_holder);
1318
1319 // Check if interceptor provided a value for property. If it's
1320 // the case, return immediately.
1321 Label interceptor_failed;
1322 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1323 __ cmp(r0, scratch1);
1324 __ b(eq, &interceptor_failed);
1325 __ LeaveInternalFrame();
1326 __ Ret();
1327
1328 __ bind(&interceptor_failed);
1329 __ pop(name_reg);
1330 __ pop(holder_reg);
1331 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1332 __ pop(receiver);
1333 }
1334
1335 __ LeaveInternalFrame();
1336
1337 // Check that the maps from interceptor's holder to lookup's holder
1338 // haven't changed. And load lookup's holder into |holder| register.
1339 if (interceptor_holder != lookup->holder()) {
1340 holder_reg = CheckPrototypes(interceptor_holder,
1341 holder_reg,
1342 lookup->holder(),
1343 scratch1,
1344 scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001345 scratch3,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001346 name,
1347 miss);
1348 }
1349
1350 if (lookup->type() == FIELD) {
1351 // We found FIELD property in prototype chain of interceptor's holder.
1352 // Retrieve a field from field's holder.
1353 GenerateFastPropertyLoad(masm(), r0, holder_reg,
1354 lookup->holder(), lookup->GetFieldIndex());
1355 __ Ret();
1356 } else {
1357 // We found CALLBACKS property in prototype chain of interceptor's
1358 // holder.
1359 ASSERT(lookup->type() == CALLBACKS);
1360 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
1361 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1362 ASSERT(callback != NULL);
1363 ASSERT(callback->getter() != NULL);
1364
1365 // Tail call to runtime.
1366 // Important invariant in CALLBACKS case: the code above must be
1367 // structured to never clobber |receiver| register.
1368 __ Move(scratch2, Handle<AccessorInfo>(callback));
1369 // holder_reg is either receiver or scratch1.
1370 if (!receiver.is(holder_reg)) {
1371 ASSERT(scratch1.is(holder_reg));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001372 __ Push(receiver, holder_reg);
1373 __ ldr(scratch3,
1374 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1375 __ Push(scratch3, scratch2, name_reg);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001376 } else {
1377 __ push(receiver);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001378 __ ldr(scratch3,
1379 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1380 __ Push(holder_reg, scratch3, scratch2, name_reg);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001381 }
1382
1383 ExternalReference ref =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001384 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1385 masm()->isolate());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001386 __ TailCallExternalReference(ref, 5, 1);
1387 }
1388 } else { // !compile_followup_inline
1389 // Call the runtime system to load the interceptor.
1390 // Check that the maps haven't changed.
1391 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001392 scratch1, scratch2, scratch3,
1393 name, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001394 PushInterceptorArguments(masm(), receiver, holder_reg,
1395 name_reg, interceptor_holder);
1396
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001397 ExternalReference ref =
1398 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
1399 masm()->isolate());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001400 __ TailCallExternalReference(ref, 5, 1);
1401 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001402}
1403
1404
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001405void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
1406 if (kind_ == Code::KEYED_CALL_IC) {
1407 __ cmp(r2, Operand(Handle<String>(name)));
1408 __ b(ne, miss);
1409 }
1410}
1411
1412
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001413void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
1414 JSObject* holder,
1415 String* name,
1416 Label* miss) {
1417 ASSERT(holder->IsGlobalObject());
1418
1419 // Get the number of arguments.
1420 const int argc = arguments().immediate();
1421
1422 // Get the receiver from the stack.
1423 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1424
1425 // If the object is the holder then we know that it's a global
1426 // object which can only happen for contextual calls. In this case,
1427 // the receiver cannot be a smi.
1428 if (object != holder) {
1429 __ tst(r0, Operand(kSmiTagMask));
1430 __ b(eq, miss);
1431 }
1432
1433 // Check that the maps haven't changed.
1434 CheckPrototypes(object, r0, holder, r3, r1, r4, name, miss);
1435}
1436
1437
1438void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
1439 JSFunction* function,
1440 Label* miss) {
1441 // Get the value from the cell.
1442 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1443 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1444
1445 // Check that the cell contains the same function.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001446 if (heap()->InNewSpace(function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001447 // We can't embed a pointer to a function in new space so we have
1448 // to verify that the shared function info is unchanged. This has
1449 // the nice side effect that multiple closures based on the same
1450 // function can all use this call IC. Before we load through the
1451 // function, we have to verify that it still is a function.
1452 __ tst(r1, Operand(kSmiTagMask));
1453 __ b(eq, miss);
1454 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1455 __ b(ne, miss);
1456
1457 // Check the shared function info. Make sure it hasn't changed.
1458 __ Move(r3, Handle<SharedFunctionInfo>(function->shared()));
1459 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1460 __ cmp(r4, r3);
1461 __ b(ne, miss);
1462 } else {
1463 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1464 __ b(ne, miss);
1465 }
1466}
1467
1468
lrn@chromium.org303ada72010-10-27 09:33:13 +00001469MaybeObject* CallStubCompiler::GenerateMissBranch() {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001470 MaybeObject* maybe_obj =
1471 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1472 kind_,
1473 extra_ic_state_);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001474 Object* obj;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001475 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001476 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1477 return obj;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001478}
1479
1480
lrn@chromium.org303ada72010-10-27 09:33:13 +00001481MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
1482 JSObject* holder,
1483 int index,
1484 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001486 // -- r2 : name
1487 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001488 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489 Label miss;
1490
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001491 GenerateNameCheck(name, &miss);
1492
mads.s.ager31e71382008-08-13 09:32:07 +00001493 const int argc = arguments().immediate();
1494
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001495 // Get the receiver of the function from the stack into r0.
1496 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497 // Check that the receiver isn't a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001498 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001499 __ b(eq, &miss);
1500
1501 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001502 Register reg = CheckPrototypes(object, r0, holder, r1, r3, r4, name, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001503 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001505 GenerateCallFunction(masm(), object, arguments(), &miss, extra_ic_state_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001506
1507 // Handle call cache miss.
1508 __ bind(&miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001509 MaybeObject* maybe_result = GenerateMissBranch();
1510 if (maybe_result->IsFailure()) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001511
1512 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001513 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514}
1515
1516
lrn@chromium.org303ada72010-10-27 09:33:13 +00001517MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
1518 JSObject* holder,
1519 JSGlobalPropertyCell* cell,
1520 JSFunction* function,
1521 String* name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001522 // ----------- S t a t e -------------
1523 // -- r2 : name
1524 // -- lr : return address
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001525 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1526 // -- ...
1527 // -- sp[argc * 4] : receiver
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001528 // -----------------------------------
1529
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001530 // If object is not an array, bail out to regular call.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001531 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001532
1533 Label miss;
1534
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001535 GenerateNameCheck(name, &miss);
1536
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001537 Register receiver = r1;
1538
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001539 // Get the receiver from the stack
1540 const int argc = arguments().immediate();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001541 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001542
1543 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001544 __ JumpIfSmi(receiver, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001545
1546 // Check that the maps haven't changed.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001547 CheckPrototypes(JSObject::cast(object), receiver,
1548 holder, r3, r0, r4, name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001549
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001550 if (argc == 0) {
1551 // Nothing to do, just return the length.
1552 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1553 __ Drop(argc + 1);
1554 __ Ret();
1555 } else {
1556 Label call_builtin;
1557
1558 Register elements = r3;
1559 Register end_elements = r5;
1560
1561 // Get the elements array of the object.
1562 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1563
1564 // Check that the elements are in fast mode and writable.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001565 __ CheckMap(elements,
1566 r0,
1567 Heap::kFixedArrayMapRootIndex,
1568 &call_builtin,
1569 DONT_DO_SMI_CHECK);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001570
1571 if (argc == 1) { // Otherwise fall through to call the builtin.
1572 Label exit, with_write_barrier, attempt_to_grow_elements;
1573
1574 // Get the array's length into r0 and calculate new length.
1575 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1576 STATIC_ASSERT(kSmiTagSize == 1);
1577 STATIC_ASSERT(kSmiTag == 0);
1578 __ add(r0, r0, Operand(Smi::FromInt(argc)));
1579
1580 // Get the element's length.
1581 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
1582
1583 // Check if we could survive without allocation.
1584 __ cmp(r0, r4);
1585 __ b(gt, &attempt_to_grow_elements);
1586
1587 // Save new length.
1588 __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1589
1590 // Push the element.
1591 __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize));
1592 // We may need a register containing the address end_elements below,
1593 // so write back the value in end_elements.
1594 __ add(end_elements, elements,
1595 Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1596 const int kEndElementsOffset =
1597 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
1598 __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex));
1599
1600 // Check for a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001601 __ JumpIfNotSmi(r4, &with_write_barrier);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001602 __ bind(&exit);
1603 __ Drop(argc + 1);
1604 __ Ret();
1605
1606 __ bind(&with_write_barrier);
1607 __ InNewSpace(elements, r4, eq, &exit);
1608 __ RecordWriteHelper(elements, end_elements, r4);
1609 __ Drop(argc + 1);
1610 __ Ret();
1611
1612 __ bind(&attempt_to_grow_elements);
1613 // r0: array's length + 1.
1614 // r4: elements' length.
1615
1616 if (!FLAG_inline_new) {
1617 __ b(&call_builtin);
1618 }
1619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 Isolate* isolate = masm()->isolate();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001621 ExternalReference new_space_allocation_top =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001622 ExternalReference::new_space_allocation_top_address(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001623 ExternalReference new_space_allocation_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624 ExternalReference::new_space_allocation_limit_address(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001625
1626 const int kAllocationDelta = 4;
1627 // Load top and check if it is the end of elements.
1628 __ add(end_elements, elements,
1629 Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1630 __ add(end_elements, end_elements, Operand(kEndElementsOffset));
1631 __ mov(r7, Operand(new_space_allocation_top));
1632 __ ldr(r6, MemOperand(r7));
1633 __ cmp(end_elements, r6);
1634 __ b(ne, &call_builtin);
1635
1636 __ mov(r9, Operand(new_space_allocation_limit));
1637 __ ldr(r9, MemOperand(r9));
1638 __ add(r6, r6, Operand(kAllocationDelta * kPointerSize));
1639 __ cmp(r6, r9);
1640 __ b(hi, &call_builtin);
1641
1642 // We fit and could grow elements.
1643 // Update new_space_allocation_top.
1644 __ str(r6, MemOperand(r7));
1645 // Push the argument.
1646 __ ldr(r6, MemOperand(sp, (argc - 1) * kPointerSize));
1647 __ str(r6, MemOperand(end_elements));
1648 // Fill the rest with holes.
1649 __ LoadRoot(r6, Heap::kTheHoleValueRootIndex);
1650 for (int i = 1; i < kAllocationDelta; i++) {
1651 __ str(r6, MemOperand(end_elements, i * kPointerSize));
1652 }
1653
1654 // Update elements' and array's sizes.
1655 __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1656 __ add(r4, r4, Operand(Smi::FromInt(kAllocationDelta)));
1657 __ str(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
1658
1659 // Elements are in new space, so write barrier is not required.
1660 __ Drop(argc + 1);
1661 __ Ret();
1662 }
1663 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001664 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1665 masm()->isolate()),
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001666 argc + 1,
1667 1);
1668 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001669
1670 // Handle call cache miss.
1671 __ bind(&miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001672 MaybeObject* maybe_result = GenerateMissBranch();
1673 if (maybe_result->IsFailure()) return maybe_result;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001674
1675 // Return the generated code.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001676 return GetCode(function);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001677}
1678
1679
lrn@chromium.org303ada72010-10-27 09:33:13 +00001680MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
1681 JSObject* holder,
1682 JSGlobalPropertyCell* cell,
1683 JSFunction* function,
1684 String* name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001685 // ----------- S t a t e -------------
1686 // -- r2 : name
1687 // -- lr : return address
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001688 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1689 // -- ...
1690 // -- sp[argc * 4] : receiver
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001691 // -----------------------------------
1692
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001693 // If object is not an array, bail out to regular call.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001694 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001695
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001696 Label miss, return_undefined, call_builtin;
1697
1698 Register receiver = r1;
1699 Register elements = r3;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001700
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001701 GenerateNameCheck(name, &miss);
1702
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001703 // Get the receiver from the stack
1704 const int argc = arguments().immediate();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001705 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001706
1707 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001708 __ JumpIfSmi(receiver, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001709
1710 // Check that the maps haven't changed.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001711 CheckPrototypes(JSObject::cast(object),
1712 receiver, holder, elements, r4, r0, name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001713
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001714 // Get the elements array of the object.
1715 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1716
1717 // Check that the elements are in fast mode and writable.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001718 __ CheckMap(elements,
1719 r0,
1720 Heap::kFixedArrayMapRootIndex,
1721 &call_builtin,
1722 DONT_DO_SMI_CHECK);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001723
1724 // Get the array's length into r4 and calculate new length.
1725 __ ldr(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
1726 __ sub(r4, r4, Operand(Smi::FromInt(1)), SetCC);
1727 __ b(lt, &return_undefined);
1728
1729 // Get the last element.
1730 __ LoadRoot(r6, Heap::kTheHoleValueRootIndex);
1731 STATIC_ASSERT(kSmiTagSize == 1);
1732 STATIC_ASSERT(kSmiTag == 0);
1733 // We can't address the last element in one operation. Compute the more
1734 // expensive shift first, and use an offset later on.
1735 __ add(elements, elements, Operand(r4, LSL, kPointerSizeLog2 - kSmiTagSize));
1736 __ ldr(r0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1737 __ cmp(r0, r6);
1738 __ b(eq, &call_builtin);
1739
1740 // Set the array's length.
1741 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
1742
1743 // Fill with the hole.
1744 __ str(r6, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1745 __ Drop(argc + 1);
1746 __ Ret();
1747
1748 __ bind(&return_undefined);
1749 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1750 __ Drop(argc + 1);
1751 __ Ret();
1752
1753 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1755 masm()->isolate()),
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001756 argc + 1,
1757 1);
1758
1759 // Handle call cache miss.
1760 __ bind(&miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 MaybeObject* maybe_result = GenerateMissBranch();
1762 if (maybe_result->IsFailure()) return maybe_result;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001763
1764 // Return the generated code.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001765 return GetCode(function);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001766}
1767
1768
lrn@chromium.org303ada72010-10-27 09:33:13 +00001769MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001770 Object* object,
1771 JSObject* holder,
1772 JSGlobalPropertyCell* cell,
1773 JSFunction* function,
1774 String* name) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001775 // ----------- S t a t e -------------
1776 // -- r2 : function name
1777 // -- lr : return address
1778 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1779 // -- ...
1780 // -- sp[argc * 4] : receiver
1781 // -----------------------------------
1782
1783 // If object is not a string, bail out to regular call.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001784 if (!object->IsString() || cell != NULL) return heap()->undefined_value();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001785
1786 const int argc = arguments().immediate();
1787
1788 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001789 Label name_miss;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001790 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001791 Label* index_out_of_range_label = &index_out_of_range;
1792
danno@chromium.org40cb8782011-05-25 07:58:50 +00001793 if (kind_ == Code::CALL_IC &&
1794 (CallICBase::StringStubState::decode(extra_ic_state_) ==
1795 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001796 index_out_of_range_label = &miss;
1797 }
1798
1799 GenerateNameCheck(name, &name_miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001800
1801 // Check that the maps starting from the prototype haven't changed.
1802 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1803 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001804 r0,
1805 &miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001806 ASSERT(object != holder);
1807 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder,
1808 r1, r3, r4, name, &miss);
1809
1810 Register receiver = r1;
1811 Register index = r4;
1812 Register scratch = r3;
1813 Register result = r0;
1814 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
1815 if (argc > 0) {
1816 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
1817 } else {
1818 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1819 }
1820
1821 StringCharCodeAtGenerator char_code_at_generator(receiver,
1822 index,
1823 scratch,
1824 result,
1825 &miss, // When not a string.
1826 &miss, // When not a number.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001827 index_out_of_range_label,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001828 STRING_INDEX_IS_NUMBER);
1829 char_code_at_generator.GenerateFast(masm());
1830 __ Drop(argc + 1);
1831 __ Ret();
1832
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001833 StubRuntimeCallHelper call_helper;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001834 char_code_at_generator.GenerateSlow(masm(), call_helper);
1835
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001836 if (index_out_of_range.is_linked()) {
1837 __ bind(&index_out_of_range);
1838 __ LoadRoot(r0, Heap::kNanValueRootIndex);
1839 __ Drop(argc + 1);
1840 __ Ret();
1841 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001842
1843 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001844 // Restore function name in r2.
1845 __ Move(r2, Handle<String>(name));
1846 __ bind(&name_miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001847 MaybeObject* maybe_result = GenerateMissBranch();
1848 if (maybe_result->IsFailure()) return maybe_result;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001849
1850 // Return the generated code.
1851 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001852}
1853
1854
lrn@chromium.org303ada72010-10-27 09:33:13 +00001855MaybeObject* CallStubCompiler::CompileStringCharAtCall(
1856 Object* object,
1857 JSObject* holder,
1858 JSGlobalPropertyCell* cell,
1859 JSFunction* function,
1860 String* name) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001861 // ----------- S t a t e -------------
1862 // -- r2 : function name
1863 // -- lr : return address
1864 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1865 // -- ...
1866 // -- sp[argc * 4] : receiver
1867 // -----------------------------------
1868
1869 // If object is not a string, bail out to regular call.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001870 if (!object->IsString() || cell != NULL) return heap()->undefined_value();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001871
1872 const int argc = arguments().immediate();
1873
1874 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001875 Label name_miss;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001876 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001877 Label* index_out_of_range_label = &index_out_of_range;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001878
danno@chromium.org40cb8782011-05-25 07:58:50 +00001879 if (kind_ == Code::CALL_IC &&
1880 (CallICBase::StringStubState::decode(extra_ic_state_) ==
1881 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001882 index_out_of_range_label = &miss;
1883 }
1884
1885 GenerateNameCheck(name, &name_miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001886
1887 // Check that the maps starting from the prototype haven't changed.
1888 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1889 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001890 r0,
1891 &miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001892 ASSERT(object != holder);
1893 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder,
1894 r1, r3, r4, name, &miss);
1895
1896 Register receiver = r0;
1897 Register index = r4;
1898 Register scratch1 = r1;
1899 Register scratch2 = r3;
1900 Register result = r0;
1901 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
1902 if (argc > 0) {
1903 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
1904 } else {
1905 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1906 }
1907
1908 StringCharAtGenerator char_at_generator(receiver,
1909 index,
1910 scratch1,
1911 scratch2,
1912 result,
1913 &miss, // When not a string.
1914 &miss, // When not a number.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001915 index_out_of_range_label,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001916 STRING_INDEX_IS_NUMBER);
1917 char_at_generator.GenerateFast(masm());
1918 __ Drop(argc + 1);
1919 __ Ret();
1920
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001921 StubRuntimeCallHelper call_helper;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001922 char_at_generator.GenerateSlow(masm(), call_helper);
1923
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001924 if (index_out_of_range.is_linked()) {
1925 __ bind(&index_out_of_range);
1926 __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
1927 __ Drop(argc + 1);
1928 __ Ret();
1929 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001930
1931 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001932 // Restore function name in r2.
1933 __ Move(r2, Handle<String>(name));
1934 __ bind(&name_miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001935 MaybeObject* maybe_result = GenerateMissBranch();
1936 if (maybe_result->IsFailure()) return maybe_result;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001937
1938 // Return the generated code.
1939 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001940}
1941
1942
lrn@chromium.org303ada72010-10-27 09:33:13 +00001943MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001944 Object* object,
1945 JSObject* holder,
1946 JSGlobalPropertyCell* cell,
1947 JSFunction* function,
1948 String* name) {
1949 // ----------- S t a t e -------------
1950 // -- r2 : function name
1951 // -- lr : return address
1952 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1953 // -- ...
1954 // -- sp[argc * 4] : receiver
1955 // -----------------------------------
1956
1957 const int argc = arguments().immediate();
1958
1959 // If the object is not a JSObject or we got an unexpected number of
1960 // arguments, bail out to the regular call.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001961 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001962
1963 Label miss;
1964 GenerateNameCheck(name, &miss);
1965
1966 if (cell == NULL) {
1967 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
1968
1969 STATIC_ASSERT(kSmiTag == 0);
1970 __ tst(r1, Operand(kSmiTagMask));
1971 __ b(eq, &miss);
1972
1973 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
1974 &miss);
1975 } else {
1976 ASSERT(cell->value() == function);
1977 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
1978 GenerateLoadFunctionFromCell(cell, function, &miss);
1979 }
1980
1981 // Load the char code argument.
1982 Register code = r1;
1983 __ ldr(code, MemOperand(sp, 0 * kPointerSize));
1984
1985 // Check the code is a smi.
1986 Label slow;
1987 STATIC_ASSERT(kSmiTag == 0);
1988 __ tst(code, Operand(kSmiTagMask));
1989 __ b(ne, &slow);
1990
1991 // Convert the smi code to uint16.
1992 __ and_(code, code, Operand(Smi::FromInt(0xffff)));
1993
1994 StringCharFromCodeGenerator char_from_code_generator(code, r0);
1995 char_from_code_generator.GenerateFast(masm());
1996 __ Drop(argc + 1);
1997 __ Ret();
1998
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001999 StubRuntimeCallHelper call_helper;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002000 char_from_code_generator.GenerateSlow(masm(), call_helper);
2001
2002 // Tail call the full function. We do not have to patch the receiver
2003 // because the function makes no use of it.
2004 __ bind(&slow);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002005 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002006
2007 __ bind(&miss);
2008 // r2: function name.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002009 MaybeObject* maybe_result = GenerateMissBranch();
2010 if (maybe_result->IsFailure()) return maybe_result;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002011
2012 // Return the generated code.
2013 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
2014}
2015
2016
lrn@chromium.org303ada72010-10-27 09:33:13 +00002017MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
2018 JSObject* holder,
2019 JSGlobalPropertyCell* cell,
2020 JSFunction* function,
2021 String* name) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002022 // ----------- S t a t e -------------
2023 // -- r2 : function name
2024 // -- lr : return address
2025 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2026 // -- ...
2027 // -- sp[argc * 4] : receiver
2028 // -----------------------------------
2029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002030 if (!CpuFeatures::IsSupported(VFP3)) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002031 return heap()->undefined_value();
2032 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002033
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002034 CpuFeatures::Scope scope_vfp3(VFP3);
2035
2036 const int argc = arguments().immediate();
2037
2038 // If the object is not a JSObject or we got an unexpected number of
2039 // arguments, bail out to the regular call.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002040 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002041
2042 Label miss, slow;
2043 GenerateNameCheck(name, &miss);
2044
2045 if (cell == NULL) {
2046 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
2047
2048 STATIC_ASSERT(kSmiTag == 0);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002049 __ JumpIfSmi(r1, &miss);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002050
2051 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
2052 &miss);
2053 } else {
2054 ASSERT(cell->value() == function);
2055 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
2056 GenerateLoadFunctionFromCell(cell, function, &miss);
2057 }
2058
2059 // Load the (only) argument into r0.
2060 __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
2061
2062 // If the argument is a smi, just return.
2063 STATIC_ASSERT(kSmiTag == 0);
2064 __ tst(r0, Operand(kSmiTagMask));
2065 __ Drop(argc + 1, eq);
2066 __ Ret(eq);
2067
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002068 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002069
2070 Label wont_fit_smi, no_vfp_exception, restore_fpscr_and_return;
2071
2072 // If vfp3 is enabled, we use the fpu rounding with the RM (round towards
2073 // minus infinity) mode.
2074
2075 // Load the HeapNumber value.
2076 // We will need access to the value in the core registers, so we load it
2077 // with ldrd and move it to the fpu. It also spares a sub instruction for
2078 // updating the HeapNumber value address, as vldr expects a multiple
2079 // of 4 offset.
2080 __ Ldrd(r4, r5, FieldMemOperand(r0, HeapNumber::kValueOffset));
2081 __ vmov(d1, r4, r5);
2082
2083 // Backup FPSCR.
2084 __ vmrs(r3);
2085 // Set custom FPCSR:
2086 // - Set rounding mode to "Round towards Minus Infinity"
2087 // (ie bits [23:22] = 0b10).
2088 // - Clear vfp cumulative exception flags (bits [3:0]).
2089 // - Make sure Flush-to-zero mode control bit is unset (bit 22).
2090 __ bic(r9, r3,
2091 Operand(kVFPExceptionMask | kVFPRoundingModeMask | kVFPFlushToZeroMask));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002092 __ orr(r9, r9, Operand(kRoundToMinusInf));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002093 __ vmsr(r9);
2094
2095 // Convert the argument to an integer.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002096 __ vcvt_s32_f64(s0, d1, kFPSCRRounding);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002097
2098 // Use vcvt latency to start checking for special cases.
2099 // Get the argument exponent and clear the sign bit.
2100 __ bic(r6, r5, Operand(HeapNumber::kSignMask));
2101 __ mov(r6, Operand(r6, LSR, HeapNumber::kMantissaBitsInTopWord));
2102
2103 // Retrieve FPSCR and check for vfp exceptions.
2104 __ vmrs(r9);
2105 __ tst(r9, Operand(kVFPExceptionMask));
2106 __ b(&no_vfp_exception, eq);
2107
2108 // Check for NaN, Infinity, and -Infinity.
2109 // They are invariant through a Math.Floor call, so just
2110 // return the original argument.
2111 __ sub(r7, r6, Operand(HeapNumber::kExponentMask
2112 >> HeapNumber::kMantissaBitsInTopWord), SetCC);
2113 __ b(&restore_fpscr_and_return, eq);
2114 // We had an overflow or underflow in the conversion. Check if we
2115 // have a big exponent.
2116 __ cmp(r7, Operand(HeapNumber::kMantissaBits));
2117 // If greater or equal, the argument is already round and in r0.
2118 __ b(&restore_fpscr_and_return, ge);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002119 __ b(&wont_fit_smi);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002120
2121 __ bind(&no_vfp_exception);
2122 // Move the result back to general purpose register r0.
2123 __ vmov(r0, s0);
2124 // Check if the result fits into a smi.
2125 __ add(r1, r0, Operand(0x40000000), SetCC);
2126 __ b(&wont_fit_smi, mi);
2127 // Tag the result.
2128 STATIC_ASSERT(kSmiTag == 0);
2129 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
2130
2131 // Check for -0.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002132 __ cmp(r0, Operand(0, RelocInfo::NONE));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002133 __ b(&restore_fpscr_and_return, ne);
2134 // r5 already holds the HeapNumber exponent.
2135 __ tst(r5, Operand(HeapNumber::kSignMask));
2136 // If our HeapNumber is negative it was -0, so load its address and return.
2137 // Else r0 is loaded with 0, so we can also just return.
2138 __ ldr(r0, MemOperand(sp, 0 * kPointerSize), ne);
2139
2140 __ bind(&restore_fpscr_and_return);
2141 // Restore FPSCR and return.
2142 __ vmsr(r3);
2143 __ Drop(argc + 1);
2144 __ Ret();
2145
2146 __ bind(&wont_fit_smi);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002147 // Restore FPCSR and fall to slow case.
2148 __ vmsr(r3);
2149
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002150 __ bind(&slow);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002151 // Tail call the full function. We do not have to patch the receiver
2152 // because the function makes no use of it.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002153 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002154
2155 __ bind(&miss);
2156 // r2: function name.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002157 MaybeObject* maybe_result = GenerateMissBranch();
2158 if (maybe_result->IsFailure()) return maybe_result;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002159
2160 // Return the generated code.
2161 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002162}
2163
2164
lrn@chromium.org303ada72010-10-27 09:33:13 +00002165MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
2166 JSObject* holder,
2167 JSGlobalPropertyCell* cell,
2168 JSFunction* function,
2169 String* name) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002170 // ----------- S t a t e -------------
2171 // -- r2 : function name
2172 // -- lr : return address
2173 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2174 // -- ...
2175 // -- sp[argc * 4] : receiver
2176 // -----------------------------------
2177
2178 const int argc = arguments().immediate();
2179
2180 // If the object is not a JSObject or we got an unexpected number of
2181 // arguments, bail out to the regular call.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002182 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002183
2184 Label miss;
2185 GenerateNameCheck(name, &miss);
2186
2187 if (cell == NULL) {
2188 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
2189
2190 STATIC_ASSERT(kSmiTag == 0);
2191 __ tst(r1, Operand(kSmiTagMask));
2192 __ b(eq, &miss);
2193
2194 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
2195 &miss);
2196 } else {
2197 ASSERT(cell->value() == function);
2198 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
2199 GenerateLoadFunctionFromCell(cell, function, &miss);
2200 }
2201
2202 // Load the (only) argument into r0.
2203 __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
2204
2205 // Check if the argument is a smi.
2206 Label not_smi;
2207 STATIC_ASSERT(kSmiTag == 0);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002208 __ JumpIfNotSmi(r0, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002209
2210 // Do bitwise not or do nothing depending on the sign of the
2211 // argument.
2212 __ eor(r1, r0, Operand(r0, ASR, kBitsPerInt - 1));
2213
2214 // Add 1 or do nothing depending on the sign of the argument.
2215 __ sub(r0, r1, Operand(r0, ASR, kBitsPerInt - 1), SetCC);
2216
2217 // If the result is still negative, go to the slow case.
2218 // This only happens for the most negative smi.
2219 Label slow;
2220 __ b(mi, &slow);
2221
2222 // Smi case done.
2223 __ Drop(argc + 1);
2224 __ Ret();
2225
2226 // Check if the argument is a heap number and load its exponent and
2227 // sign.
2228 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002229 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002230 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset));
2231
2232 // Check the sign of the argument. If the argument is positive,
2233 // just return it.
2234 Label negative_sign;
2235 __ tst(r1, Operand(HeapNumber::kSignMask));
2236 __ b(ne, &negative_sign);
2237 __ Drop(argc + 1);
2238 __ Ret();
2239
2240 // If the argument is negative, clear the sign, and return a new
2241 // number.
2242 __ bind(&negative_sign);
2243 __ eor(r1, r1, Operand(HeapNumber::kSignMask));
2244 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
2245 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
2246 __ AllocateHeapNumber(r0, r4, r5, r6, &slow);
2247 __ str(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset));
2248 __ str(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
2249 __ Drop(argc + 1);
2250 __ Ret();
2251
2252 // Tail call the full function. We do not have to patch the receiver
2253 // because the function makes no use of it.
2254 __ bind(&slow);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002255 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002256
2257 __ bind(&miss);
2258 // r2: function name.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002259 MaybeObject* maybe_result = GenerateMissBranch();
2260 if (maybe_result->IsFailure()) return maybe_result;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002261
2262 // Return the generated code.
2263 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
2264}
2265
2266
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002267MaybeObject* CallStubCompiler::CompileFastApiCall(
2268 const CallOptimization& optimization,
2269 Object* object,
2270 JSObject* holder,
2271 JSGlobalPropertyCell* cell,
2272 JSFunction* function,
2273 String* name) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002274 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002275
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002276 ASSERT(optimization.is_simple_api_call());
2277 // Bail out if object is a global object as we don't want to
2278 // repatch it to global receiver.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002279 if (object->IsGlobalObject()) return heap()->undefined_value();
2280 if (cell != NULL) return heap()->undefined_value();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002281 if (!object->IsJSObject()) return heap()->undefined_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002282 int depth = optimization.GetPrototypeDepthOfExpectedType(
2283 JSObject::cast(object), holder);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002284 if (depth == kInvalidProtoDepth) return heap()->undefined_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002285
2286 Label miss, miss_before_stack_reserved;
2287
2288 GenerateNameCheck(name, &miss_before_stack_reserved);
2289
2290 // Get the receiver from the stack.
2291 const int argc = arguments().immediate();
2292 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
2293
2294 // Check that the receiver isn't a smi.
2295 __ tst(r1, Operand(kSmiTagMask));
2296 __ b(eq, &miss_before_stack_reserved);
2297
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002298 __ IncrementCounter(counters->call_const(), 1, r0, r3);
2299 __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002300
2301 ReserveSpaceForFastApiCall(masm(), r0);
2302
2303 // Check that the maps haven't changed and find a Holder as a side effect.
2304 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
2305 depth, &miss);
2306
2307 MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
2308 if (result->IsFailure()) return result;
2309
2310 __ bind(&miss);
2311 FreeSpaceForFastApiCall(masm());
2312
2313 __ bind(&miss_before_stack_reserved);
2314 MaybeObject* maybe_result = GenerateMissBranch();
2315 if (maybe_result->IsFailure()) return maybe_result;
2316
2317 // Return the generated code.
2318 return GetCode(function);
2319}
2320
2321
lrn@chromium.org303ada72010-10-27 09:33:13 +00002322MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
2323 JSObject* holder,
2324 JSFunction* function,
2325 String* name,
2326 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002327 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002328 // -- r2 : name
2329 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002330 // -----------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002331 if (HasCustomCallGenerator(function)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002332 MaybeObject* maybe_result = CompileCustomCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002333 object, holder, NULL, function, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002334 Object* result;
2335 if (!maybe_result->ToObject(&result)) return maybe_result;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002336 // undefined means bail out to regular compiler.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002337 if (!result->IsUndefined()) return result;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002338 }
2339
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002340 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002342 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002343
mads.s.ager31e71382008-08-13 09:32:07 +00002344 // Get the receiver from the stack
2345 const int argc = arguments().immediate();
2346 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
2347
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002348 // Check that the receiver isn't a smi.
2349 if (check != NUMBER_CHECK) {
2350 __ tst(r1, Operand(kSmiTagMask));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002351 __ b(eq, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002352 }
2353
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002354 // Make sure that it's okay not to patch the on stack receiver
2355 // unless we're doing a receiver map check.
2356 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2357
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002358 SharedFunctionInfo* function_info = function->shared();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002359 switch (check) {
2360 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002361 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2362 1, r0, r3);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002363
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002364 // Check that the maps haven't changed.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002365 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002366 &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002367
2368 // Patch the receiver on the stack with the global proxy if
2369 // necessary.
2370 if (object->IsGlobalObject()) {
2371 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
2372 __ str(r3, MemOperand(sp, argc * kPointerSize));
2373 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002374 break;
2375
2376 case STRING_CHECK:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002377 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2378 // Calling non-strict non-builtins with a value as the receiver
2379 // requires boxing.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002380 __ jmp(&miss);
2381 } else {
2382 // Check that the object is a two-byte string or a symbol.
ager@chromium.org5c838252010-02-19 08:53:10 +00002383 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002384 __ b(ge, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002385 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002386 GenerateDirectLoadGlobalFunctionPrototype(
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002387 masm(), Context::STRING_FUNCTION_INDEX, r0, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00002388 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002389 r1, r4, name, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002390 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002391 break;
2392
2393 case NUMBER_CHECK: {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002394 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2395 // Calling non-strict non-builtins with a value as the receiver
2396 // requires boxing.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002397 __ jmp(&miss);
2398 } else {
2399 Label fast;
2400 // Check that the object is a smi or a heap number.
2401 __ tst(r1, Operand(kSmiTagMask));
2402 __ b(eq, &fast);
ager@chromium.org5c838252010-02-19 08:53:10 +00002403 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002404 __ b(ne, &miss);
2405 __ bind(&fast);
2406 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002407 GenerateDirectLoadGlobalFunctionPrototype(
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002408 masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00002409 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002410 r1, r4, name, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002411 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002412 break;
2413 }
2414
2415 case BOOLEAN_CHECK: {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002416 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2417 // Calling non-strict non-builtins with a value as the receiver
2418 // requires boxing.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002419 __ jmp(&miss);
2420 } else {
2421 Label fast;
2422 // Check that the object is a boolean.
2423 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
2424 __ cmp(r1, ip);
2425 __ b(eq, &fast);
2426 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
2427 __ cmp(r1, ip);
2428 __ b(ne, &miss);
2429 __ bind(&fast);
2430 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002431 GenerateDirectLoadGlobalFunctionPrototype(
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002432 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00002433 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002434 r1, r4, name, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002435 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002436 break;
2437 }
2438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002439 default:
2440 UNREACHABLE();
2441 }
2442
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002443 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
2444 ? CALL_AS_FUNCTION
2445 : CALL_AS_METHOD;
2446 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002447
2448 // Handle call cache miss.
2449 __ bind(&miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002450 MaybeObject* maybe_result = GenerateMissBranch();
2451 if (maybe_result->IsFailure()) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002452
2453 // Return the generated code.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002454 return GetCode(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002455}
2456
2457
lrn@chromium.org303ada72010-10-27 09:33:13 +00002458MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
2459 JSObject* holder,
2460 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002461 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002462 // -- r2 : name
2463 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002464 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002465
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002466 Label miss;
ager@chromium.org5c838252010-02-19 08:53:10 +00002467
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002468 GenerateNameCheck(name, &miss);
2469
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002470 // Get the number of arguments.
2471 const int argc = arguments().immediate();
2472
2473 LookupResult lookup;
2474 LookupPostInterceptor(holder, name, &lookup);
2475
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002476 // Get the receiver from the stack.
2477 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002478
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002479 CallInterceptorCompiler compiler(this, arguments(), r2, extra_ic_state_);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002480 MaybeObject* result = compiler.Compile(masm(),
2481 object,
2482 holder,
2483 name,
2484 &lookup,
2485 r1,
2486 r3,
2487 r4,
2488 r0,
2489 &miss);
2490 if (result->IsFailure()) {
2491 return result;
2492 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002493
2494 // Move returned value, the function to call, to r1.
2495 __ mov(r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002496 // Restore receiver.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002497 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002498
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002499 GenerateCallFunction(masm(), object, arguments(), &miss, extra_ic_state_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002500
2501 // Handle call cache miss.
2502 __ bind(&miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002503 MaybeObject* maybe_result = GenerateMissBranch();
2504 if (maybe_result->IsFailure()) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002505
2506 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002507 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002508}
2509
2510
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002511MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
2512 GlobalObject* holder,
2513 JSGlobalPropertyCell* cell,
2514 JSFunction* function,
2515 String* name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002516 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002517 // -- r2 : name
2518 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002519 // -----------------------------------
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002520
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002521 if (HasCustomCallGenerator(function)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002522 MaybeObject* maybe_result = CompileCustomCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002523 object, holder, cell, function, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002524 Object* result;
2525 if (!maybe_result->ToObject(&result)) return maybe_result;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002526 // undefined means bail out to regular compiler.
2527 if (!result->IsUndefined()) return result;
2528 }
2529
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002530 Label miss;
2531
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002532 GenerateNameCheck(name, &miss);
2533
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002534 // Get the number of arguments.
2535 const int argc = arguments().immediate();
2536
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002537 GenerateGlobalReceiverCheck(object, holder, name, &miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002538
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002539 GenerateLoadFunctionFromCell(cell, function, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002540
2541 // Patch the receiver on the stack with the global proxy if
2542 // necessary.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002543 if (object->IsGlobalObject()) {
2544 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
2545 __ str(r3, MemOperand(sp, argc * kPointerSize));
2546 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002547
2548 // Setup the context (function already in r1).
2549 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
2550
2551 // Jump to the cached code (tail call).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002552 Counters* counters = masm()->isolate()->counters();
2553 __ IncrementCounter(counters->call_global_inline(), 1, r3, r4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002554 ASSERT(function->is_compiled());
2555 Handle<Code> code(function->code());
2556 ParameterCount expected(function->shared()->formal_parameter_count());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002557 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002558 ? CALL_AS_FUNCTION
2559 : CALL_AS_METHOD;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002560 if (V8::UseCrankshaft()) {
2561 // TODO(kasperl): For now, we always call indirectly through the
2562 // code field in the function to allow recompilation to take effect
2563 // without changing any of the call sites.
2564 __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002565 __ InvokeCode(r3, expected, arguments(), JUMP_FUNCTION,
2566 NullCallWrapper(), call_kind);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002567 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002568 __ InvokeCode(code, expected, arguments(), RelocInfo::CODE_TARGET,
2569 JUMP_FUNCTION, call_kind);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002570 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002571
2572 // Handle call cache miss.
2573 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002574 __ IncrementCounter(counters->call_global_inline_miss(), 1, r1, r3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002575 MaybeObject* maybe_result = GenerateMissBranch();
2576 if (maybe_result->IsFailure()) return maybe_result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002577
2578 // Return the generated code.
2579 return GetCode(NORMAL, name);
2580}
2581
2582
lrn@chromium.org303ada72010-10-27 09:33:13 +00002583MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
2584 int index,
2585 Map* transition,
2586 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002587 // ----------- S t a t e -------------
2588 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00002589 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002590 // -- r2 : name
2591 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002592 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002593 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002594
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002595 GenerateStoreField(masm(),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002596 object,
2597 index,
2598 transition,
ager@chromium.org5c838252010-02-19 08:53:10 +00002599 r1, r2, r3,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002600 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002601 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002602 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
ager@chromium.org236ad962008-09-25 09:45:57 +00002603 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002604
2605 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002606 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002607}
2608
2609
lrn@chromium.org303ada72010-10-27 09:33:13 +00002610MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
2611 AccessorInfo* callback,
2612 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002613 // ----------- S t a t e -------------
2614 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00002615 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002616 // -- r2 : name
2617 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002618 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002619 Label miss;
2620
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002621 // Check that the object isn't a smi.
ager@chromium.org5c838252010-02-19 08:53:10 +00002622 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002623 __ b(eq, &miss);
2624
2625 // Check that the map of the object hasn't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00002626 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
2627 __ cmp(r3, Operand(Handle<Map>(object->map())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002628 __ b(ne, &miss);
2629
2630 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002631 if (object->IsJSGlobalProxy()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002632 __ CheckAccessGlobalProxy(r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002633 }
2634
2635 // Stub never generated for non-global objects that require access
2636 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002637 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002638
ager@chromium.org5c838252010-02-19 08:53:10 +00002639 __ push(r1); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002640 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002641 __ Push(ip, r2, r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002642
mads.s.ager31e71382008-08-13 09:32:07 +00002643 // Do tail-call to the runtime system.
2644 ExternalReference store_callback_property =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002645 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2646 masm()->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002647 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002648
2649 // Handle store cache miss.
2650 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002651 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
ager@chromium.org236ad962008-09-25 09:45:57 +00002652 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002653
2654 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002655 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002656}
2657
2658
lrn@chromium.org303ada72010-10-27 09:33:13 +00002659MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
2660 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002661 // ----------- S t a t e -------------
2662 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00002663 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002664 // -- r2 : name
2665 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002666 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002667 Label miss;
2668
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002669 // Check that the object isn't a smi.
ager@chromium.org5c838252010-02-19 08:53:10 +00002670 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002671 __ b(eq, &miss);
2672
2673 // Check that the map of the object hasn't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00002674 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
2675 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002676 __ b(ne, &miss);
2677
2678 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002679 if (receiver->IsJSGlobalProxy()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002680 __ CheckAccessGlobalProxy(r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002681 }
2682
ager@chromium.org5c838252010-02-19 08:53:10 +00002683 // Stub is never generated for non-global objects that require access
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002684 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002685 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002686
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002687 __ Push(r1, r2, r0); // Receiver, name, value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002688
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002689 __ mov(r0, Operand(Smi::FromInt(strict_mode_)));
2690 __ push(r0); // strict mode
2691
mads.s.ager31e71382008-08-13 09:32:07 +00002692 // Do tail-call to the runtime system.
2693 ExternalReference store_ic_property =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002694 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2695 masm()->isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002696 __ TailCallExternalReference(store_ic_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002697
2698 // Handle store cache miss.
2699 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002700 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
ager@chromium.org236ad962008-09-25 09:45:57 +00002701 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002702
2703 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002704 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002705}
2706
2707
lrn@chromium.org303ada72010-10-27 09:33:13 +00002708MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
2709 JSGlobalPropertyCell* cell,
2710 String* name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002711 // ----------- S t a t e -------------
2712 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00002713 // -- r1 : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002714 // -- r2 : name
2715 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002716 // -----------------------------------
2717 Label miss;
2718
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002719 // Check that the map of the global has not changed.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002720 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
2721 __ cmp(r3, Operand(Handle<Map>(object->map())));
2722 __ b(ne, &miss);
2723
ager@chromium.org378b34e2011-01-28 08:04:38 +00002724 // Check that the value in the cell is not the hole. If it is, this
2725 // cell could have been deleted and reintroducing the global needs
2726 // to update the property details in the property dictionary of the
2727 // global object. We bail out to the runtime system to do that.
2728 __ mov(r4, Operand(Handle<JSGlobalPropertyCell>(cell)));
2729 __ LoadRoot(r5, Heap::kTheHoleValueRootIndex);
2730 __ ldr(r6, FieldMemOperand(r4, JSGlobalPropertyCell::kValueOffset));
2731 __ cmp(r5, r6);
2732 __ b(eq, &miss);
2733
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002734 // Store the value in the cell.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002735 __ str(r0, FieldMemOperand(r4, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002736
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002737 Counters* counters = masm()->isolate()->counters();
2738 __ IncrementCounter(counters->named_store_global_inline(), 1, r4, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002739 __ Ret();
2740
2741 // Handle store cache miss.
2742 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002743 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, r4, r3);
2744 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002745 __ Jump(ic, RelocInfo::CODE_TARGET);
2746
2747 // Return the generated code.
2748 return GetCode(NORMAL, name);
2749}
2750
2751
lrn@chromium.org303ada72010-10-27 09:33:13 +00002752MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
2753 JSObject* object,
2754 JSObject* last) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002755 // ----------- S t a t e -------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002756 // -- r0 : receiver
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002757 // -- lr : return address
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002758 // -----------------------------------
2759 Label miss;
2760
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002761 // Check that receiver is not a smi.
2762 __ tst(r0, Operand(kSmiTagMask));
2763 __ b(eq, &miss);
2764
2765 // Check the maps of the full prototype chain.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002766 CheckPrototypes(object, r0, last, r3, r1, r4, name, &miss);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002767
2768 // If the last object in the prototype chain is a global object,
2769 // check that the global property cell is empty.
2770 if (last->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002771 MaybeObject* cell = GenerateCheckPropertyCell(masm(),
2772 GlobalObject::cast(last),
2773 name,
2774 r1,
2775 &miss);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002776 if (cell->IsFailure()) {
2777 miss.Unuse();
2778 return cell;
2779 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002780 }
2781
2782 // Return undefined if maps of the full prototype chain are still the
2783 // same and no global property with this name contains a value.
2784 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
2785 __ Ret();
2786
2787 __ bind(&miss);
2788 GenerateLoadMiss(masm(), Code::LOAD_IC);
2789
2790 // Return the generated code.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002791 return GetCode(NONEXISTENT, heap()->empty_string());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002792}
2793
2794
lrn@chromium.org303ada72010-10-27 09:33:13 +00002795MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object,
2796 JSObject* holder,
2797 int index,
2798 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002799 // ----------- S t a t e -------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002800 // -- r0 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002801 // -- r2 : name
2802 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002803 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002804 Label miss;
2805
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002806 GenerateLoadField(object, holder, r0, r3, r1, r4, index, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002807 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002808 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002809
2810 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002811 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002812}
2813
2814
lrn@chromium.org303ada72010-10-27 09:33:13 +00002815MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
2816 JSObject* object,
2817 JSObject* holder,
2818 AccessorInfo* callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002819 // ----------- S t a t e -------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002820 // -- r0 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002821 // -- r2 : name
2822 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002823 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002824 Label miss;
2825
ager@chromium.org378b34e2011-01-28 08:04:38 +00002826 MaybeObject* result = GenerateLoadCallback(object, holder, r0, r2, r3, r1, r4,
2827 callback, name, &miss);
2828 if (result->IsFailure()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002829 miss.Unuse();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002830 return result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002831 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002832
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002833 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002834 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002835
2836 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002837 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002838}
2839
2840
lrn@chromium.org303ada72010-10-27 09:33:13 +00002841MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
2842 JSObject* holder,
2843 Object* value,
2844 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002845 // ----------- S t a t e -------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002846 // -- r0 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002847 // -- r2 : name
2848 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002849 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002850 Label miss;
2851
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002852 GenerateLoadConstant(object, holder, r0, r3, r1, r4, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002853 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002854 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002855
2856 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002857 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002858}
2859
2860
lrn@chromium.org303ada72010-10-27 09:33:13 +00002861MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
2862 JSObject* holder,
2863 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002864 // ----------- S t a t e -------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002865 // -- r0 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002866 // -- r2 : name
2867 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002868 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002869 Label miss;
2870
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002871 LookupResult lookup;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002872 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002873 GenerateLoadInterceptor(object,
ager@chromium.orge2902be2009-06-08 12:21:35 +00002874 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002875 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00002876 r0,
2877 r2,
2878 r3,
2879 r1,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002880 r4,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002881 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00002882 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002883 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002884 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002885
2886 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002887 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002888}
2889
2890
lrn@chromium.org303ada72010-10-27 09:33:13 +00002891MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
2892 GlobalObject* holder,
2893 JSGlobalPropertyCell* cell,
2894 String* name,
2895 bool is_dont_delete) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002896 // ----------- S t a t e -------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002897 // -- r0 : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002898 // -- r2 : name
2899 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002900 // -----------------------------------
2901 Label miss;
2902
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002903 // If the object is the holder then we know that it's a global
2904 // object which can only happen for contextual calls. In this case,
2905 // the receiver cannot be a smi.
2906 if (object != holder) {
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002907 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002908 __ b(eq, &miss);
2909 }
2910
2911 // Check that the map of the global has not changed.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002912 CheckPrototypes(object, r0, holder, r3, r4, r1, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002913
2914 // Get the value from the cell.
2915 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002916 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002917
2918 // Check for deleted property if property can actually be deleted.
2919 if (!is_dont_delete) {
ager@chromium.orgab99eea2009-08-25 07:05:41 +00002920 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002921 __ cmp(r4, ip);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002922 __ b(eq, &miss);
2923 }
2924
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002925 __ mov(r0, r4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002926 Counters* counters = masm()->isolate()->counters();
2927 __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002928 __ Ret();
2929
2930 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002931 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002932 GenerateLoadMiss(masm(), Code::LOAD_IC);
2933
2934 // Return the generated code.
2935 return GetCode(NORMAL, name);
2936}
2937
2938
lrn@chromium.org303ada72010-10-27 09:33:13 +00002939MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
2940 JSObject* receiver,
2941 JSObject* holder,
2942 int index) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002943 // ----------- S t a t e -------------
2944 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00002945 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002946 // -- r1 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002947 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002948 Label miss;
2949
ager@chromium.orgac091b72010-05-05 07:34:42 +00002950 // Check the key is the cached one.
2951 __ cmp(r0, Operand(Handle<String>(name)));
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002952 __ b(ne, &miss);
2953
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002954 GenerateLoadField(receiver, holder, r1, r2, r3, r4, index, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002955 __ bind(&miss);
2956 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2957
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002958 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002959}
2960
2961
lrn@chromium.org303ada72010-10-27 09:33:13 +00002962MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
2963 String* name,
2964 JSObject* receiver,
2965 JSObject* holder,
2966 AccessorInfo* callback) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002967 // ----------- S t a t e -------------
2968 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00002969 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002970 // -- r1 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002971 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002972 Label miss;
2973
ager@chromium.orgac091b72010-05-05 07:34:42 +00002974 // Check the key is the cached one.
2975 __ cmp(r0, Operand(Handle<String>(name)));
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002976 __ b(ne, &miss);
2977
ager@chromium.org378b34e2011-01-28 08:04:38 +00002978 MaybeObject* result = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3,
2979 r4, callback, name, &miss);
2980 if (result->IsFailure()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002981 miss.Unuse();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002982 return result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002983 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002984
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002985 __ bind(&miss);
2986 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2987
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002988 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002989}
2990
2991
lrn@chromium.org303ada72010-10-27 09:33:13 +00002992MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
2993 JSObject* receiver,
2994 JSObject* holder,
2995 Object* value) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002996 // ----------- S t a t e -------------
2997 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00002998 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002999 // -- r1 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003000 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003001 Label miss;
3002
ager@chromium.orgac091b72010-05-05 07:34:42 +00003003 // Check the key is the cached one.
3004 __ cmp(r0, Operand(Handle<String>(name)));
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003005 __ b(ne, &miss);
3006
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003007 GenerateLoadConstant(receiver, holder, r1, r2, r3, r4, value, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003008 __ bind(&miss);
3009 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3010
3011 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003012 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003013}
3014
3015
lrn@chromium.org303ada72010-10-27 09:33:13 +00003016MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
3017 JSObject* holder,
3018 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003019 // ----------- S t a t e -------------
3020 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00003021 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00003022 // -- r1 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003023 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003024 Label miss;
3025
ager@chromium.orgac091b72010-05-05 07:34:42 +00003026 // Check the key is the cached one.
3027 __ cmp(r0, Operand(Handle<String>(name)));
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003028 __ b(ne, &miss);
3029
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003030 LookupResult lookup;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003031 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003032 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00003033 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003034 &lookup,
ager@chromium.orgac091b72010-05-05 07:34:42 +00003035 r1,
ager@chromium.orge2902be2009-06-08 12:21:35 +00003036 r0,
3037 r2,
3038 r3,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003039 r4,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003040 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00003041 &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003042 __ bind(&miss);
3043 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3044
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003045 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003046}
3047
3048
lrn@chromium.org303ada72010-10-27 09:33:13 +00003049MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003050 // ----------- S t a t e -------------
3051 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00003052 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00003053 // -- r1 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003054 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003055 Label miss;
3056
ager@chromium.orgac091b72010-05-05 07:34:42 +00003057 // Check the key is the cached one.
3058 __ cmp(r0, Operand(Handle<String>(name)));
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003059 __ b(ne, &miss);
3060
ager@chromium.orgac091b72010-05-05 07:34:42 +00003061 GenerateLoadArrayLength(masm(), r1, r2, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003062 __ bind(&miss);
3063 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3064
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003065 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003066}
3067
3068
lrn@chromium.org303ada72010-10-27 09:33:13 +00003069MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003070 // ----------- S t a t e -------------
3071 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00003072 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00003073 // -- r1 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003074 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003075 Label miss;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003076
3077 Counters* counters = masm()->isolate()->counters();
3078 __ IncrementCounter(counters->keyed_load_string_length(), 1, r2, r3);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003079
ager@chromium.orgac091b72010-05-05 07:34:42 +00003080 // Check the key is the cached one.
3081 __ cmp(r0, Operand(Handle<String>(name)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003082 __ b(ne, &miss);
3083
ager@chromium.org378b34e2011-01-28 08:04:38 +00003084 GenerateLoadStringLength(masm(), r1, r2, r3, &miss, true);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003085 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003086 __ DecrementCounter(counters->keyed_load_string_length(), 1, r2, r3);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003087
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003088 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3089
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003090 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091}
3092
3093
lrn@chromium.org303ada72010-10-27 09:33:13 +00003094MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003095 // ----------- S t a t e -------------
3096 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00003097 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00003098 // -- r1 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003099 // -----------------------------------
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003100 Label miss;
3101
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003102 Counters* counters = masm()->isolate()->counters();
3103 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, r2, r3);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003104
3105 // Check the name hasn't changed.
3106 __ cmp(r0, Operand(Handle<String>(name)));
3107 __ b(ne, &miss);
3108
3109 GenerateLoadFunctionPrototype(masm(), r1, r2, r3, &miss);
3110 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003111 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, r2, r3);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003112 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3113
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003114 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003115}
3116
3117
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003118MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003119 // ----------- S t a t e -------------
3120 // -- lr : return address
3121 // -- r0 : key
3122 // -- r1 : receiver
3123 // -----------------------------------
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003124 Code* stub;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003125 MaybeObject* maybe_stub = ComputeSharedKeyedLoadElementStub(receiver_map);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003126 if (!maybe_stub->To(&stub)) return maybe_stub;
3127 __ DispatchMap(r1,
3128 r2,
3129 Handle<Map>(receiver_map),
3130 Handle<Code>(stub),
3131 DO_SMI_CHECK);
3132
3133 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3134 __ Jump(ic, RelocInfo::CODE_TARGET);
3135
3136 // Return the generated code.
3137 return GetCode(NORMAL, NULL);
3138}
3139
3140
3141MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
3142 MapList* receiver_maps,
3143 CodeList* handler_ics) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003144 // ----------- S t a t e -------------
3145 // -- lr : return address
3146 // -- r0 : key
3147 // -- r1 : receiver
3148 // -----------------------------------
3149 Label miss;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003150 __ JumpIfSmi(r1, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003151
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003152 int receiver_count = receiver_maps->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003153 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003154 for (int current = 0; current < receiver_count; ++current) {
3155 Handle<Map> map(receiver_maps->at(current));
3156 Handle<Code> code(handler_ics->at(current));
3157 __ mov(ip, Operand(map));
3158 __ cmp(r2, ip);
3159 __ Jump(code, RelocInfo::CODE_TARGET, eq);
3160 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003161
3162 __ bind(&miss);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003163 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3164 __ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003165
3166 // Return the generated code.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003167 return GetCode(NORMAL, NULL, MEGAMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003168}
3169
3170
lrn@chromium.org303ada72010-10-27 09:33:13 +00003171MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
3172 int index,
3173 Map* transition,
3174 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003175 // ----------- S t a t e -------------
3176 // -- r0 : value
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003177 // -- r1 : name
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003178 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003179 // -- lr : return address
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003180 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003181 Label miss;
3182
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003183 Counters* counters = masm()->isolate()->counters();
3184 __ IncrementCounter(counters->keyed_store_field(), 1, r3, r4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003185
3186 // Check that the name has not changed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003187 __ cmp(r1, Operand(Handle<String>(name)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003188 __ b(ne, &miss);
3189
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003190 // r3 is used as scratch register. r1 and r2 keep their values if a jump to
3191 // the miss label is generated.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003192 GenerateStoreField(masm(),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003193 object,
3194 index,
3195 transition,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003196 r2, r1, r3,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003197 &miss);
3198 __ bind(&miss);
3199
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003200 __ DecrementCounter(counters->keyed_store_field(), 1, r3, r4);
3201 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003202 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003203
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003204 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003205 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003206}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003207
3208
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003209MaybeObject* KeyedStoreStubCompiler::CompileStoreElement(Map* receiver_map) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003210 // ----------- S t a t e -------------
3211 // -- r0 : value
3212 // -- r1 : key
3213 // -- r2 : receiver
3214 // -- lr : return address
3215 // -- r3 : scratch
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003216 // -----------------------------------
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003217 Code* stub;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003218 MaybeObject* maybe_stub = ComputeSharedKeyedStoreElementStub(receiver_map);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003219 if (!maybe_stub->To(&stub)) return maybe_stub;
3220 __ DispatchMap(r2,
3221 r3,
3222 Handle<Map>(receiver_map),
3223 Handle<Code>(stub),
3224 DO_SMI_CHECK);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003225
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003226 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003227 __ Jump(ic, RelocInfo::CODE_TARGET);
3228
3229 // Return the generated code.
3230 return GetCode(NORMAL, NULL);
3231}
3232
3233
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003234MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
3235 MapList* receiver_maps,
3236 CodeList* handler_ics) {
3237 // ----------- S t a t e -------------
3238 // -- r0 : value
3239 // -- r1 : key
3240 // -- r2 : receiver
3241 // -- lr : return address
3242 // -- r3 : scratch
3243 // -----------------------------------
3244 Label miss;
3245 __ JumpIfSmi(r2, &miss);
3246
3247 int receiver_count = receiver_maps->length();
3248 __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
3249 for (int current = 0; current < receiver_count; ++current) {
3250 Handle<Map> map(receiver_maps->at(current));
3251 Handle<Code> code(handler_ics->at(current));
3252 __ mov(ip, Operand(map));
3253 __ cmp(r3, ip);
3254 __ Jump(code, RelocInfo::CODE_TARGET, eq);
3255 }
3256
3257 __ bind(&miss);
3258 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3259 __ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
3260
3261 // Return the generated code.
3262 return GetCode(NORMAL, NULL, MEGAMORPHIC);
3263}
3264
3265
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003266MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00003267 // ----------- S t a t e -------------
3268 // -- r0 : argc
3269 // -- r1 : constructor
3270 // -- lr : return address
3271 // -- [sp] : last argument
3272 // -----------------------------------
3273 Label generic_stub_call;
3274
3275 // Use r7 for holding undefined which is used in several places below.
3276 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
3277
3278#ifdef ENABLE_DEBUGGER_SUPPORT
3279 // Check to see whether there are any break points in the function code. If
3280 // there are jump to the generic constructor stub which calls the actual
3281 // code for the function thereby hitting the break points.
3282 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
3283 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
3284 __ cmp(r2, r7);
3285 __ b(ne, &generic_stub_call);
3286#endif
3287
3288 // Load the initial map and verify that it is in fact a map.
3289 // r1: constructor function
3290 // r7: undefined
3291 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
3292 __ tst(r2, Operand(kSmiTagMask));
3293 __ b(eq, &generic_stub_call);
3294 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
3295 __ b(ne, &generic_stub_call);
3296
3297#ifdef DEBUG
3298 // Cannot construct functions this way.
3299 // r0: argc
3300 // r1: constructor function
3301 // r2: initial map
3302 // r7: undefined
3303 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
3304 __ Check(ne, "Function constructed by construct stub.");
3305#endif
3306
3307 // Now allocate the JSObject in new space.
3308 // r0: argc
3309 // r1: constructor function
3310 // r2: initial map
3311 // r7: undefined
3312 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003313 __ AllocateInNewSpace(r3,
3314 r4,
3315 r5,
3316 r6,
3317 &generic_stub_call,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00003318 SIZE_IN_WORDS);
ager@chromium.orga1645e22009-09-09 19:27:10 +00003319
3320 // Allocated the JSObject, now initialize the fields. Map is set to initial
3321 // map and properties and elements are set to empty fixed array.
3322 // r0: argc
3323 // r1: constructor function
3324 // r2: initial map
3325 // r3: object size (in words)
3326 // r4: JSObject (not tagged)
3327 // r7: undefined
3328 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
3329 __ mov(r5, r4);
3330 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3331 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
3332 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3333 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
3334 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3335 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
3336
3337 // Calculate the location of the first argument. The stack contains only the
3338 // argc arguments.
3339 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
3340
3341 // Fill all the in-object properties with undefined.
3342 // r0: argc
3343 // r1: first argument
3344 // r3: object size (in words)
3345 // r4: JSObject (not tagged)
3346 // r5: First in-object property of JSObject (not tagged)
3347 // r7: undefined
3348 // Fill the initialized properties with a constant value or a passed argument
3349 // depending on the this.x = ...; assignment in the function.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003350 SharedFunctionInfo* shared = function->shared();
ager@chromium.orga1645e22009-09-09 19:27:10 +00003351 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3352 if (shared->IsThisPropertyAssignmentArgument(i)) {
3353 Label not_passed, next;
3354 // Check if the argument assigned to the property is actually passed.
3355 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3356 __ cmp(r0, Operand(arg_number));
3357 __ b(le, &not_passed);
3358 // Argument passed - find it on the stack.
3359 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
3360 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
3361 __ b(&next);
3362 __ bind(&not_passed);
3363 // Set the property to undefined.
3364 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
3365 __ bind(&next);
3366 } else {
3367 // Set the property to the constant value.
3368 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3369 __ mov(r2, Operand(constant));
3370 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
3371 }
3372 }
3373
3374 // Fill the unused in-object property fields with undefined.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003375 ASSERT(function->has_initial_map());
ager@chromium.orga1645e22009-09-09 19:27:10 +00003376 for (int i = shared->this_property_assignments_count();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003377 i < function->initial_map()->inobject_properties();
ager@chromium.orga1645e22009-09-09 19:27:10 +00003378 i++) {
3379 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
3380 }
3381
3382 // r0: argc
3383 // r4: JSObject (not tagged)
3384 // Move argc to r1 and the JSObject to return to r0 and tag it.
3385 __ mov(r1, r0);
3386 __ mov(r0, r4);
3387 __ orr(r0, r0, Operand(kHeapObjectTag));
3388
3389 // r0: JSObject
3390 // r1: argc
3391 // Remove caller arguments and receiver from the stack and return.
3392 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
3393 __ add(sp, sp, Operand(kPointerSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003394 Counters* counters = masm()->isolate()->counters();
3395 __ IncrementCounter(counters->constructed_objects(), 1, r1, r2);
3396 __ IncrementCounter(counters->constructed_objects_stub(), 1, r1, r2);
ager@chromium.orga1645e22009-09-09 19:27:10 +00003397 __ Jump(lr);
3398
3399 // Jump to the generic stub in case the specialized code cannot handle the
3400 // construction.
3401 __ bind(&generic_stub_call);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003402 Handle<Code> code = masm()->isolate()->builtins()->JSConstructStubGeneric();
3403 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003404
3405 // Return the generated code.
3406 return GetCode();
3407}
3408
3409
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003410#undef __
3411#define __ ACCESS_MASM(masm)
3412
3413
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003414static bool IsElementTypeSigned(JSObject::ElementsKind elements_kind) {
3415 switch (elements_kind) {
3416 case JSObject::EXTERNAL_BYTE_ELEMENTS:
3417 case JSObject::EXTERNAL_SHORT_ELEMENTS:
3418 case JSObject::EXTERNAL_INT_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003419 return true;
3420
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003421 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3422 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3423 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
3424 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003425 return false;
3426
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003427 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
3428 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
3429 case JSObject::FAST_ELEMENTS:
3430 case JSObject::FAST_DOUBLE_ELEMENTS:
3431 case JSObject::DICTIONARY_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003432 UNREACHABLE();
3433 return false;
3434 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003435 return false;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003436}
3437
3438
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003439void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3440 MacroAssembler* masm,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003441 JSObject::ElementsKind elements_kind) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003442 // ---------- S t a t e --------------
3443 // -- lr : return address
3444 // -- r0 : key
3445 // -- r1 : receiver
3446 // -----------------------------------
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003447 Label miss_force_generic, slow, failed_allocation;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003448
3449 Register key = r0;
3450 Register receiver = r1;
3451
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003452 // This stub is meant to be tail-jumped to, the receiver must already
3453 // have been verified by the caller to not be a smi.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003454
3455 // Check that the key is a smi.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003456 __ JumpIfNotSmi(key, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003457
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003458 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003459 // r3: elements array
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003460
3461 // Check that the index is in range.
3462 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
3463 __ cmp(ip, Operand(key, ASR, kSmiTagSize));
3464 // Unsigned comparison catches both negative and too-large values.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003465 __ b(lo, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003466
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003467 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
3468 // r3: base pointer of external storage
3469
3470 // We are not untagging smi key and instead work with it
3471 // as if it was premultiplied by 2.
3472 ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
3473
3474 Register value = r2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003475 switch (elements_kind) {
3476 case JSObject::EXTERNAL_BYTE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003477 __ ldrsb(value, MemOperand(r3, key, LSR, 1));
3478 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003479 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
3480 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003481 __ ldrb(value, MemOperand(r3, key, LSR, 1));
3482 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003483 case JSObject::EXTERNAL_SHORT_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003484 __ ldrsh(value, MemOperand(r3, key, LSL, 0));
3485 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003486 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003487 __ ldrh(value, MemOperand(r3, key, LSL, 0));
3488 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003489 case JSObject::EXTERNAL_INT_ELEMENTS:
3490 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003491 __ ldr(value, MemOperand(r3, key, LSL, 1));
3492 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003493 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003494 if (CpuFeatures::IsSupported(VFP3)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003495 CpuFeatures::Scope scope(VFP3);
3496 __ add(r2, r3, Operand(key, LSL, 1));
3497 __ vldr(s0, r2, 0);
3498 } else {
3499 __ ldr(value, MemOperand(r3, key, LSL, 1));
3500 }
3501 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003502 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003503 if (CpuFeatures::IsSupported(VFP3)) {
3504 CpuFeatures::Scope scope(VFP3);
3505 __ add(r2, r3, Operand(key, LSL, 2));
3506 __ vldr(d0, r2, 0);
3507 } else {
3508 __ add(r4, r3, Operand(key, LSL, 2));
3509 // r4: pointer to the beginning of the double we want to load.
3510 __ ldr(r2, MemOperand(r4, 0));
3511 __ ldr(r3, MemOperand(r4, Register::kSizeInBytes));
3512 }
3513 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003514 case JSObject::FAST_ELEMENTS:
3515 case JSObject::FAST_DOUBLE_ELEMENTS:
3516 case JSObject::DICTIONARY_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003517 UNREACHABLE();
3518 break;
3519 }
3520
3521 // For integer array types:
3522 // r2: value
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003523 // For float array type:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003524 // s0: value (if VFP3 is supported)
3525 // r2: value (if VFP3 is not supported)
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003526 // For double array type:
3527 // d0: value (if VFP3 is supported)
3528 // r2/r3: value (if VFP3 is not supported)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003529
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003530 if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003531 // For the Int and UnsignedInt array types, we need to see whether
3532 // the value can be represented in a Smi. If not, we need to convert
3533 // it to a HeapNumber.
3534 Label box_int;
3535 __ cmp(value, Operand(0xC0000000));
3536 __ b(mi, &box_int);
3537 // Tag integer as smi and return it.
3538 __ mov(r0, Operand(value, LSL, kSmiTagSize));
3539 __ Ret();
3540
3541 __ bind(&box_int);
3542 // Allocate a HeapNumber for the result and perform int-to-double
3543 // conversion. Don't touch r0 or r1 as they are needed if allocation
3544 // fails.
3545 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
3546 __ AllocateHeapNumber(r5, r3, r4, r6, &slow);
3547 // Now we can use r0 for the result as key is not needed any more.
3548 __ mov(r0, r5);
3549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003550 if (CpuFeatures::IsSupported(VFP3)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003551 CpuFeatures::Scope scope(VFP3);
3552 __ vmov(s0, value);
3553 __ vcvt_f64_s32(d0, s0);
3554 __ sub(r3, r0, Operand(kHeapObjectTag));
3555 __ vstr(d0, r3, HeapNumber::kValueOffset);
3556 __ Ret();
3557 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003558 Register dst1 = r1;
3559 Register dst2 = r3;
3560 FloatingPointHelper::Destination dest =
3561 FloatingPointHelper::kCoreRegisters;
3562 FloatingPointHelper::ConvertIntToDouble(masm,
3563 value,
3564 dest,
3565 d0,
3566 dst1,
3567 dst2,
3568 r9,
3569 s0);
3570 __ str(dst1, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
3571 __ str(dst2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
3572 __ Ret();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003573 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003574 } else if (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003575 // The test is different for unsigned int values. Since we need
3576 // the value to be in the range of a positive smi, we can't
3577 // handle either of the top two bits being set in the value.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003578 if (CpuFeatures::IsSupported(VFP3)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003579 CpuFeatures::Scope scope(VFP3);
3580 Label box_int, done;
3581 __ tst(value, Operand(0xC0000000));
3582 __ b(ne, &box_int);
3583 // Tag integer as smi and return it.
3584 __ mov(r0, Operand(value, LSL, kSmiTagSize));
3585 __ Ret();
3586
3587 __ bind(&box_int);
3588 __ vmov(s0, value);
3589 // Allocate a HeapNumber for the result and perform int-to-double
3590 // conversion. Don't use r0 and r1 as AllocateHeapNumber clobbers all
3591 // registers - also when jumping due to exhausted young space.
3592 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
3593 __ AllocateHeapNumber(r2, r3, r4, r6, &slow);
3594
3595 __ vcvt_f64_u32(d0, s0);
3596 __ sub(r1, r2, Operand(kHeapObjectTag));
3597 __ vstr(d0, r1, HeapNumber::kValueOffset);
3598
3599 __ mov(r0, r2);
3600 __ Ret();
3601 } else {
3602 // Check whether unsigned integer fits into smi.
3603 Label box_int_0, box_int_1, done;
3604 __ tst(value, Operand(0x80000000));
3605 __ b(ne, &box_int_0);
3606 __ tst(value, Operand(0x40000000));
3607 __ b(ne, &box_int_1);
3608 // Tag integer as smi and return it.
3609 __ mov(r0, Operand(value, LSL, kSmiTagSize));
3610 __ Ret();
3611
3612 Register hiword = value; // r2.
3613 Register loword = r3;
3614
3615 __ bind(&box_int_0);
3616 // Integer does not have leading zeros.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003617 GenerateUInt2Double(masm, hiword, loword, r4, 0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003618 __ b(&done);
3619
3620 __ bind(&box_int_1);
3621 // Integer has one leading zero.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003622 GenerateUInt2Double(masm, hiword, loword, r4, 1);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003623
3624
3625 __ bind(&done);
3626 // Integer was converted to double in registers hiword:loword.
3627 // Wrap it into a HeapNumber. Don't use r0 and r1 as AllocateHeapNumber
3628 // clobbers all registers - also when jumping due to exhausted young
3629 // space.
3630 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
3631 __ AllocateHeapNumber(r4, r5, r7, r6, &slow);
3632
3633 __ str(hiword, FieldMemOperand(r4, HeapNumber::kExponentOffset));
3634 __ str(loword, FieldMemOperand(r4, HeapNumber::kMantissaOffset));
3635
3636 __ mov(r0, r4);
3637 __ Ret();
3638 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003639 } else if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003640 // For the floating-point array type, we need to always allocate a
3641 // HeapNumber.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003642 if (CpuFeatures::IsSupported(VFP3)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003643 CpuFeatures::Scope scope(VFP3);
3644 // Allocate a HeapNumber for the result. Don't use r0 and r1 as
3645 // AllocateHeapNumber clobbers all registers - also when jumping due to
3646 // exhausted young space.
3647 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
3648 __ AllocateHeapNumber(r2, r3, r4, r6, &slow);
3649 __ vcvt_f64_f32(d0, s0);
3650 __ sub(r1, r2, Operand(kHeapObjectTag));
3651 __ vstr(d0, r1, HeapNumber::kValueOffset);
3652
3653 __ mov(r0, r2);
3654 __ Ret();
3655 } else {
3656 // Allocate a HeapNumber for the result. Don't use r0 and r1 as
3657 // AllocateHeapNumber clobbers all registers - also when jumping due to
3658 // exhausted young space.
3659 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
3660 __ AllocateHeapNumber(r3, r4, r5, r6, &slow);
3661 // VFP is not available, do manual single to double conversion.
3662
3663 // r2: floating point value (binary32)
3664 // r3: heap number for result
3665
3666 // Extract mantissa to r0. OK to clobber r0 now as there are no jumps to
3667 // the slow case from here.
3668 __ and_(r0, value, Operand(kBinary32MantissaMask));
3669
3670 // Extract exponent to r1. OK to clobber r1 now as there are no jumps to
3671 // the slow case from here.
3672 __ mov(r1, Operand(value, LSR, kBinary32MantissaBits));
3673 __ and_(r1, r1, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3674
3675 Label exponent_rebiased;
3676 __ teq(r1, Operand(0x00));
3677 __ b(eq, &exponent_rebiased);
3678
3679 __ teq(r1, Operand(0xff));
3680 __ mov(r1, Operand(0x7ff), LeaveCC, eq);
3681 __ b(eq, &exponent_rebiased);
3682
3683 // Rebias exponent.
3684 __ add(r1,
3685 r1,
3686 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3687
3688 __ bind(&exponent_rebiased);
3689 __ and_(r2, value, Operand(kBinary32SignMask));
3690 value = no_reg;
3691 __ orr(r2, r2, Operand(r1, LSL, HeapNumber::kMantissaBitsInTopWord));
3692
3693 // Shift mantissa.
3694 static const int kMantissaShiftForHiWord =
3695 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3696
3697 static const int kMantissaShiftForLoWord =
3698 kBitsPerInt - kMantissaShiftForHiWord;
3699
3700 __ orr(r2, r2, Operand(r0, LSR, kMantissaShiftForHiWord));
3701 __ mov(r0, Operand(r0, LSL, kMantissaShiftForLoWord));
3702
3703 __ str(r2, FieldMemOperand(r3, HeapNumber::kExponentOffset));
3704 __ str(r0, FieldMemOperand(r3, HeapNumber::kMantissaOffset));
3705
3706 __ mov(r0, r3);
3707 __ Ret();
3708 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003709 } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003710 if (CpuFeatures::IsSupported(VFP3)) {
3711 CpuFeatures::Scope scope(VFP3);
3712 // Allocate a HeapNumber for the result. Don't use r0 and r1 as
3713 // AllocateHeapNumber clobbers all registers - also when jumping due to
3714 // exhausted young space.
3715 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
3716 __ AllocateHeapNumber(r2, r3, r4, r6, &slow);
3717 __ sub(r1, r2, Operand(kHeapObjectTag));
3718 __ vstr(d0, r1, HeapNumber::kValueOffset);
3719
3720 __ mov(r0, r2);
3721 __ Ret();
3722 } else {
3723 // Allocate a HeapNumber for the result. Don't use r0 and r1 as
3724 // AllocateHeapNumber clobbers all registers - also when jumping due to
3725 // exhausted young space.
3726 __ LoadRoot(r7, Heap::kHeapNumberMapRootIndex);
3727 __ AllocateHeapNumber(r4, r5, r6, r7, &slow);
3728
3729 __ str(r2, FieldMemOperand(r4, HeapNumber::kMantissaOffset));
3730 __ str(r3, FieldMemOperand(r4, HeapNumber::kExponentOffset));
3731 __ mov(r0, r4);
3732 __ Ret();
3733 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003734
3735 } else {
3736 // Tag integer as smi and return it.
3737 __ mov(r0, Operand(value, LSL, kSmiTagSize));
3738 __ Ret();
3739 }
3740
3741 // Slow case, key and receiver still in r0 and r1.
3742 __ bind(&slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003743 __ IncrementCounter(
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003744 masm->isolate()->counters()->keyed_load_external_array_slow(),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003745 1, r2, r3);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003746
3747 // ---------- S t a t e --------------
3748 // -- lr : return address
3749 // -- r0 : key
3750 // -- r1 : receiver
3751 // -----------------------------------
3752
3753 __ Push(r1, r0);
3754
3755 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3756
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003757 __ bind(&miss_force_generic);
3758 Code* stub = masm->isolate()->builtins()->builtin(
3759 Builtins::kKeyedLoadIC_MissForceGeneric);
3760 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003761}
3762
3763
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003764void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3765 MacroAssembler* masm,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003766 JSObject::ElementsKind elements_kind) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003767 // ---------- S t a t e --------------
3768 // -- r0 : value
3769 // -- r1 : key
3770 // -- r2 : receiver
3771 // -- lr : return address
3772 // -----------------------------------
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003773 Label slow, check_heap_number, miss_force_generic;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003774
3775 // Register usage.
3776 Register value = r0;
3777 Register key = r1;
3778 Register receiver = r2;
3779 // r3 mostly holds the elements array or the destination external array.
3780
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003781 // This stub is meant to be tail-jumped to, the receiver must already
3782 // have been verified by the caller to not be a smi.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003783
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003784 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3785
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003786 // Check that the key is a smi.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003787 __ JumpIfNotSmi(key, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003788
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003789 // Check that the index is in range
3790 __ SmiUntag(r4, key);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003791 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
3792 __ cmp(r4, ip);
3793 // Unsigned comparison catches both negative and too-large values.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003794 __ b(hs, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003795
3796 // Handle both smis and HeapNumbers in the fast path. Go to the
3797 // runtime for all other kinds of values.
3798 // r3: external array.
3799 // r4: key (integer).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003800 if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003801 // Double to pixel conversion is only implemented in the runtime for now.
3802 __ JumpIfNotSmi(value, &slow);
3803 } else {
3804 __ JumpIfNotSmi(value, &check_heap_number);
3805 }
3806 __ SmiUntag(r5, value);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003807 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
3808
3809 // r3: base pointer of external storage.
3810 // r4: key (integer).
3811 // r5: value (integer).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003812 switch (elements_kind) {
3813 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003814 // Clamp the value to [0..255].
3815 __ Usat(r5, 8, Operand(r5));
3816 __ strb(r5, MemOperand(r3, r4, LSL, 0));
3817 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003818 case JSObject::EXTERNAL_BYTE_ELEMENTS:
3819 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003820 __ strb(r5, MemOperand(r3, r4, LSL, 0));
3821 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003822 case JSObject::EXTERNAL_SHORT_ELEMENTS:
3823 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003824 __ strh(r5, MemOperand(r3, r4, LSL, 1));
3825 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003826 case JSObject::EXTERNAL_INT_ELEMENTS:
3827 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003828 __ str(r5, MemOperand(r3, r4, LSL, 2));
3829 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003830 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003831 // Perform int-to-float conversion and store to memory.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003832 StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003833 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003834 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003835 __ add(r3, r3, Operand(r4, LSL, 3));
3836 // r3: effective address of the double element
3837 FloatingPointHelper::Destination destination;
3838 if (CpuFeatures::IsSupported(VFP3)) {
3839 destination = FloatingPointHelper::kVFPRegisters;
3840 } else {
3841 destination = FloatingPointHelper::kCoreRegisters;
3842 }
3843 FloatingPointHelper::ConvertIntToDouble(
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003844 masm, r5, destination,
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003845 d0, r6, r7, // These are: double_dst, dst1, dst2.
3846 r4, s2); // These are: scratch2, single_scratch.
3847 if (destination == FloatingPointHelper::kVFPRegisters) {
3848 CpuFeatures::Scope scope(VFP3);
3849 __ vstr(d0, r3, 0);
3850 } else {
3851 __ str(r6, MemOperand(r3, 0));
3852 __ str(r7, MemOperand(r3, Register::kSizeInBytes));
3853 }
3854 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003855 case JSObject::FAST_ELEMENTS:
3856 case JSObject::FAST_DOUBLE_ELEMENTS:
3857 case JSObject::DICTIONARY_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003858 UNREACHABLE();
3859 break;
3860 }
3861
3862 // Entry registers are intact, r0 holds the value which is the return value.
3863 __ Ret();
3864
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003865 if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003866 // r3: external array.
3867 // r4: index (integer).
3868 __ bind(&check_heap_number);
3869 __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
3870 __ b(ne, &slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003871
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003872 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003873
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003874 // r3: base pointer of external storage.
3875 // r4: key (integer).
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003876
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003877 // The WebGL specification leaves the behavior of storing NaN and
3878 // +/-Infinity into integer arrays basically undefined. For more
3879 // reproducible behavior, convert these to zero.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003880 if (CpuFeatures::IsSupported(VFP3)) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003881 CpuFeatures::Scope scope(VFP3);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003882
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003883 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003884 // vldr requires offset to be a multiple of 4 so we can not
3885 // include -kHeapObjectTag into it.
3886 __ sub(r5, r0, Operand(kHeapObjectTag));
3887 __ vldr(d0, r5, HeapNumber::kValueOffset);
3888 __ add(r5, r3, Operand(r4, LSL, 2));
3889 __ vcvt_f32_f64(s0, d0);
3890 __ vstr(s0, r5, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003891 } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003892 __ sub(r5, r0, Operand(kHeapObjectTag));
3893 __ vldr(d0, r5, HeapNumber::kValueOffset);
3894 __ add(r5, r3, Operand(r4, LSL, 3));
3895 __ vstr(d0, r5, 0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003896 } else {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003897 // Hoisted load. vldr requires offset to be a multiple of 4 so we can
3898 // not include -kHeapObjectTag into it.
3899 __ sub(r5, value, Operand(kHeapObjectTag));
3900 __ vldr(d0, r5, HeapNumber::kValueOffset);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003901 __ EmitECMATruncate(r5, d0, s2, r6, r7, r9);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003902
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003903 switch (elements_kind) {
3904 case JSObject::EXTERNAL_BYTE_ELEMENTS:
3905 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003906 __ strb(r5, MemOperand(r3, r4, LSL, 0));
3907 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003908 case JSObject::EXTERNAL_SHORT_ELEMENTS:
3909 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003910 __ strh(r5, MemOperand(r3, r4, LSL, 1));
3911 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003912 case JSObject::EXTERNAL_INT_ELEMENTS:
3913 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003914 __ str(r5, MemOperand(r3, r4, LSL, 2));
3915 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003916 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
3917 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
3918 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
3919 case JSObject::FAST_ELEMENTS:
3920 case JSObject::FAST_DOUBLE_ELEMENTS:
3921 case JSObject::DICTIONARY_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003922 UNREACHABLE();
3923 break;
3924 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003925 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003926
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003927 // Entry registers are intact, r0 holds the value which is the return
3928 // value.
3929 __ Ret();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003930 } else {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003931 // VFP3 is not available do manual conversions.
3932 __ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset));
3933 __ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003934
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003935 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003936 Label done, nan_or_infinity_or_zero;
3937 static const int kMantissaInHiWordShift =
3938 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003939
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003940 static const int kMantissaInLoWordShift =
3941 kBitsPerInt - kMantissaInHiWordShift;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003942
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003943 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3944 // and infinities. All these should be converted to 0.
3945 __ mov(r7, Operand(HeapNumber::kExponentMask));
3946 __ and_(r9, r5, Operand(r7), SetCC);
3947 __ b(eq, &nan_or_infinity_or_zero);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003948
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003949 __ teq(r9, Operand(r7));
3950 __ mov(r9, Operand(kBinary32ExponentMask), LeaveCC, eq);
3951 __ b(eq, &nan_or_infinity_or_zero);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003952
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003953 // Rebias exponent.
3954 __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
3955 __ add(r9,
3956 r9,
3957 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003958
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003959 __ cmp(r9, Operand(kBinary32MaxExponent));
3960 __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, gt);
3961 __ orr(r5, r5, Operand(kBinary32ExponentMask), LeaveCC, gt);
3962 __ b(gt, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003963
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003964 __ cmp(r9, Operand(kBinary32MinExponent));
3965 __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, lt);
3966 __ b(lt, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003967
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003968 __ and_(r7, r5, Operand(HeapNumber::kSignMask));
3969 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
3970 __ orr(r7, r7, Operand(r5, LSL, kMantissaInHiWordShift));
3971 __ orr(r7, r7, Operand(r6, LSR, kMantissaInLoWordShift));
3972 __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003973
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003974 __ bind(&done);
3975 __ str(r5, MemOperand(r3, r4, LSL, 2));
3976 // Entry registers are intact, r0 holds the value which is the return
3977 // value.
3978 __ Ret();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003979
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003980 __ bind(&nan_or_infinity_or_zero);
3981 __ and_(r7, r5, Operand(HeapNumber::kSignMask));
3982 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
3983 __ orr(r9, r9, r7);
3984 __ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift));
3985 __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
3986 __ b(&done);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003987 } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003988 __ add(r7, r3, Operand(r4, LSL, 3));
3989 // r7: effective address of destination element.
3990 __ str(r6, MemOperand(r7, 0));
3991 __ str(r5, MemOperand(r7, Register::kSizeInBytes));
3992 __ Ret();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003993 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003994 bool is_signed_type = IsElementTypeSigned(elements_kind);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003995 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3996 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3997
3998 Label done, sign;
3999
4000 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4001 // and infinities. All these should be converted to 0.
4002 __ mov(r7, Operand(HeapNumber::kExponentMask));
4003 __ and_(r9, r5, Operand(r7), SetCC);
4004 __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq);
4005 __ b(eq, &done);
4006
4007 __ teq(r9, Operand(r7));
4008 __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq);
4009 __ b(eq, &done);
4010
4011 // Unbias exponent.
4012 __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
4013 __ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC);
4014 // If exponent is negative then result is 0.
4015 __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, mi);
4016 __ b(mi, &done);
4017
4018 // If exponent is too big then result is minimal value.
4019 __ cmp(r9, Operand(meaningfull_bits - 1));
4020 __ mov(r5, Operand(min_value), LeaveCC, ge);
4021 __ b(ge, &done);
4022
4023 __ and_(r7, r5, Operand(HeapNumber::kSignMask), SetCC);
4024 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
4025 __ orr(r5, r5, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4026
4027 __ rsb(r9, r9, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC);
4028 __ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl);
4029 __ b(pl, &sign);
4030
4031 __ rsb(r9, r9, Operand(0, RelocInfo::NONE));
4032 __ mov(r5, Operand(r5, LSL, r9));
4033 __ rsb(r9, r9, Operand(meaningfull_bits));
4034 __ orr(r5, r5, Operand(r6, LSR, r9));
4035
4036 __ bind(&sign);
4037 __ teq(r7, Operand(0, RelocInfo::NONE));
4038 __ rsb(r5, r5, Operand(0, RelocInfo::NONE), LeaveCC, ne);
4039
4040 __ bind(&done);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004041 switch (elements_kind) {
4042 case JSObject::EXTERNAL_BYTE_ELEMENTS:
4043 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004044 __ strb(r5, MemOperand(r3, r4, LSL, 0));
4045 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004046 case JSObject::EXTERNAL_SHORT_ELEMENTS:
4047 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004048 __ strh(r5, MemOperand(r3, r4, LSL, 1));
4049 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004050 case JSObject::EXTERNAL_INT_ELEMENTS:
4051 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004052 __ str(r5, MemOperand(r3, r4, LSL, 2));
4053 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004054 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
4055 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
4056 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
4057 case JSObject::FAST_ELEMENTS:
4058 case JSObject::FAST_DOUBLE_ELEMENTS:
4059 case JSObject::DICTIONARY_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004060 UNREACHABLE();
4061 break;
4062 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004063 }
4064 }
4065 }
4066
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004067 // Slow case, key and receiver still in r0 and r1.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004068 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004069 __ IncrementCounter(
4070 masm->isolate()->counters()->keyed_load_external_array_slow(),
4071 1, r2, r3);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004072
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004073 // ---------- S t a t e --------------
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004074 // -- lr : return address
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004075 // -- r0 : key
4076 // -- r1 : receiver
4077 // -----------------------------------
4078 Handle<Code> slow_ic =
4079 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4080 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4081
4082 // Miss case, call the runtime.
4083 __ bind(&miss_force_generic);
4084
4085 // ---------- S t a t e --------------
4086 // -- lr : return address
4087 // -- r0 : key
4088 // -- r1 : receiver
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004089 // -----------------------------------
4090
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004091 Handle<Code> miss_ic =
4092 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4093 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4094}
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004095
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004096
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004097void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4098 // ----------- S t a t e -------------
4099 // -- lr : return address
4100 // -- r0 : key
4101 // -- r1 : receiver
4102 // -----------------------------------
4103 Label miss_force_generic;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004104
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004105 // This stub is meant to be tail-jumped to, the receiver must already
4106 // have been verified by the caller to not be a smi.
4107
4108 // Check that the key is a smi.
4109 __ JumpIfNotSmi(r0, &miss_force_generic);
4110
4111 // Get the elements array.
4112 __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
4113 __ AssertFastElements(r2);
4114
4115 // Check that the key is within bounds.
4116 __ ldr(r3, FieldMemOperand(r2, FixedArray::kLengthOffset));
4117 __ cmp(r0, Operand(r3));
4118 __ b(hs, &miss_force_generic);
4119
4120 // Load the result and make sure it's not the hole.
4121 __ add(r3, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4122 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4123 __ ldr(r4,
4124 MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
4125 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
4126 __ cmp(r4, ip);
4127 __ b(eq, &miss_force_generic);
4128 __ mov(r0, r4);
4129 __ Ret();
4130
4131 __ bind(&miss_force_generic);
4132 Code* stub = masm->isolate()->builtins()->builtin(
4133 Builtins::kKeyedLoadIC_MissForceGeneric);
4134 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
4135}
4136
4137
4138void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
4139 bool is_js_array) {
4140 // ----------- S t a t e -------------
4141 // -- r0 : value
4142 // -- r1 : key
4143 // -- r2 : receiver
4144 // -- lr : return address
4145 // -- r3 : scratch
4146 // -- r4 : scratch (elements)
4147 // -----------------------------------
4148 Label miss_force_generic;
4149
4150 Register value_reg = r0;
4151 Register key_reg = r1;
4152 Register receiver_reg = r2;
4153 Register scratch = r3;
4154 Register elements_reg = r4;
4155
4156 // This stub is meant to be tail-jumped to, the receiver must already
4157 // have been verified by the caller to not be a smi.
4158
4159 // Check that the key is a smi.
4160 __ JumpIfNotSmi(r0, &miss_force_generic);
4161
4162 // Get the elements array and make sure it is a fast element array, not 'cow'.
4163 __ ldr(elements_reg,
4164 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4165 __ CheckMap(elements_reg,
4166 scratch,
4167 Heap::kFixedArrayMapRootIndex,
4168 &miss_force_generic,
4169 DONT_DO_SMI_CHECK);
4170
4171 // Check that the key is within bounds.
4172 if (is_js_array) {
4173 __ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4174 } else {
4175 __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4176 }
4177 // Compare smis.
4178 __ cmp(key_reg, scratch);
4179 __ b(hs, &miss_force_generic);
4180
4181 __ add(scratch,
4182 elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4183 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4184 __ str(value_reg,
4185 MemOperand(scratch, key_reg, LSL, kPointerSizeLog2 - kSmiTagSize));
4186 __ RecordWrite(scratch,
4187 Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize),
4188 receiver_reg , elements_reg);
4189
4190 // value_reg (r0) is preserved.
4191 // Done.
4192 __ Ret();
4193
4194 __ bind(&miss_force_generic);
4195 Handle<Code> ic =
4196 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4197 __ Jump(ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004198}
4199
4200
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201#undef __
4202
4203} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004204
4205#endif // V8_TARGET_ARCH_ARM