blob: 0da5f64696ed1adc22f1dbe24891408a53914fe6 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// 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
Leon Clarkef7060e22010-06-03 12:02:55 +010030#if defined(V8_TARGET_ARCH_ARM)
31
Steve Blocka7e24c12009-10-30 11:49:00 +000032#include "ic-inl.h"
33#include "codegen-inl.h"
34#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
42static void ProbeTable(MacroAssembler* masm,
43 Code::Flags flags,
44 StubCache::Table table,
45 Register name,
46 Register offset) {
47 ExternalReference key_offset(SCTableReference::keyReference(table));
48 ExternalReference value_offset(SCTableReference::valueReference(table));
49
50 Label miss;
51
52 // Save the offset on the stack.
53 __ push(offset);
54
55 // Check that the key in the entry matches the name.
56 __ mov(ip, Operand(key_offset));
57 __ ldr(ip, MemOperand(ip, offset, LSL, 1));
Steve Block6ded16b2010-05-10 14:33:55 +010058 __ cmp(name, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +000059 __ b(ne, &miss);
60
61 // Get the code entry from the cache.
62 __ mov(ip, Operand(value_offset));
63 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
64
65 // Check that the flags match what we're looking for.
66 __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
67 __ and_(offset, offset, Operand(~Code::kFlagsNotUsedInLookup));
68 __ cmp(offset, Operand(flags));
69 __ b(ne, &miss);
70
71 // Restore offset and re-load code entry from cache.
72 __ pop(offset);
73 __ mov(ip, Operand(value_offset));
74 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
75
76 // Jump to the first instruction in the code stub.
77 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
78 __ Jump(offset);
79
80 // Miss: Restore offset and fall through.
81 __ bind(&miss);
82 __ pop(offset);
83}
84
85
Ben Murdoch3bec4d22010-07-22 14:51:16 +010086// Helper function used to check that the dictionary doesn't contain
87// the property. This function may return false negatives, so miss_label
88// must always call a backup property check that is complete.
89// This function is safe to call if the receiver has fast properties.
90// Name must be a symbol and receiver must be a heap object.
91static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
92 Label* miss_label,
93 Register receiver,
94 String* name,
95 Register scratch0,
96 Register scratch1) {
97 ASSERT(name->IsSymbol());
98 __ IncrementCounter(&Counters::negative_lookups, 1, scratch0, scratch1);
99 __ IncrementCounter(&Counters::negative_lookups_miss, 1, scratch0, scratch1);
100
101 Label done;
102
103 const int kInterceptorOrAccessCheckNeededMask =
104 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
105
106 // Bail out if the receiver has a named interceptor or requires access checks.
107 Register map = scratch1;
108 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
109 __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
110 __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
111 __ b(ne, miss_label);
112
113 // Check that receiver is a JSObject.
114 __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
115 __ cmp(scratch0, Operand(FIRST_JS_OBJECT_TYPE));
116 __ b(lt, miss_label);
117
118 // Load properties array.
119 Register properties = scratch0;
120 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
121 // Check that the properties array is a dictionary.
122 __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
123 Register tmp = properties;
124 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
125 __ cmp(map, tmp);
126 __ b(ne, miss_label);
127
128 // Restore the temporarily used register.
129 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
130
131 // Compute the capacity mask.
132 const int kCapacityOffset =
133 StringDictionary::kHeaderSize +
134 StringDictionary::kCapacityIndex * kPointerSize;
135
136 // Generate an unrolled loop that performs a few probes before
137 // giving up.
138 static const int kProbes = 4;
139 const int kElementsStartOffset =
140 StringDictionary::kHeaderSize +
141 StringDictionary::kElementsStartIndex * kPointerSize;
142
143 // If names of slots in range from 1 to kProbes - 1 for the hash value are
144 // not equal to the name and kProbes-th slot is not used (its name is the
145 // undefined value), it guarantees the hash table doesn't contain the
146 // property. It's true even if some slots represent deleted properties
147 // (their names are the null value).
148 for (int i = 0; i < kProbes; i++) {
149 // scratch0 points to properties hash.
150 // Compute the masked index: (hash + i + i * i) & mask.
151 Register index = scratch1;
152 // Capacity is smi 2^n.
153 __ ldr(index, FieldMemOperand(properties, kCapacityOffset));
154 __ sub(index, index, Operand(1));
155 __ and_(index, index, Operand(
156 Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i))));
157
158 // Scale the index by multiplying by the entry size.
159 ASSERT(StringDictionary::kEntrySize == 3);
160 __ add(index, index, Operand(index, LSL, 1)); // index *= 3.
161
162 Register entity_name = scratch1;
163 // Having undefined at this place means the name is not contained.
164 ASSERT_EQ(kSmiTagSize, 1);
165 Register tmp = properties;
166 __ add(tmp, properties, Operand(index, LSL, 1));
167 __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
168
169 ASSERT(!tmp.is(entity_name));
170 __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
171 __ cmp(entity_name, tmp);
172 if (i != kProbes - 1) {
173 __ b(eq, &done);
174
175 // Stop if found the property.
176 __ cmp(entity_name, Operand(Handle<String>(name)));
177 __ b(eq, miss_label);
178
179 // Check if the entry name is not a symbol.
180 __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
181 __ ldrb(entity_name,
182 FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
183 __ tst(entity_name, Operand(kIsSymbolMask));
184 __ b(eq, miss_label);
185
186 // Restore the properties.
187 __ ldr(properties,
188 FieldMemOperand(receiver, JSObject::kPropertiesOffset));
189 } else {
190 // Give up probing if still not found the undefined value.
191 __ b(ne, miss_label);
192 }
193 }
194 __ bind(&done);
195 __ DecrementCounter(&Counters::negative_lookups_miss, 1, scratch0, scratch1);
196}
197
198
Steve Blocka7e24c12009-10-30 11:49:00 +0000199void StubCache::GenerateProbe(MacroAssembler* masm,
200 Code::Flags flags,
201 Register receiver,
202 Register name,
203 Register scratch,
204 Register extra) {
205 Label miss;
206
207 // Make sure that code is valid. The shifting code relies on the
208 // entry size being 8.
209 ASSERT(sizeof(Entry) == 8);
210
211 // Make sure the flags does not name a specific type.
212 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
213
214 // Make sure that there are no register conflicts.
215 ASSERT(!scratch.is(receiver));
216 ASSERT(!scratch.is(name));
217
218 // Check that the receiver isn't a smi.
219 __ tst(receiver, Operand(kSmiTagMask));
220 __ b(eq, &miss);
221
222 // Get the map of the receiver and compute the hash.
Steve Blockd0582a62009-12-15 09:54:21 +0000223 __ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
225 __ add(scratch, scratch, Operand(ip));
226 __ eor(scratch, scratch, Operand(flags));
227 __ and_(scratch,
228 scratch,
229 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
230
231 // Probe the primary table.
232 ProbeTable(masm, flags, kPrimary, name, scratch);
233
234 // Primary miss: Compute hash for secondary probe.
235 __ sub(scratch, scratch, Operand(name));
236 __ add(scratch, scratch, Operand(flags));
237 __ and_(scratch,
238 scratch,
239 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
240
241 // Probe the secondary table.
242 ProbeTable(masm, flags, kSecondary, name, scratch);
243
244 // Cache miss: Fall-through and let caller handle the miss by
245 // entering the runtime system.
246 __ bind(&miss);
247}
248
249
250void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
251 int index,
252 Register prototype) {
253 // Load the global or builtins object from the current context.
254 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
255 // Load the global context from the global or builtins object.
256 __ ldr(prototype,
257 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
258 // Load the function from the global context.
259 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
260 // Load the initial map. The global functions all have initial maps.
261 __ ldr(prototype,
262 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
263 // Load the prototype from the initial map.
264 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
265}
266
267
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100268void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
269 MacroAssembler* masm, int index, Register prototype) {
270 // Get the global function with the given index.
271 JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
272 // Load its initial map. The global functions all have initial maps.
273 __ Move(prototype, Handle<Map>(function->initial_map()));
274 // Load the prototype from the initial map.
275 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
276}
277
278
Steve Blocka7e24c12009-10-30 11:49:00 +0000279// Load a fast property out of a holder object (src). In-object properties
280// are loaded directly otherwise the property is loaded from the properties
281// fixed array.
282void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
283 Register dst, Register src,
284 JSObject* holder, int index) {
285 // Adjust for the number of properties stored in the holder.
286 index -= holder->map()->inobject_properties();
287 if (index < 0) {
288 // Get the property straight out of the holder.
289 int offset = holder->map()->instance_size() + (index * kPointerSize);
290 __ ldr(dst, FieldMemOperand(src, offset));
291 } else {
292 // Calculate the offset into the properties array.
293 int offset = index * kPointerSize + FixedArray::kHeaderSize;
294 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
295 __ ldr(dst, FieldMemOperand(dst, offset));
296 }
297}
298
299
300void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
301 Register receiver,
302 Register scratch,
303 Label* miss_label) {
304 // Check that the receiver isn't a smi.
305 __ tst(receiver, Operand(kSmiTagMask));
306 __ b(eq, miss_label);
307
308 // Check that the object is a JS array.
309 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
310 __ b(ne, miss_label);
311
312 // Load length directly from the JS array.
313 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
314 __ Ret();
315}
316
317
Andrei Popescu402d9372010-02-26 13:31:12 +0000318// Generate code to check if an object is a string. If the object is a
319// heap object, its map's instance type is left in the scratch1 register.
320// If this is not needed, scratch1 and scratch2 may be the same register.
Steve Blocka7e24c12009-10-30 11:49:00 +0000321static void GenerateStringCheck(MacroAssembler* masm,
322 Register receiver,
323 Register scratch1,
324 Register scratch2,
325 Label* smi,
326 Label* non_string_object) {
327 // Check that the receiver isn't a smi.
328 __ tst(receiver, Operand(kSmiTagMask));
329 __ b(eq, smi);
330
331 // Check that the object is a string.
332 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
333 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
334 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
335 // The cast is to resolve the overload for the argument of 0x0.
336 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
337 __ b(ne, non_string_object);
338}
339
340
341// Generate code to load the length from a string object and return the length.
342// If the receiver object is not a string or a wrapped string object the
343// execution continues at the miss label. The register containing the
344// receiver is potentially clobbered.
Andrei Popescu402d9372010-02-26 13:31:12 +0000345void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
346 Register receiver,
347 Register scratch1,
348 Register scratch2,
349 Label* miss) {
350 Label check_wrapper;
Steve Blocka7e24c12009-10-30 11:49:00 +0000351
Steve Blocka7e24c12009-10-30 11:49:00 +0000352 // Check if the object is a string leaving the instance type in the
353 // scratch1 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000354 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
Steve Blocka7e24c12009-10-30 11:49:00 +0000355
356 // Load length directly from the string.
Steve Blocka7e24c12009-10-30 11:49:00 +0000357 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000358 __ Ret();
359
360 // Check if the object is a JSValue wrapper.
361 __ bind(&check_wrapper);
362 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
363 __ b(ne, miss);
364
Andrei Popescu402d9372010-02-26 13:31:12 +0000365 // Unwrap the value and check if the wrapped value is a string.
366 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
367 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
368 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
Andrei Popescu402d9372010-02-26 13:31:12 +0000369 __ Ret();
Steve Blocka7e24c12009-10-30 11:49:00 +0000370}
371
372
373void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
374 Register receiver,
375 Register scratch1,
376 Register scratch2,
377 Label* miss_label) {
378 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
379 __ mov(r0, scratch1);
380 __ Ret();
381}
382
383
384// Generate StoreField code, value is passed in r0 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000385// When leaving generated code after success, the receiver_reg and name_reg
386// may be clobbered. Upon branch to miss_label, the receiver and name
387// registers have their original values.
Steve Blocka7e24c12009-10-30 11:49:00 +0000388void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Steve Blocka7e24c12009-10-30 11:49:00 +0000389 JSObject* object,
390 int index,
391 Map* transition,
392 Register receiver_reg,
393 Register name_reg,
394 Register scratch,
395 Label* miss_label) {
396 // r0 : value
397 Label exit;
398
399 // Check that the receiver isn't a smi.
400 __ tst(receiver_reg, Operand(kSmiTagMask));
401 __ b(eq, miss_label);
402
403 // Check that the map of the receiver hasn't changed.
404 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
405 __ cmp(scratch, Operand(Handle<Map>(object->map())));
406 __ b(ne, miss_label);
407
408 // Perform global security token check if needed.
409 if (object->IsJSGlobalProxy()) {
410 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
411 }
412
413 // Stub never generated for non-global objects that require access
414 // checks.
415 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
416
417 // Perform map transition for the receiver if necessary.
418 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
419 // The properties must be extended before we can store the value.
420 // We jump to a runtime call that extends the properties array.
Andrei Popescu402d9372010-02-26 13:31:12 +0000421 __ push(receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000422 __ mov(r2, Operand(Handle<Map>(transition)));
Steve Block6ded16b2010-05-10 14:33:55 +0100423 __ Push(r2, r0);
424 __ TailCallExternalReference(
Andrei Popescu402d9372010-02-26 13:31:12 +0000425 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)),
426 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000427 return;
428 }
429
430 if (transition != NULL) {
431 // Update the map of the object; no write barrier updating is
432 // needed because the map is never in new space.
433 __ mov(ip, Operand(Handle<Map>(transition)));
434 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
435 }
436
437 // Adjust for the number of properties stored in the object. Even in the
438 // face of a transition we can use the old map here because the size of the
439 // object and the number of in-object properties is not going to change.
440 index -= object->map()->inobject_properties();
441
442 if (index < 0) {
443 // Set the property straight into the object.
444 int offset = object->map()->instance_size() + (index * kPointerSize);
445 __ str(r0, FieldMemOperand(receiver_reg, 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.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100452 // Pass the now unused name_reg as a scratch register.
453 __ RecordWrite(receiver_reg, Operand(offset), name_reg, scratch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000454 } else {
455 // Write to the properties array.
456 int offset = index * kPointerSize + FixedArray::kHeaderSize;
457 // Get the properties array
458 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
459 __ str(r0, FieldMemOperand(scratch, offset));
460
461 // Skip updating write barrier if storing a smi.
462 __ tst(r0, Operand(kSmiTagMask));
463 __ b(eq, &exit);
464
465 // Update the write barrier for the array address.
466 // Ok to clobber receiver_reg and name_reg, since we return.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100467 __ RecordWrite(scratch, Operand(offset), name_reg, receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000468 }
469
470 // Return the value (register r0).
471 __ bind(&exit);
472 __ Ret();
473}
474
475
476void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
477 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
478 Code* code = NULL;
479 if (kind == Code::LOAD_IC) {
480 code = Builtins::builtin(Builtins::LoadIC_Miss);
481 } else {
482 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
483 }
484
485 Handle<Code> ic(code);
486 __ Jump(ic, RelocInfo::CODE_TARGET);
487}
488
489
Leon Clarke4515c472010-02-03 11:58:03 +0000490static void GenerateCallFunction(MacroAssembler* masm,
491 Object* object,
492 const ParameterCount& arguments,
493 Label* miss) {
494 // ----------- S t a t e -------------
495 // -- r0: receiver
496 // -- r1: function to call
497 // -----------------------------------
498
499 // Check that the function really is a function.
500 __ BranchOnSmi(r1, miss);
Andrei Popescu402d9372010-02-26 13:31:12 +0000501 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
Leon Clarke4515c472010-02-03 11:58:03 +0000502 __ b(ne, miss);
503
504 // Patch the receiver on the stack with the global proxy if
505 // necessary.
506 if (object->IsGlobalObject()) {
507 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
508 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
509 }
510
511 // Invoke the function.
512 __ InvokeFunction(r1, arguments, JUMP_FUNCTION);
513}
514
515
Leon Clarke4515c472010-02-03 11:58:03 +0000516static void PushInterceptorArguments(MacroAssembler* masm,
517 Register receiver,
518 Register holder,
519 Register name,
520 JSObject* holder_obj) {
Leon Clarke4515c472010-02-03 11:58:03 +0000521 __ push(name);
522 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
523 ASSERT(!Heap::InNewSpace(interceptor));
Steve Block6ded16b2010-05-10 14:33:55 +0100524 Register scratch = name;
Leon Clarke4515c472010-02-03 11:58:03 +0000525 __ mov(scratch, Operand(Handle<Object>(interceptor)));
526 __ push(scratch);
Steve Block6ded16b2010-05-10 14:33:55 +0100527 __ push(receiver);
528 __ push(holder);
Leon Clarke4515c472010-02-03 11:58:03 +0000529 __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
530 __ push(scratch);
531}
532
533
534static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
535 Register receiver,
536 Register holder,
537 Register name,
538 JSObject* holder_obj) {
539 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
540
541 ExternalReference ref =
542 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
543 __ mov(r0, Operand(5));
544 __ mov(r1, Operand(ref));
545
546 CEntryStub stub(1);
547 __ CallStub(&stub);
548}
549
550
Steve Block6ded16b2010-05-10 14:33:55 +0100551// Reserves space for the extra arguments to FastHandleApiCall in the
552// caller's frame.
553//
554// These arguments are set by CheckPrototypes and GenerateFastApiCall.
555static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
556 Register scratch) {
557 __ mov(scratch, Operand(Smi::FromInt(0)));
558 __ push(scratch);
559 __ push(scratch);
560 __ push(scratch);
561 __ push(scratch);
562}
563
564
565// Undoes the effects of ReserveSpaceForFastApiCall.
566static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
567 __ Drop(4);
568}
569
570
571// Generates call to FastHandleApiCall builtin.
572static void GenerateFastApiCall(MacroAssembler* masm,
573 const CallOptimization& optimization,
574 int argc) {
575 // Get the function and setup the context.
576 JSFunction* function = optimization.constant_function();
577 __ mov(r7, Operand(Handle<JSFunction>(function)));
578 __ ldr(cp, FieldMemOperand(r7, JSFunction::kContextOffset));
579
580 // Pass the additional arguments FastHandleApiCall expects.
581 bool info_loaded = false;
582 Object* callback = optimization.api_call_info()->callback();
583 if (Heap::InNewSpace(callback)) {
584 info_loaded = true;
585 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
586 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
587 } else {
588 __ Move(r6, Handle<Object>(callback));
589 }
590 Object* call_data = optimization.api_call_info()->data();
591 if (Heap::InNewSpace(call_data)) {
592 if (!info_loaded) {
593 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
594 }
595 __ ldr(r5, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
596 } else {
597 __ Move(r5, Handle<Object>(call_data));
598 }
599
600 __ add(sp, sp, Operand(1 * kPointerSize));
601 __ stm(ia, sp, r5.bit() | r6.bit() | r7.bit());
602 __ sub(sp, sp, Operand(1 * kPointerSize));
603
604 // Set the number of arguments.
605 __ mov(r0, Operand(argc + 4));
606
607 // Jump to the fast api call builtin (tail call).
608 Handle<Code> code = Handle<Code>(
609 Builtins::builtin(Builtins::FastHandleApiCall));
610 ParameterCount expected(0);
611 __ InvokeCode(code, expected, expected,
612 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
613}
614
615
616class CallInterceptorCompiler BASE_EMBEDDED {
617 public:
618 CallInterceptorCompiler(StubCompiler* stub_compiler,
619 const ParameterCount& arguments,
620 Register name)
621 : stub_compiler_(stub_compiler),
622 arguments_(arguments),
623 name_(name) {}
624
625 void Compile(MacroAssembler* masm,
626 JSObject* object,
627 JSObject* holder,
628 String* name,
629 LookupResult* lookup,
630 Register receiver,
631 Register scratch1,
632 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100633 Register scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100634 Label* miss) {
635 ASSERT(holder->HasNamedInterceptor());
636 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
637
638 // Check that the receiver isn't a smi.
639 __ BranchOnSmi(receiver, miss);
640
641 CallOptimization optimization(lookup);
642
643 if (optimization.is_constant_call()) {
644 CompileCacheable(masm,
645 object,
646 receiver,
647 scratch1,
648 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100649 scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100650 holder,
651 lookup,
652 name,
653 optimization,
654 miss);
655 } else {
656 CompileRegular(masm,
657 object,
658 receiver,
659 scratch1,
660 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100661 scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100662 name,
663 holder,
664 miss);
665 }
666 }
667
668 private:
669 void CompileCacheable(MacroAssembler* masm,
670 JSObject* object,
671 Register receiver,
672 Register scratch1,
673 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100674 Register scratch3,
Leon Clarkef7060e22010-06-03 12:02:55 +0100675 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100676 LookupResult* lookup,
677 String* name,
678 const CallOptimization& optimization,
679 Label* miss_label) {
680 ASSERT(optimization.is_constant_call());
681 ASSERT(!lookup->holder()->IsGlobalObject());
682
683 int depth1 = kInvalidProtoDepth;
684 int depth2 = kInvalidProtoDepth;
685 bool can_do_fast_api_call = false;
686 if (optimization.is_simple_api_call() &&
687 !lookup->holder()->IsGlobalObject()) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100688 depth1 =
689 optimization.GetPrototypeDepthOfExpectedType(object,
690 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100691 if (depth1 == kInvalidProtoDepth) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100692 depth2 =
693 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
694 lookup->holder());
Steve Block6ded16b2010-05-10 14:33:55 +0100695 }
696 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
697 (depth2 != kInvalidProtoDepth);
698 }
699
700 __ IncrementCounter(&Counters::call_const_interceptor, 1,
701 scratch1, scratch2);
702
703 if (can_do_fast_api_call) {
704 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1,
705 scratch1, scratch2);
706 ReserveSpaceForFastApiCall(masm, scratch1);
707 }
708
Leon Clarkef7060e22010-06-03 12:02:55 +0100709 // Check that the maps from receiver to interceptor's holder
710 // haven't changed and thus we can invoke interceptor.
Steve Block6ded16b2010-05-10 14:33:55 +0100711 Label miss_cleanup;
712 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
713 Register holder =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100714 stub_compiler_->CheckPrototypes(object, receiver,
715 interceptor_holder, scratch1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100716 scratch2, scratch3, name, depth1, miss);
Steve Block6ded16b2010-05-10 14:33:55 +0100717
Leon Clarkef7060e22010-06-03 12:02:55 +0100718 // Invoke an interceptor and if it provides a value,
719 // branch to |regular_invoke|.
Steve Block6ded16b2010-05-10 14:33:55 +0100720 Label regular_invoke;
Leon Clarkef7060e22010-06-03 12:02:55 +0100721 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
Steve Block6ded16b2010-05-10 14:33:55 +0100722 &regular_invoke);
723
Leon Clarkef7060e22010-06-03 12:02:55 +0100724 // Interceptor returned nothing for this property. Try to use cached
725 // constant function.
Steve Block6ded16b2010-05-10 14:33:55 +0100726
Leon Clarkef7060e22010-06-03 12:02:55 +0100727 // Check that the maps from interceptor's holder to constant function's
728 // holder haven't changed and thus we can use cached constant function.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100729 if (interceptor_holder != lookup->holder()) {
730 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
731 lookup->holder(), scratch1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100732 scratch2, scratch3, name, depth2, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100733 } else {
734 // CheckPrototypes has a side effect of fetching a 'holder'
735 // for API (object which is instanceof for the signature). It's
736 // safe to omit it here, as if present, it should be fetched
737 // by the previous CheckPrototypes.
738 ASSERT(depth2 == kInvalidProtoDepth);
739 }
Steve Block6ded16b2010-05-10 14:33:55 +0100740
Leon Clarkef7060e22010-06-03 12:02:55 +0100741 // Invoke function.
Steve Block6ded16b2010-05-10 14:33:55 +0100742 if (can_do_fast_api_call) {
743 GenerateFastApiCall(masm, optimization, arguments_.immediate());
744 } else {
745 __ InvokeFunction(optimization.constant_function(), arguments_,
746 JUMP_FUNCTION);
747 }
748
Leon Clarkef7060e22010-06-03 12:02:55 +0100749 // Deferred code for fast API call case---clean preallocated space.
Steve Block6ded16b2010-05-10 14:33:55 +0100750 if (can_do_fast_api_call) {
751 __ bind(&miss_cleanup);
752 FreeSpaceForFastApiCall(masm);
753 __ b(miss_label);
754 }
755
Leon Clarkef7060e22010-06-03 12:02:55 +0100756 // Invoke a regular function.
Steve Block6ded16b2010-05-10 14:33:55 +0100757 __ bind(&regular_invoke);
758 if (can_do_fast_api_call) {
759 FreeSpaceForFastApiCall(masm);
760 }
761 }
762
763 void CompileRegular(MacroAssembler* masm,
764 JSObject* object,
765 Register receiver,
766 Register scratch1,
767 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100768 Register scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100769 String* name,
Leon Clarkef7060e22010-06-03 12:02:55 +0100770 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100771 Label* miss_label) {
772 Register holder =
Leon Clarkef7060e22010-06-03 12:02:55 +0100773 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100774 scratch1, scratch2, scratch3, name,
Steve Block6ded16b2010-05-10 14:33:55 +0100775 miss_label);
776
777 // Call a runtime function to load the interceptor property.
778 __ EnterInternalFrame();
779 // Save the name_ register across the call.
780 __ push(name_);
781
782 PushInterceptorArguments(masm,
783 receiver,
784 holder,
785 name_,
Leon Clarkef7060e22010-06-03 12:02:55 +0100786 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100787
788 __ CallExternalReference(
789 ExternalReference(
790 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
791 5);
792
793 // Restore the name_ register.
794 __ pop(name_);
795 __ LeaveInternalFrame();
796 }
797
798 void LoadWithInterceptor(MacroAssembler* masm,
799 Register receiver,
800 Register holder,
801 JSObject* holder_obj,
802 Register scratch,
803 Label* interceptor_succeeded) {
804 __ EnterInternalFrame();
805 __ Push(holder, name_);
806
807 CompileCallLoadPropertyWithInterceptor(masm,
808 receiver,
809 holder,
810 name_,
811 holder_obj);
812
813 __ pop(name_); // Restore the name.
814 __ pop(receiver); // Restore the holder.
815 __ LeaveInternalFrame();
816
817 // If interceptor returns no-result sentinel, call the constant function.
818 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
819 __ cmp(r0, scratch);
820 __ b(ne, interceptor_succeeded);
821 }
822
823 StubCompiler* stub_compiler_;
824 const ParameterCount& arguments_;
825 Register name_;
826};
827
828
829// Generate code to check that a global property cell is empty. Create
830// the property cell at compilation time if no cell exists for the
831// property.
832static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
833 GlobalObject* global,
834 String* name,
835 Register scratch,
836 Label* miss) {
837 Object* probe = global->EnsurePropertyCell(name);
838 if (probe->IsFailure()) return probe;
839 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
840 ASSERT(cell->value()->IsTheHole());
841 __ mov(scratch, Operand(Handle<Object>(cell)));
842 __ ldr(scratch,
843 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
844 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
845 __ cmp(scratch, ip);
846 __ b(ne, miss);
847 return cell;
848}
849
850
Steve Blocka7e24c12009-10-30 11:49:00 +0000851#undef __
852#define __ ACCESS_MASM(masm())
853
854
855Register StubCompiler::CheckPrototypes(JSObject* object,
856 Register object_reg,
857 JSObject* holder,
858 Register holder_reg,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100859 Register scratch1,
860 Register scratch2,
Steve Blocka7e24c12009-10-30 11:49:00 +0000861 String* name,
Andrei Popescu402d9372010-02-26 13:31:12 +0000862 int save_at_depth,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100863 Label* miss) {
864 // Make sure there's no overlap between holder and object registers.
865 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
866 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
867 && !scratch2.is(scratch1));
868
869 // Keep track of the current object in register reg.
870 Register reg = object_reg;
871 int depth = 0;
872
873 if (save_at_depth == depth) {
874 __ str(reg, MemOperand(sp));
875 }
876
877 // Check the maps in the prototype chain.
878 // Traverse the prototype chain from the object and do map checks.
879 JSObject* current = object;
880 while (current != holder) {
881 depth++;
882
883 // Only global objects and objects that do not require access
884 // checks are allowed in stubs.
885 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
886
887 JSObject* prototype = JSObject::cast(current->GetPrototype());
888 if (!current->HasFastProperties() &&
889 !current->IsJSGlobalObject() &&
890 !current->IsJSGlobalProxy()) {
891 if (!name->IsSymbol()) {
892 Object* lookup_result = Heap::LookupSymbol(name);
893 if (lookup_result->IsFailure()) {
894 set_failure(Failure::cast(lookup_result));
895 return reg;
896 } else {
897 name = String::cast(lookup_result);
898 }
899 }
900 ASSERT(current->property_dictionary()->FindEntry(name) ==
901 StringDictionary::kNotFound);
902
903 GenerateDictionaryNegativeLookup(masm(),
904 miss,
905 reg,
906 name,
907 scratch1,
908 scratch2);
909 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
910 reg = holder_reg; // from now the object is in holder_reg
911 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
912 } else {
913 // Get the map of the current object.
914 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
915 __ cmp(scratch1, Operand(Handle<Map>(current->map())));
916
917 // Branch on the result of the map check.
918 __ b(ne, miss);
919
920 // Check access rights to the global object. This has to happen
921 // after the map check so that we know that the object is
922 // actually a global object.
923 if (current->IsJSGlobalProxy()) {
924 __ CheckAccessGlobalProxy(reg, scratch1, miss);
925 // Restore scratch register to be the map of the object. In the
926 // new space case below, we load the prototype from the map in
927 // the scratch register.
928 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
929 }
930
931 reg = holder_reg; // from now the object is in holder_reg
932 if (Heap::InNewSpace(prototype)) {
933 // The prototype is in new space; we cannot store a reference
934 // to it in the code. Load it from the map.
935 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
936 } else {
937 // The prototype is in old space; load it directly.
938 __ mov(reg, Operand(Handle<JSObject>(prototype)));
939 }
940 }
941
942 if (save_at_depth == depth) {
943 __ str(reg, MemOperand(sp));
944 }
945
946 // Go to the next object in the prototype chain.
947 current = prototype;
948 }
949
950 // Check the holder map.
951 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
952 __ cmp(scratch1, Operand(Handle<Map>(current->map())));
953 __ b(ne, miss);
954
955 // Log the check depth.
956 LOG(IntEvent("check-maps-depth", depth + 1));
957
958 // Perform security check for access to the global object and return
959 // the holder register.
960 ASSERT(current == holder);
961 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
962 if (current->IsJSGlobalProxy()) {
963 __ CheckAccessGlobalProxy(reg, scratch1, miss);
964 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000965
966 // If we've skipped any global objects, it's not enough to verify
Steve Block6ded16b2010-05-10 14:33:55 +0100967 // that their maps haven't changed. We also need to check that the
968 // property cell for the property is still empty.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100969 current = object;
970 while (current != holder) {
971 if (current->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100972 Object* cell = GenerateCheckPropertyCell(masm(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100973 GlobalObject::cast(current),
Steve Block6ded16b2010-05-10 14:33:55 +0100974 name,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100975 scratch1,
Steve Block6ded16b2010-05-10 14:33:55 +0100976 miss);
977 if (cell->IsFailure()) {
978 set_failure(Failure::cast(cell));
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100979 return reg;
Steve Blocka7e24c12009-10-30 11:49:00 +0000980 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000981 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100982 current = JSObject::cast(current->GetPrototype());
Steve Blocka7e24c12009-10-30 11:49:00 +0000983 }
984
Andrei Popescu402d9372010-02-26 13:31:12 +0000985 // Return the register containing the holder.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100986 return reg;
Steve Blocka7e24c12009-10-30 11:49:00 +0000987}
988
989
990void StubCompiler::GenerateLoadField(JSObject* object,
991 JSObject* holder,
992 Register receiver,
993 Register scratch1,
994 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100995 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +0000996 int index,
997 String* name,
998 Label* miss) {
999 // Check that the receiver isn't a smi.
1000 __ tst(receiver, Operand(kSmiTagMask));
1001 __ b(eq, miss);
1002
1003 // Check that the maps haven't changed.
1004 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001005 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1006 name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001007 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
1008 __ Ret();
1009}
1010
1011
1012void StubCompiler::GenerateLoadConstant(JSObject* object,
1013 JSObject* holder,
1014 Register receiver,
1015 Register scratch1,
1016 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001017 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001018 Object* value,
1019 String* name,
1020 Label* miss) {
1021 // Check that the receiver isn't a smi.
1022 __ tst(receiver, Operand(kSmiTagMask));
1023 __ b(eq, miss);
1024
1025 // Check that the maps haven't changed.
1026 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001027 CheckPrototypes(object, receiver, holder,
1028 scratch1, scratch2, scratch3, name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001029
1030 // Return the constant value.
1031 __ mov(r0, Operand(Handle<Object>(value)));
1032 __ Ret();
1033}
1034
1035
Leon Clarkee46be812010-01-19 14:06:41 +00001036bool StubCompiler::GenerateLoadCallback(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001037 JSObject* holder,
1038 Register receiver,
1039 Register name_reg,
1040 Register scratch1,
1041 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001042 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001043 AccessorInfo* callback,
1044 String* name,
Leon Clarkee46be812010-01-19 14:06:41 +00001045 Label* miss,
1046 Failure** failure) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001047 // Check that the receiver isn't a smi.
1048 __ tst(receiver, Operand(kSmiTagMask));
1049 __ b(eq, miss);
1050
1051 // Check that the maps haven't changed.
1052 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001053 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1054 name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001055
1056 // Push the arguments on the JS stack of the caller.
Steve Block6ded16b2010-05-10 14:33:55 +01001057 __ push(receiver); // Receiver.
1058 __ push(reg); // Holder.
Steve Blocka7e24c12009-10-30 11:49:00 +00001059 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
Steve Blocka7e24c12009-10-30 11:49:00 +00001060 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
Steve Block6ded16b2010-05-10 14:33:55 +01001061 __ Push(ip, reg, name_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +00001062
1063 // Do tail-call to the runtime system.
1064 ExternalReference load_callback_property =
1065 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001066 __ TailCallExternalReference(load_callback_property, 5, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00001067
1068 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001069}
1070
1071
1072void StubCompiler::GenerateLoadInterceptor(JSObject* object,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001073 JSObject* interceptor_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +00001074 LookupResult* lookup,
1075 Register receiver,
1076 Register name_reg,
1077 Register scratch1,
1078 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001079 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 String* name,
1081 Label* miss) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001082 ASSERT(interceptor_holder->HasNamedInterceptor());
1083 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1084
1085 // Check that the receiver isn't a smi.
1086 __ BranchOnSmi(receiver, miss);
1087
1088 // So far the most popular follow ups for interceptor loads are FIELD
1089 // and CALLBACKS, so inline only them, other cases may be added
1090 // later.
1091 bool compile_followup_inline = false;
1092 if (lookup->IsProperty() && lookup->IsCacheable()) {
1093 if (lookup->type() == FIELD) {
1094 compile_followup_inline = true;
1095 } else if (lookup->type() == CALLBACKS &&
1096 lookup->GetCallbackObject()->IsAccessorInfo() &&
1097 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
1098 compile_followup_inline = true;
1099 }
1100 }
1101
1102 if (compile_followup_inline) {
1103 // Compile the interceptor call, followed by inline code to load the
1104 // property from further up the prototype chain if the call fails.
1105 // Check that the maps haven't changed.
1106 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001107 scratch1, scratch2, scratch3,
1108 name, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001109 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1110
1111 // Save necessary data before invoking an interceptor.
1112 // Requires a frame to make GC aware of pushed pointers.
1113 __ EnterInternalFrame();
1114
1115 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1116 // CALLBACKS case needs a receiver to be passed into C++ callback.
1117 __ Push(receiver, holder_reg, name_reg);
1118 } else {
1119 __ Push(holder_reg, name_reg);
1120 }
1121
1122 // Invoke an interceptor. Note: map checks from receiver to
1123 // interceptor's holder has been compiled before (see a caller
1124 // of this method.)
1125 CompileCallLoadPropertyWithInterceptor(masm(),
1126 receiver,
1127 holder_reg,
1128 name_reg,
1129 interceptor_holder);
1130
1131 // Check if interceptor provided a value for property. If it's
1132 // the case, return immediately.
1133 Label interceptor_failed;
1134 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1135 __ cmp(r0, scratch1);
1136 __ b(eq, &interceptor_failed);
1137 __ LeaveInternalFrame();
1138 __ Ret();
1139
1140 __ bind(&interceptor_failed);
1141 __ pop(name_reg);
1142 __ pop(holder_reg);
1143 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1144 __ pop(receiver);
1145 }
1146
1147 __ LeaveInternalFrame();
1148
1149 // Check that the maps from interceptor's holder to lookup's holder
1150 // haven't changed. And load lookup's holder into |holder| register.
1151 if (interceptor_holder != lookup->holder()) {
1152 holder_reg = CheckPrototypes(interceptor_holder,
1153 holder_reg,
1154 lookup->holder(),
1155 scratch1,
1156 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001157 scratch3,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001158 name,
1159 miss);
1160 }
1161
1162 if (lookup->type() == FIELD) {
1163 // We found FIELD property in prototype chain of interceptor's holder.
1164 // Retrieve a field from field's holder.
1165 GenerateFastPropertyLoad(masm(), r0, holder_reg,
1166 lookup->holder(), lookup->GetFieldIndex());
1167 __ Ret();
1168 } else {
1169 // We found CALLBACKS property in prototype chain of interceptor's
1170 // holder.
1171 ASSERT(lookup->type() == CALLBACKS);
1172 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
1173 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1174 ASSERT(callback != NULL);
1175 ASSERT(callback->getter() != NULL);
1176
1177 // Tail call to runtime.
1178 // Important invariant in CALLBACKS case: the code above must be
1179 // structured to never clobber |receiver| register.
1180 __ Move(scratch2, Handle<AccessorInfo>(callback));
1181 // holder_reg is either receiver or scratch1.
1182 if (!receiver.is(holder_reg)) {
1183 ASSERT(scratch1.is(holder_reg));
1184 __ Push(receiver, holder_reg, scratch2);
1185 __ ldr(scratch1,
1186 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
1187 __ Push(scratch1, name_reg);
1188 } else {
1189 __ push(receiver);
1190 __ ldr(scratch1,
1191 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
1192 __ Push(holder_reg, scratch2, scratch1, name_reg);
1193 }
1194
1195 ExternalReference ref =
1196 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
1197 __ TailCallExternalReference(ref, 5, 1);
1198 }
1199 } else { // !compile_followup_inline
1200 // Call the runtime system to load the interceptor.
1201 // Check that the maps haven't changed.
1202 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001203 scratch1, scratch2, scratch3,
1204 name, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001205 PushInterceptorArguments(masm(), receiver, holder_reg,
1206 name_reg, interceptor_holder);
1207
1208 ExternalReference ref = ExternalReference(
1209 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
1210 __ TailCallExternalReference(ref, 5, 1);
1211 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001212}
1213
1214
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001215void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
1216 if (kind_ == Code::KEYED_CALL_IC) {
1217 __ cmp(r2, Operand(Handle<String>(name)));
1218 __ b(ne, miss);
1219 }
1220}
1221
1222
Steve Block59151502010-09-22 15:07:15 +01001223void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
1224 JSObject* holder,
1225 String* name,
1226 Label* miss) {
1227 ASSERT(holder->IsGlobalObject());
1228
1229 // Get the number of arguments.
1230 const int argc = arguments().immediate();
1231
1232 // Get the receiver from the stack.
1233 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1234
1235 // If the object is the holder then we know that it's a global
1236 // object which can only happen for contextual calls. In this case,
1237 // the receiver cannot be a smi.
1238 if (object != holder) {
1239 __ tst(r0, Operand(kSmiTagMask));
1240 __ b(eq, miss);
1241 }
1242
1243 // Check that the maps haven't changed.
1244 CheckPrototypes(object, r0, holder, r3, r1, r4, name, miss);
1245}
1246
1247
1248void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
1249 JSFunction* function,
1250 Label* miss) {
1251 // Get the value from the cell.
1252 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1253 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1254
1255 // Check that the cell contains the same function.
1256 if (Heap::InNewSpace(function)) {
1257 // We can't embed a pointer to a function in new space so we have
1258 // to verify that the shared function info is unchanged. This has
1259 // the nice side effect that multiple closures based on the same
1260 // function can all use this call IC. Before we load through the
1261 // function, we have to verify that it still is a function.
1262 __ tst(r1, Operand(kSmiTagMask));
1263 __ b(eq, miss);
1264 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1265 __ b(ne, miss);
1266
1267 // Check the shared function info. Make sure it hasn't changed.
1268 __ Move(r3, Handle<SharedFunctionInfo>(function->shared()));
1269 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1270 __ cmp(r4, r3);
1271 __ b(ne, miss);
1272 } else {
1273 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1274 __ b(ne, miss);
1275 }
1276}
1277
1278
Ben Murdochbb769b22010-08-11 14:56:33 +01001279Object* CallStubCompiler::GenerateMissBranch() {
1280 Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
1281 if (obj->IsFailure()) return obj;
1282 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1283 return obj;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001284}
1285
1286
Andrei Popescu402d9372010-02-26 13:31:12 +00001287Object* CallStubCompiler::CompileCallField(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001288 JSObject* holder,
1289 int index,
1290 String* name) {
1291 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001292 // -- r2 : name
1293 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001294 // -----------------------------------
1295 Label miss;
1296
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001297 GenerateNameCheck(name, &miss);
1298
Steve Blocka7e24c12009-10-30 11:49:00 +00001299 const int argc = arguments().immediate();
1300
1301 // Get the receiver of the function from the stack into r0.
1302 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1303 // Check that the receiver isn't a smi.
1304 __ tst(r0, Operand(kSmiTagMask));
1305 __ b(eq, &miss);
1306
1307 // Do the right check and compute the holder register.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001308 Register reg = CheckPrototypes(object, r0, holder, r1, r3, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001309 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
1310
Leon Clarke4515c472010-02-03 11:58:03 +00001311 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001312
1313 // Handle call cache miss.
1314 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001315 Object* obj = GenerateMissBranch();
1316 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001317
1318 // Return the generated code.
1319 return GetCode(FIELD, name);
1320}
1321
1322
Steve Block6ded16b2010-05-10 14:33:55 +01001323Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1324 JSObject* holder,
Steve Block59151502010-09-22 15:07:15 +01001325 JSGlobalPropertyCell* cell,
Steve Block6ded16b2010-05-10 14:33:55 +01001326 JSFunction* function,
Steve Block59151502010-09-22 15:07:15 +01001327 String* name) {
Steve Block6ded16b2010-05-10 14:33:55 +01001328 // ----------- S t a t e -------------
1329 // -- r2 : name
1330 // -- lr : return address
1331 // -----------------------------------
1332
Steve Block6ded16b2010-05-10 14:33:55 +01001333 // TODO(639): faster implementation.
Steve Block59151502010-09-22 15:07:15 +01001334
1335 // If object is not an array, bail out to regular call.
1336 if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001337
1338 Label miss;
1339
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001340 GenerateNameCheck(name, &miss);
1341
Steve Block6ded16b2010-05-10 14:33:55 +01001342 // Get the receiver from the stack
1343 const int argc = arguments().immediate();
1344 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1345
1346 // Check that the receiver isn't a smi.
1347 __ tst(r1, Operand(kSmiTagMask));
1348 __ b(eq, &miss);
1349
1350 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001351 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001352
Steve Block6ded16b2010-05-10 14:33:55 +01001353 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1354 argc + 1,
1355 1);
1356
1357 // Handle call cache miss.
1358 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001359 Object* obj = GenerateMissBranch();
1360 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +01001361
1362 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001363 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001364}
1365
1366
1367Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1368 JSObject* holder,
Steve Block59151502010-09-22 15:07:15 +01001369 JSGlobalPropertyCell* cell,
Steve Block6ded16b2010-05-10 14:33:55 +01001370 JSFunction* function,
Steve Block59151502010-09-22 15:07:15 +01001371 String* name) {
Steve Block6ded16b2010-05-10 14:33:55 +01001372 // ----------- S t a t e -------------
1373 // -- r2 : name
1374 // -- lr : return address
1375 // -----------------------------------
1376
Steve Block6ded16b2010-05-10 14:33:55 +01001377 // TODO(642): faster implementation.
Steve Block59151502010-09-22 15:07:15 +01001378
1379 // If object is not an array, bail out to regular call.
1380 if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001381
1382 Label miss;
1383
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001384 GenerateNameCheck(name, &miss);
1385
Steve Block6ded16b2010-05-10 14:33:55 +01001386 // Get the receiver from the stack
1387 const int argc = arguments().immediate();
1388 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1389
1390 // Check that the receiver isn't a smi.
1391 __ tst(r1, Operand(kSmiTagMask));
1392 __ b(eq, &miss);
1393
1394 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001395 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001396
Steve Block6ded16b2010-05-10 14:33:55 +01001397 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1398 argc + 1,
1399 1);
1400
1401 // Handle call cache miss.
1402 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001403 Object* obj = GenerateMissBranch();
1404 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +01001405
1406 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001407 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001408}
1409
1410
Steve Block59151502010-09-22 15:07:15 +01001411Object* CallStubCompiler::CompileStringCharCodeAtCall(
1412 Object* object,
1413 JSObject* holder,
1414 JSGlobalPropertyCell* cell,
1415 JSFunction* function,
1416 String* name) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001417 // ----------- S t a t e -------------
1418 // -- r2 : function name
1419 // -- lr : return address
1420 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1421 // -- ...
1422 // -- sp[argc * 4] : receiver
1423 // -----------------------------------
1424
1425 // If object is not a string, bail out to regular call.
Steve Block59151502010-09-22 15:07:15 +01001426 if (!object->IsString() || cell != NULL) return Heap::undefined_value();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001427
1428 const int argc = arguments().immediate();
1429
1430 Label miss;
1431 Label index_out_of_range;
1432 GenerateNameCheck(name, &miss);
1433
1434 // Check that the maps starting from the prototype haven't changed.
1435 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1436 Context::STRING_FUNCTION_INDEX,
1437 r0);
1438 ASSERT(object != holder);
1439 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder,
1440 r1, r3, r4, name, &miss);
1441
1442 Register receiver = r1;
1443 Register index = r4;
1444 Register scratch = r3;
1445 Register result = r0;
1446 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
1447 if (argc > 0) {
1448 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
1449 } else {
1450 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1451 }
1452
1453 StringCharCodeAtGenerator char_code_at_generator(receiver,
1454 index,
1455 scratch,
1456 result,
1457 &miss, // When not a string.
1458 &miss, // When not a number.
1459 &index_out_of_range,
1460 STRING_INDEX_IS_NUMBER);
1461 char_code_at_generator.GenerateFast(masm());
1462 __ Drop(argc + 1);
1463 __ Ret();
1464
1465 ICRuntimeCallHelper call_helper;
1466 char_code_at_generator.GenerateSlow(masm(), call_helper);
1467
1468 __ bind(&index_out_of_range);
1469 __ LoadRoot(r0, Heap::kNanValueRootIndex);
1470 __ Drop(argc + 1);
1471 __ Ret();
1472
1473 __ bind(&miss);
1474 Object* obj = GenerateMissBranch();
1475 if (obj->IsFailure()) return obj;
1476
1477 // Return the generated code.
1478 return GetCode(function);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001479}
1480
1481
1482Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
1483 JSObject* holder,
Steve Block59151502010-09-22 15:07:15 +01001484 JSGlobalPropertyCell* cell,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001485 JSFunction* function,
Steve Block59151502010-09-22 15:07:15 +01001486 String* name) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001487 // ----------- S t a t e -------------
1488 // -- r2 : function name
1489 // -- lr : return address
1490 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1491 // -- ...
1492 // -- sp[argc * 4] : receiver
1493 // -----------------------------------
1494
1495 // If object is not a string, bail out to regular call.
Steve Block59151502010-09-22 15:07:15 +01001496 if (!object->IsString() || cell != NULL) return Heap::undefined_value();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001497
1498 const int argc = arguments().immediate();
1499
1500 Label miss;
1501 Label index_out_of_range;
1502
1503 GenerateNameCheck(name, &miss);
1504
1505 // Check that the maps starting from the prototype haven't changed.
1506 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1507 Context::STRING_FUNCTION_INDEX,
1508 r0);
1509 ASSERT(object != holder);
1510 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder,
1511 r1, r3, r4, name, &miss);
1512
1513 Register receiver = r0;
1514 Register index = r4;
1515 Register scratch1 = r1;
1516 Register scratch2 = r3;
1517 Register result = r0;
1518 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
1519 if (argc > 0) {
1520 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
1521 } else {
1522 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1523 }
1524
1525 StringCharAtGenerator char_at_generator(receiver,
1526 index,
1527 scratch1,
1528 scratch2,
1529 result,
1530 &miss, // When not a string.
1531 &miss, // When not a number.
1532 &index_out_of_range,
1533 STRING_INDEX_IS_NUMBER);
1534 char_at_generator.GenerateFast(masm());
1535 __ Drop(argc + 1);
1536 __ Ret();
1537
1538 ICRuntimeCallHelper call_helper;
1539 char_at_generator.GenerateSlow(masm(), call_helper);
1540
1541 __ bind(&index_out_of_range);
1542 __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
1543 __ Drop(argc + 1);
1544 __ Ret();
1545
1546 __ bind(&miss);
1547 Object* obj = GenerateMissBranch();
1548 if (obj->IsFailure()) return obj;
1549
1550 // Return the generated code.
1551 return GetCode(function);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001552}
1553
1554
Steve Block59151502010-09-22 15:07:15 +01001555Object* CallStubCompiler::CompileStringFromCharCodeCall(
1556 Object* object,
1557 JSObject* holder,
1558 JSGlobalPropertyCell* cell,
1559 JSFunction* function,
1560 String* name) {
1561 // ----------- S t a t e -------------
1562 // -- r2 : function name
1563 // -- lr : return address
1564 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1565 // -- ...
1566 // -- sp[argc * 4] : receiver
1567 // -----------------------------------
1568
1569 const int argc = arguments().immediate();
1570
1571 // If the object is not a JSObject or we got an unexpected number of
1572 // arguments, bail out to the regular call.
1573 if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
1574
1575 Label miss;
1576 GenerateNameCheck(name, &miss);
1577
1578 if (cell == NULL) {
1579 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
1580
1581 STATIC_ASSERT(kSmiTag == 0);
1582 __ tst(r1, Operand(kSmiTagMask));
1583 __ b(eq, &miss);
1584
1585 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
1586 &miss);
1587 } else {
1588 ASSERT(cell->value() == function);
1589 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
1590 GenerateLoadFunctionFromCell(cell, function, &miss);
1591 }
1592
1593 // Load the char code argument.
1594 Register code = r1;
1595 __ ldr(code, MemOperand(sp, 0 * kPointerSize));
1596
1597 // Check the code is a smi.
1598 Label slow;
1599 STATIC_ASSERT(kSmiTag == 0);
1600 __ tst(code, Operand(kSmiTagMask));
1601 __ b(ne, &slow);
1602
1603 // Convert the smi code to uint16.
1604 __ and_(code, code, Operand(Smi::FromInt(0xffff)));
1605
1606 StringCharFromCodeGenerator char_from_code_generator(code, r0);
1607 char_from_code_generator.GenerateFast(masm());
1608 __ Drop(argc + 1);
1609 __ Ret();
1610
1611 ICRuntimeCallHelper call_helper;
1612 char_from_code_generator.GenerateSlow(masm(), call_helper);
1613
1614 // Tail call the full function. We do not have to patch the receiver
1615 // because the function makes no use of it.
1616 __ bind(&slow);
1617 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1618
1619 __ bind(&miss);
1620 // r2: function name.
1621 Object* obj = GenerateMissBranch();
1622 if (obj->IsFailure()) return obj;
1623
1624 // Return the generated code.
1625 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
1626}
1627
1628
Steve Blocka7e24c12009-10-30 11:49:00 +00001629Object* CallStubCompiler::CompileCallConstant(Object* object,
1630 JSObject* holder,
1631 JSFunction* function,
1632 String* name,
1633 CheckType check) {
1634 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001635 // -- r2 : name
1636 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001637 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001638 SharedFunctionInfo* function_info = function->shared();
1639 if (function_info->HasCustomCallGenerator()) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001640 const int id = function_info->custom_call_generator_id();
Steve Block59151502010-09-22 15:07:15 +01001641 Object* result = CompileCustomCall(
1642 id, object, holder, NULL, function, name);
Steve Block6ded16b2010-05-10 14:33:55 +01001643 // undefined means bail out to regular compiler.
1644 if (!result->IsUndefined()) {
1645 return result;
1646 }
1647 }
1648
1649 Label miss_in_smi_check;
Steve Blocka7e24c12009-10-30 11:49:00 +00001650
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001651 GenerateNameCheck(name, &miss_in_smi_check);
1652
Steve Blocka7e24c12009-10-30 11:49:00 +00001653 // Get the receiver from the stack
1654 const int argc = arguments().immediate();
1655 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1656
1657 // Check that the receiver isn't a smi.
1658 if (check != NUMBER_CHECK) {
1659 __ tst(r1, Operand(kSmiTagMask));
Steve Block6ded16b2010-05-10 14:33:55 +01001660 __ b(eq, &miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001661 }
1662
1663 // Make sure that it's okay not to patch the on stack receiver
1664 // unless we're doing a receiver map check.
1665 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1666
Steve Block6ded16b2010-05-10 14:33:55 +01001667 CallOptimization optimization(function);
1668 int depth = kInvalidProtoDepth;
1669 Label miss;
1670
Steve Blocka7e24c12009-10-30 11:49:00 +00001671 switch (check) {
1672 case RECEIVER_MAP_CHECK:
Steve Block6ded16b2010-05-10 14:33:55 +01001673 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1674
1675 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1676 depth = optimization.GetPrototypeDepthOfExpectedType(
1677 JSObject::cast(object), holder);
1678 }
1679
1680 if (depth != kInvalidProtoDepth) {
1681 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1682 ReserveSpaceForFastApiCall(masm(), r0);
1683 }
1684
Steve Blocka7e24c12009-10-30 11:49:00 +00001685 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001686 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
Steve Block6ded16b2010-05-10 14:33:55 +01001687 depth, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001688
1689 // Patch the receiver on the stack with the global proxy if
1690 // necessary.
1691 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001692 ASSERT(depth == kInvalidProtoDepth);
Steve Blocka7e24c12009-10-30 11:49:00 +00001693 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1694 __ str(r3, MemOperand(sp, argc * kPointerSize));
1695 }
1696 break;
1697
1698 case STRING_CHECK:
Leon Clarkee46be812010-01-19 14:06:41 +00001699 if (!function->IsBuiltin()) {
1700 // Calling non-builtins with a value as receiver requires boxing.
1701 __ jmp(&miss);
1702 } else {
1703 // Check that the object is a two-byte string or a symbol.
Andrei Popescu402d9372010-02-26 13:31:12 +00001704 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001705 __ b(hs, &miss);
1706 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001707 GenerateDirectLoadGlobalFunctionPrototype(
1708 masm(), Context::STRING_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001709 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001710 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001711 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001712 break;
1713
1714 case NUMBER_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001715 if (!function->IsBuiltin()) {
1716 // Calling non-builtins with a value as receiver requires boxing.
1717 __ jmp(&miss);
1718 } else {
1719 Label fast;
1720 // Check that the object is a smi or a heap number.
1721 __ tst(r1, Operand(kSmiTagMask));
1722 __ b(eq, &fast);
Andrei Popescu402d9372010-02-26 13:31:12 +00001723 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001724 __ b(ne, &miss);
1725 __ bind(&fast);
1726 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001727 GenerateDirectLoadGlobalFunctionPrototype(
1728 masm(), Context::NUMBER_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001729 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001730 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001731 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001732 break;
1733 }
1734
1735 case BOOLEAN_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001736 if (!function->IsBuiltin()) {
1737 // Calling non-builtins with a value as receiver requires boxing.
1738 __ jmp(&miss);
1739 } else {
1740 Label fast;
1741 // Check that the object is a boolean.
1742 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1743 __ cmp(r1, ip);
1744 __ b(eq, &fast);
1745 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1746 __ cmp(r1, ip);
1747 __ b(ne, &miss);
1748 __ bind(&fast);
1749 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001750 GenerateDirectLoadGlobalFunctionPrototype(
1751 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001752 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001753 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001754 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001755 break;
1756 }
1757
Steve Blocka7e24c12009-10-30 11:49:00 +00001758 default:
1759 UNREACHABLE();
1760 }
1761
Steve Block6ded16b2010-05-10 14:33:55 +01001762 if (depth != kInvalidProtoDepth) {
1763 GenerateFastApiCall(masm(), optimization, argc);
1764 } else {
1765 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1766 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001767
1768 // Handle call cache miss.
1769 __ bind(&miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001770 if (depth != kInvalidProtoDepth) {
1771 FreeSpaceForFastApiCall(masm());
1772 }
1773
1774 __ bind(&miss_in_smi_check);
Ben Murdochbb769b22010-08-11 14:56:33 +01001775 Object* obj = GenerateMissBranch();
1776 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001777
1778 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001779 return GetCode(function);
Steve Blocka7e24c12009-10-30 11:49:00 +00001780}
1781
1782
Andrei Popescu402d9372010-02-26 13:31:12 +00001783Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001784 JSObject* holder,
1785 String* name) {
1786 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001787 // -- r2 : name
1788 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001789 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001790
Steve Block6ded16b2010-05-10 14:33:55 +01001791 Label miss;
Andrei Popescu402d9372010-02-26 13:31:12 +00001792
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001793 GenerateNameCheck(name, &miss);
1794
Leon Clarke4515c472010-02-03 11:58:03 +00001795 // Get the number of arguments.
1796 const int argc = arguments().immediate();
1797
1798 LookupResult lookup;
1799 LookupPostInterceptor(holder, name, &lookup);
1800
Steve Block6ded16b2010-05-10 14:33:55 +01001801 // Get the receiver from the stack.
1802 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001803
Steve Block6ded16b2010-05-10 14:33:55 +01001804 CallInterceptorCompiler compiler(this, arguments(), r2);
1805 compiler.Compile(masm(),
1806 object,
1807 holder,
1808 name,
1809 &lookup,
1810 r1,
1811 r3,
1812 r4,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001813 r0,
Steve Block6ded16b2010-05-10 14:33:55 +01001814 &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001815
1816 // Move returned value, the function to call, to r1.
1817 __ mov(r1, r0);
Leon Clarke4515c472010-02-03 11:58:03 +00001818 // Restore receiver.
Steve Block6ded16b2010-05-10 14:33:55 +01001819 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001820
1821 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001822
1823 // Handle call cache miss.
1824 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001825 Object* obj = GenerateMissBranch();
1826 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001827
1828 // Return the generated code.
1829 return GetCode(INTERCEPTOR, name);
1830}
1831
1832
1833Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1834 GlobalObject* holder,
1835 JSGlobalPropertyCell* cell,
1836 JSFunction* function,
1837 String* name) {
1838 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001839 // -- r2 : name
1840 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001841 // -----------------------------------
Steve Block59151502010-09-22 15:07:15 +01001842
1843 SharedFunctionInfo* function_info = function->shared();
1844 if (function_info->HasCustomCallGenerator()) {
1845 const int id = function_info->custom_call_generator_id();
1846 Object* result = CompileCustomCall(
1847 id, object, holder, cell, function, name);
1848 // undefined means bail out to regular compiler.
1849 if (!result->IsUndefined()) return result;
1850 }
1851
Steve Blocka7e24c12009-10-30 11:49:00 +00001852 Label miss;
1853
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001854 GenerateNameCheck(name, &miss);
1855
Steve Blocka7e24c12009-10-30 11:49:00 +00001856 // Get the number of arguments.
1857 const int argc = arguments().immediate();
1858
Steve Block59151502010-09-22 15:07:15 +01001859 GenerateGlobalReceiverCheck(object, holder, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001860
Steve Block59151502010-09-22 15:07:15 +01001861 GenerateLoadFunctionFromCell(cell, function, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001862
1863 // Patch the receiver on the stack with the global proxy if
1864 // necessary.
1865 if (object->IsGlobalObject()) {
1866 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1867 __ str(r3, MemOperand(sp, argc * kPointerSize));
1868 }
1869
1870 // Setup the context (function already in r1).
1871 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1872
1873 // Jump to the cached code (tail call).
Steve Block6ded16b2010-05-10 14:33:55 +01001874 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001875 ASSERT(function->is_compiled());
1876 Handle<Code> code(function->code());
1877 ParameterCount expected(function->shared()->formal_parameter_count());
1878 __ InvokeCode(code, expected, arguments(),
1879 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1880
1881 // Handle call cache miss.
1882 __ bind(&miss);
1883 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
Ben Murdochbb769b22010-08-11 14:56:33 +01001884 Object* obj = GenerateMissBranch();
1885 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001886
1887 // Return the generated code.
1888 return GetCode(NORMAL, name);
1889}
1890
1891
1892Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1893 int index,
1894 Map* transition,
1895 String* name) {
1896 // ----------- S t a t e -------------
1897 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001898 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001899 // -- r2 : name
1900 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001901 // -----------------------------------
1902 Label miss;
1903
Steve Blocka7e24c12009-10-30 11:49:00 +00001904 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001905 object,
1906 index,
1907 transition,
Andrei Popescu402d9372010-02-26 13:31:12 +00001908 r1, r2, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001909 &miss);
1910 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001911 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1912 __ Jump(ic, RelocInfo::CODE_TARGET);
1913
1914 // Return the generated code.
1915 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1916}
1917
1918
1919Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1920 AccessorInfo* callback,
1921 String* name) {
1922 // ----------- S t a t e -------------
1923 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001924 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001925 // -- r2 : name
1926 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001927 // -----------------------------------
1928 Label miss;
1929
Steve Blocka7e24c12009-10-30 11:49:00 +00001930 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001931 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001932 __ b(eq, &miss);
1933
1934 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001935 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1936 __ cmp(r3, Operand(Handle<Map>(object->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001937 __ b(ne, &miss);
1938
1939 // Perform global security token check if needed.
1940 if (object->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001941 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001942 }
1943
1944 // Stub never generated for non-global objects that require access
1945 // checks.
1946 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1947
Andrei Popescu402d9372010-02-26 13:31:12 +00001948 __ push(r1); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001949 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
Steve Block6ded16b2010-05-10 14:33:55 +01001950 __ Push(ip, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001951
1952 // Do tail-call to the runtime system.
1953 ExternalReference store_callback_property =
1954 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001955 __ TailCallExternalReference(store_callback_property, 4, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001956
1957 // Handle store cache miss.
1958 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001959 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1960 __ Jump(ic, RelocInfo::CODE_TARGET);
1961
1962 // Return the generated code.
1963 return GetCode(CALLBACKS, name);
1964}
1965
1966
1967Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1968 String* name) {
1969 // ----------- S t a t e -------------
1970 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001971 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001972 // -- r2 : name
1973 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001974 // -----------------------------------
1975 Label miss;
1976
Steve Blocka7e24c12009-10-30 11:49:00 +00001977 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001978 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001979 __ b(eq, &miss);
1980
1981 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001982 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1983 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001984 __ b(ne, &miss);
1985
1986 // Perform global security token check if needed.
1987 if (receiver->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001988 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001989 }
1990
Andrei Popescu402d9372010-02-26 13:31:12 +00001991 // Stub is never generated for non-global objects that require access
Steve Blocka7e24c12009-10-30 11:49:00 +00001992 // checks.
1993 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1994
Steve Block6ded16b2010-05-10 14:33:55 +01001995 __ Push(r1, r2, r0); // Receiver, name, value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001996
1997 // Do tail-call to the runtime system.
1998 ExternalReference store_ic_property =
1999 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01002000 __ TailCallExternalReference(store_ic_property, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002001
2002 // Handle store cache miss.
2003 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002004 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2005 __ Jump(ic, RelocInfo::CODE_TARGET);
2006
2007 // Return the generated code.
2008 return GetCode(INTERCEPTOR, name);
2009}
2010
2011
2012Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
2013 JSGlobalPropertyCell* cell,
2014 String* name) {
2015 // ----------- S t a t e -------------
2016 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00002017 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002018 // -- r2 : name
2019 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002020 // -----------------------------------
2021 Label miss;
2022
2023 // Check that the map of the global has not changed.
Steve Blocka7e24c12009-10-30 11:49:00 +00002024 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
2025 __ cmp(r3, Operand(Handle<Map>(object->map())));
2026 __ b(ne, &miss);
2027
2028 // Store the value in the cell.
2029 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
2030 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
2031
Andrei Popescu402d9372010-02-26 13:31:12 +00002032 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00002033 __ Ret();
2034
2035 // Handle store cache miss.
2036 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00002037 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00002038 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2039 __ Jump(ic, RelocInfo::CODE_TARGET);
2040
2041 // Return the generated code.
2042 return GetCode(NORMAL, name);
2043}
2044
2045
Steve Block6ded16b2010-05-10 14:33:55 +01002046Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
2047 JSObject* object,
2048 JSObject* last) {
2049 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002050 // -- r0 : receiver
Steve Block6ded16b2010-05-10 14:33:55 +01002051 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002052 // -----------------------------------
2053 Label miss;
2054
Steve Block6ded16b2010-05-10 14:33:55 +01002055 // Check that receiver is not a smi.
2056 __ tst(r0, Operand(kSmiTagMask));
2057 __ b(eq, &miss);
2058
2059 // Check the maps of the full prototype chain.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002060 CheckPrototypes(object, r0, last, r3, r1, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01002061
2062 // If the last object in the prototype chain is a global object,
2063 // check that the global property cell is empty.
2064 if (last->IsGlobalObject()) {
2065 Object* cell = GenerateCheckPropertyCell(masm(),
2066 GlobalObject::cast(last),
2067 name,
2068 r1,
2069 &miss);
2070 if (cell->IsFailure()) return cell;
2071 }
2072
2073 // Return undefined if maps of the full prototype chain are still the
2074 // same and no global property with this name contains a value.
2075 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
2076 __ Ret();
2077
2078 __ bind(&miss);
2079 GenerateLoadMiss(masm(), Code::LOAD_IC);
2080
2081 // Return the generated code.
2082 return GetCode(NONEXISTENT, Heap::empty_string());
2083}
2084
2085
Steve Blocka7e24c12009-10-30 11:49:00 +00002086Object* LoadStubCompiler::CompileLoadField(JSObject* object,
2087 JSObject* holder,
2088 int index,
2089 String* name) {
2090 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002091 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002092 // -- r2 : name
2093 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002094 // -----------------------------------
2095 Label miss;
2096
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002097 GenerateLoadField(object, holder, r0, r3, r1, r4, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002098 __ bind(&miss);
2099 GenerateLoadMiss(masm(), Code::LOAD_IC);
2100
2101 // Return the generated code.
2102 return GetCode(FIELD, name);
2103}
2104
2105
Leon Clarkee46be812010-01-19 14:06:41 +00002106Object* LoadStubCompiler::CompileLoadCallback(String* name,
2107 JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00002108 JSObject* holder,
Leon Clarkee46be812010-01-19 14:06:41 +00002109 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002110 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002111 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002112 // -- r2 : name
2113 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002114 // -----------------------------------
2115 Label miss;
2116
Leon Clarkee46be812010-01-19 14:06:41 +00002117 Failure* failure = Failure::InternalError();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002118 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1, r4,
Leon Clarkee46be812010-01-19 14:06:41 +00002119 callback, name, &miss, &failure);
2120 if (!success) return failure;
2121
Steve Blocka7e24c12009-10-30 11:49:00 +00002122 __ bind(&miss);
2123 GenerateLoadMiss(masm(), Code::LOAD_IC);
2124
2125 // Return the generated code.
2126 return GetCode(CALLBACKS, name);
2127}
2128
2129
2130Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
2131 JSObject* holder,
2132 Object* value,
2133 String* name) {
2134 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002135 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002136 // -- r2 : name
2137 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002138 // -----------------------------------
2139 Label miss;
2140
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002141 GenerateLoadConstant(object, holder, r0, r3, r1, r4, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002142 __ bind(&miss);
2143 GenerateLoadMiss(masm(), Code::LOAD_IC);
2144
2145 // Return the generated code.
2146 return GetCode(CONSTANT_FUNCTION, name);
2147}
2148
2149
2150Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
2151 JSObject* holder,
2152 String* name) {
2153 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002154 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002155 // -- r2 : name
2156 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002157 // -----------------------------------
2158 Label miss;
2159
Steve Blocka7e24c12009-10-30 11:49:00 +00002160 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00002161 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00002162 GenerateLoadInterceptor(object,
2163 holder,
2164 &lookup,
2165 r0,
2166 r2,
2167 r3,
2168 r1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002169 r4,
Steve Blocka7e24c12009-10-30 11:49:00 +00002170 name,
2171 &miss);
2172 __ bind(&miss);
2173 GenerateLoadMiss(masm(), Code::LOAD_IC);
2174
2175 // Return the generated code.
2176 return GetCode(INTERCEPTOR, name);
2177}
2178
2179
2180Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
2181 GlobalObject* holder,
2182 JSGlobalPropertyCell* cell,
2183 String* name,
2184 bool is_dont_delete) {
2185 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002186 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002187 // -- r2 : name
2188 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002189 // -----------------------------------
2190 Label miss;
2191
Steve Blocka7e24c12009-10-30 11:49:00 +00002192 // If the object is the holder then we know that it's a global
2193 // object which can only happen for contextual calls. In this case,
2194 // the receiver cannot be a smi.
2195 if (object != holder) {
Steve Block6ded16b2010-05-10 14:33:55 +01002196 __ tst(r0, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00002197 __ b(eq, &miss);
2198 }
2199
2200 // Check that the map of the global has not changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002201 CheckPrototypes(object, r0, holder, r3, r4, r1, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002202
2203 // Get the value from the cell.
2204 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
Steve Block6ded16b2010-05-10 14:33:55 +01002205 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00002206
2207 // Check for deleted property if property can actually be deleted.
2208 if (!is_dont_delete) {
2209 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
Steve Block6ded16b2010-05-10 14:33:55 +01002210 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00002211 __ b(eq, &miss);
2212 }
2213
Steve Block6ded16b2010-05-10 14:33:55 +01002214 __ mov(r0, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002215 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
2216 __ Ret();
2217
2218 __ bind(&miss);
2219 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
2220 GenerateLoadMiss(masm(), Code::LOAD_IC);
2221
2222 // Return the generated code.
2223 return GetCode(NORMAL, name);
2224}
2225
2226
2227Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
2228 JSObject* receiver,
2229 JSObject* holder,
2230 int index) {
2231 // ----------- S t a t e -------------
2232 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002233 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002234 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002235 // -----------------------------------
2236 Label miss;
2237
Steve Block6ded16b2010-05-10 14:33:55 +01002238 // Check the key is the cached one.
2239 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002240 __ b(ne, &miss);
2241
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002242 GenerateLoadField(receiver, holder, r1, r2, r3, r4, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002243 __ bind(&miss);
2244 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2245
2246 return GetCode(FIELD, name);
2247}
2248
2249
2250Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
2251 JSObject* receiver,
2252 JSObject* holder,
2253 AccessorInfo* callback) {
2254 // ----------- S t a t e -------------
2255 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002256 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002257 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002258 // -----------------------------------
2259 Label miss;
2260
Steve Block6ded16b2010-05-10 14:33:55 +01002261 // Check the key is the cached one.
2262 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002263 __ b(ne, &miss);
2264
Leon Clarkee46be812010-01-19 14:06:41 +00002265 Failure* failure = Failure::InternalError();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002266 bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3, r4,
Leon Clarkee46be812010-01-19 14:06:41 +00002267 callback, name, &miss, &failure);
2268 if (!success) return failure;
2269
Steve Blocka7e24c12009-10-30 11:49:00 +00002270 __ bind(&miss);
2271 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2272
2273 return GetCode(CALLBACKS, name);
2274}
2275
2276
2277Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
2278 JSObject* receiver,
2279 JSObject* holder,
2280 Object* value) {
2281 // ----------- S t a t e -------------
2282 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002283 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002284 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002285 // -----------------------------------
2286 Label miss;
2287
Steve Block6ded16b2010-05-10 14:33:55 +01002288 // Check the key is the cached one.
2289 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002290 __ b(ne, &miss);
2291
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002292 GenerateLoadConstant(receiver, holder, r1, r2, r3, r4, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002293 __ bind(&miss);
2294 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2295
2296 // Return the generated code.
2297 return GetCode(CONSTANT_FUNCTION, name);
2298}
2299
2300
2301Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
2302 JSObject* holder,
2303 String* name) {
2304 // ----------- S t a t e -------------
2305 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002306 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002307 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002308 // -----------------------------------
2309 Label miss;
2310
Steve Block6ded16b2010-05-10 14:33:55 +01002311 // Check the key is the cached one.
2312 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002313 __ b(ne, &miss);
2314
2315 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00002316 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00002317 GenerateLoadInterceptor(receiver,
2318 holder,
2319 &lookup,
Steve Block6ded16b2010-05-10 14:33:55 +01002320 r1,
Steve Blocka7e24c12009-10-30 11:49:00 +00002321 r0,
2322 r2,
2323 r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002324 r4,
Steve Blocka7e24c12009-10-30 11:49:00 +00002325 name,
2326 &miss);
2327 __ bind(&miss);
2328 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2329
2330 return GetCode(INTERCEPTOR, name);
2331}
2332
2333
2334Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
2335 // ----------- S t a t e -------------
2336 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002337 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002338 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002339 // -----------------------------------
2340 Label miss;
2341
Steve Block6ded16b2010-05-10 14:33:55 +01002342 // Check the key is the cached one.
2343 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002344 __ b(ne, &miss);
2345
Steve Block6ded16b2010-05-10 14:33:55 +01002346 GenerateLoadArrayLength(masm(), r1, r2, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002347 __ bind(&miss);
2348 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2349
2350 return GetCode(CALLBACKS, name);
2351}
2352
2353
2354Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
2355 // ----------- S t a t e -------------
2356 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002357 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002358 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002359 // -----------------------------------
2360 Label miss;
2361 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
2362
Steve Block6ded16b2010-05-10 14:33:55 +01002363 // Check the key is the cached one.
2364 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002365 __ b(ne, &miss);
2366
Steve Block6ded16b2010-05-10 14:33:55 +01002367 GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002368 __ bind(&miss);
2369 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
2370
2371 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2372
2373 return GetCode(CALLBACKS, name);
2374}
2375
2376
2377// TODO(1224671): implement the fast case.
2378Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
2379 // ----------- S t a t e -------------
2380 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002381 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002382 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002383 // -----------------------------------
2384 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2385
2386 return GetCode(CALLBACKS, name);
2387}
2388
2389
2390Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
2391 int index,
2392 Map* transition,
2393 String* name) {
2394 // ----------- S t a t e -------------
2395 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01002396 // -- r1 : key
2397 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002398 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002399 // -----------------------------------
2400 Label miss;
2401
Leon Clarkef7060e22010-06-03 12:02:55 +01002402 __ IncrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002403
2404 // Check that the name has not changed.
Leon Clarkef7060e22010-06-03 12:02:55 +01002405 __ cmp(r1, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002406 __ b(ne, &miss);
2407
Leon Clarkef7060e22010-06-03 12:02:55 +01002408 // r3 is used as scratch register. r1 and r2 keep their values if a jump to
2409 // the miss label is generated.
Steve Blocka7e24c12009-10-30 11:49:00 +00002410 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002411 object,
2412 index,
2413 transition,
Leon Clarkef7060e22010-06-03 12:02:55 +01002414 r2, r1, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00002415 &miss);
2416 __ bind(&miss);
2417
Leon Clarkef7060e22010-06-03 12:02:55 +01002418 __ DecrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002419 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
Leon Clarkef7060e22010-06-03 12:02:55 +01002420
Steve Blocka7e24c12009-10-30 11:49:00 +00002421 __ Jump(ic, RelocInfo::CODE_TARGET);
2422
2423 // Return the generated code.
2424 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2425}
2426
2427
2428Object* ConstructStubCompiler::CompileConstructStub(
2429 SharedFunctionInfo* shared) {
2430 // ----------- S t a t e -------------
2431 // -- r0 : argc
2432 // -- r1 : constructor
2433 // -- lr : return address
2434 // -- [sp] : last argument
2435 // -----------------------------------
2436 Label generic_stub_call;
2437
2438 // Use r7 for holding undefined which is used in several places below.
2439 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2440
2441#ifdef ENABLE_DEBUGGER_SUPPORT
2442 // Check to see whether there are any break points in the function code. If
2443 // there are jump to the generic constructor stub which calls the actual
2444 // code for the function thereby hitting the break points.
2445 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2446 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2447 __ cmp(r2, r7);
2448 __ b(ne, &generic_stub_call);
2449#endif
2450
2451 // Load the initial map and verify that it is in fact a map.
2452 // r1: constructor function
2453 // r7: undefined
2454 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2455 __ tst(r2, Operand(kSmiTagMask));
2456 __ b(eq, &generic_stub_call);
2457 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2458 __ b(ne, &generic_stub_call);
2459
2460#ifdef DEBUG
2461 // Cannot construct functions this way.
2462 // r0: argc
2463 // r1: constructor function
2464 // r2: initial map
2465 // r7: undefined
2466 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2467 __ Check(ne, "Function constructed by construct stub.");
2468#endif
2469
2470 // Now allocate the JSObject in new space.
2471 // r0: argc
2472 // r1: constructor function
2473 // r2: initial map
2474 // r7: undefined
2475 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
2476 __ AllocateInNewSpace(r3,
2477 r4,
2478 r5,
2479 r6,
2480 &generic_stub_call,
Kristian Monsen25f61362010-05-21 11:50:48 +01002481 SIZE_IN_WORDS);
Steve Blocka7e24c12009-10-30 11:49:00 +00002482
2483 // Allocated the JSObject, now initialize the fields. Map is set to initial
2484 // map and properties and elements are set to empty fixed array.
2485 // r0: argc
2486 // r1: constructor function
2487 // r2: initial map
2488 // r3: object size (in words)
2489 // r4: JSObject (not tagged)
2490 // r7: undefined
2491 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2492 __ mov(r5, r4);
2493 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2494 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2495 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2496 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2497 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2498 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2499
2500 // Calculate the location of the first argument. The stack contains only the
2501 // argc arguments.
2502 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2503
2504 // Fill all the in-object properties with undefined.
2505 // r0: argc
2506 // r1: first argument
2507 // r3: object size (in words)
2508 // r4: JSObject (not tagged)
2509 // r5: First in-object property of JSObject (not tagged)
2510 // r7: undefined
2511 // Fill the initialized properties with a constant value or a passed argument
2512 // depending on the this.x = ...; assignment in the function.
2513 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2514 if (shared->IsThisPropertyAssignmentArgument(i)) {
2515 Label not_passed, next;
2516 // Check if the argument assigned to the property is actually passed.
2517 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2518 __ cmp(r0, Operand(arg_number));
2519 __ b(le, &not_passed);
2520 // Argument passed - find it on the stack.
2521 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2522 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2523 __ b(&next);
2524 __ bind(&not_passed);
2525 // Set the property to undefined.
2526 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2527 __ bind(&next);
2528 } else {
2529 // Set the property to the constant value.
2530 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2531 __ mov(r2, Operand(constant));
2532 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2533 }
2534 }
2535
2536 // Fill the unused in-object property fields with undefined.
2537 for (int i = shared->this_property_assignments_count();
2538 i < shared->CalculateInObjectProperties();
2539 i++) {
2540 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2541 }
2542
2543 // r0: argc
2544 // r4: JSObject (not tagged)
2545 // Move argc to r1 and the JSObject to return to r0 and tag it.
2546 __ mov(r1, r0);
2547 __ mov(r0, r4);
2548 __ orr(r0, r0, Operand(kHeapObjectTag));
2549
2550 // r0: JSObject
2551 // r1: argc
2552 // Remove caller arguments and receiver from the stack and return.
2553 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2554 __ add(sp, sp, Operand(kPointerSize));
2555 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2556 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2557 __ Jump(lr);
2558
2559 // Jump to the generic stub in case the specialized code cannot handle the
2560 // construction.
2561 __ bind(&generic_stub_call);
2562 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2563 Handle<Code> generic_construct_stub(code);
2564 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2565
2566 // Return the generated code.
2567 return GetCode();
2568}
2569
2570
2571#undef __
2572
2573} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002574
2575#endif // V8_TARGET_ARCH_ARM