blob: ff3007c444b6340abe605af0fc574d703ae99a6a [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
1215Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
1216 // ----------- S t a t e -------------
1217 // -- r1: function
1218 // -- lr: return address
1219 // -----------------------------------
1220
1221 // Enter an internal frame.
1222 __ EnterInternalFrame();
1223
1224 // Preserve the function.
1225 __ push(r1);
1226
1227 // Push the function on the stack as the argument to the runtime function.
1228 __ push(r1);
1229 __ CallRuntime(Runtime::kLazyCompile, 1);
1230
1231 // Calculate the entry point.
1232 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
1233
1234 // Restore saved function.
1235 __ pop(r1);
1236
1237 // Tear down temporary frame.
1238 __ LeaveInternalFrame();
1239
1240 // Do a tail-call of the compiled function.
1241 __ Jump(r2);
1242
1243 return GetCodeWithFlags(flags, "LazyCompileStub");
1244}
1245
1246
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001247void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
1248 if (kind_ == Code::KEYED_CALL_IC) {
1249 __ cmp(r2, Operand(Handle<String>(name)));
1250 __ b(ne, miss);
1251 }
1252}
1253
1254
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001255void CallStubCompiler::GenerateMissBranch() {
1256 Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_);
1257 __ Jump(ic, RelocInfo::CODE_TARGET);
1258}
1259
1260
Andrei Popescu402d9372010-02-26 13:31:12 +00001261Object* CallStubCompiler::CompileCallField(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001262 JSObject* holder,
1263 int index,
1264 String* name) {
1265 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001266 // -- r2 : name
1267 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001268 // -----------------------------------
1269 Label miss;
1270
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001271 GenerateNameCheck(name, &miss);
1272
Steve Blocka7e24c12009-10-30 11:49:00 +00001273 const int argc = arguments().immediate();
1274
1275 // Get the receiver of the function from the stack into r0.
1276 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1277 // Check that the receiver isn't a smi.
1278 __ tst(r0, Operand(kSmiTagMask));
1279 __ b(eq, &miss);
1280
1281 // Do the right check and compute the holder register.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001282 Register reg = CheckPrototypes(object, r0, holder, r1, r3, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001283 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
1284
Leon Clarke4515c472010-02-03 11:58:03 +00001285 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001286
1287 // Handle call cache miss.
1288 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001289 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001290
1291 // Return the generated code.
1292 return GetCode(FIELD, name);
1293}
1294
1295
Steve Block6ded16b2010-05-10 14:33:55 +01001296Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1297 JSObject* holder,
1298 JSFunction* function,
1299 String* name,
1300 CheckType check) {
1301 // ----------- S t a t e -------------
1302 // -- r2 : name
1303 // -- lr : return address
1304 // -----------------------------------
1305
1306 // If object is not an array, bail out to regular call.
1307 if (!object->IsJSArray()) {
1308 return Heap::undefined_value();
1309 }
1310
1311 // TODO(639): faster implementation.
1312 ASSERT(check == RECEIVER_MAP_CHECK);
1313
1314 Label miss;
1315
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001316 GenerateNameCheck(name, &miss);
1317
Steve Block6ded16b2010-05-10 14:33:55 +01001318 // Get the receiver from the stack
1319 const int argc = arguments().immediate();
1320 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1321
1322 // Check that the receiver isn't a smi.
1323 __ tst(r1, Operand(kSmiTagMask));
1324 __ b(eq, &miss);
1325
1326 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001327 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001328
1329 if (object->IsGlobalObject()) {
1330 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1331 __ str(r3, MemOperand(sp, argc * kPointerSize));
1332 }
1333
1334 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1335 argc + 1,
1336 1);
1337
1338 // Handle call cache miss.
1339 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001340 GenerateMissBranch();
Steve Block6ded16b2010-05-10 14:33:55 +01001341
1342 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001343 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001344}
1345
1346
1347Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1348 JSObject* holder,
1349 JSFunction* function,
1350 String* name,
1351 CheckType check) {
1352 // ----------- S t a t e -------------
1353 // -- r2 : name
1354 // -- lr : return address
1355 // -----------------------------------
1356
1357 // If object is not an array, bail out to regular call.
1358 if (!object->IsJSArray()) {
1359 return Heap::undefined_value();
1360 }
1361
1362 // TODO(642): faster implementation.
1363 ASSERT(check == RECEIVER_MAP_CHECK);
1364
1365 Label miss;
1366
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001367 GenerateNameCheck(name, &miss);
1368
Steve Block6ded16b2010-05-10 14:33:55 +01001369 // Get the receiver from the stack
1370 const int argc = arguments().immediate();
1371 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1372
1373 // Check that the receiver isn't a smi.
1374 __ tst(r1, Operand(kSmiTagMask));
1375 __ b(eq, &miss);
1376
1377 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001378 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001379
1380 if (object->IsGlobalObject()) {
1381 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1382 __ str(r3, MemOperand(sp, argc * kPointerSize));
1383 }
1384
1385 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1386 argc + 1,
1387 1);
1388
1389 // Handle call cache miss.
1390 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001391 GenerateMissBranch();
Steve Block6ded16b2010-05-10 14:33:55 +01001392
1393 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001394 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001395}
1396
1397
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001398Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
1399 JSObject* holder,
1400 JSFunction* function,
1401 String* name,
1402 CheckType check) {
1403 // TODO(722): implement this.
1404 return Heap::undefined_value();
1405}
1406
1407
1408Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
1409 JSObject* holder,
1410 JSFunction* function,
1411 String* name,
1412 CheckType check) {
1413 // TODO(722): implement this.
1414 return Heap::undefined_value();
1415}
1416
1417
Steve Blocka7e24c12009-10-30 11:49:00 +00001418Object* CallStubCompiler::CompileCallConstant(Object* object,
1419 JSObject* holder,
1420 JSFunction* function,
1421 String* name,
1422 CheckType check) {
1423 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001424 // -- r2 : name
1425 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001426 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001427 SharedFunctionInfo* function_info = function->shared();
1428 if (function_info->HasCustomCallGenerator()) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001429 const int id = function_info->custom_call_generator_id();
1430 Object* result =
1431 CompileCustomCall(id, object, holder, function, name, check);
Steve Block6ded16b2010-05-10 14:33:55 +01001432 // undefined means bail out to regular compiler.
1433 if (!result->IsUndefined()) {
1434 return result;
1435 }
1436 }
1437
1438 Label miss_in_smi_check;
Steve Blocka7e24c12009-10-30 11:49:00 +00001439
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001440 GenerateNameCheck(name, &miss_in_smi_check);
1441
Steve Blocka7e24c12009-10-30 11:49:00 +00001442 // Get the receiver from the stack
1443 const int argc = arguments().immediate();
1444 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1445
1446 // Check that the receiver isn't a smi.
1447 if (check != NUMBER_CHECK) {
1448 __ tst(r1, Operand(kSmiTagMask));
Steve Block6ded16b2010-05-10 14:33:55 +01001449 __ b(eq, &miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001450 }
1451
1452 // Make sure that it's okay not to patch the on stack receiver
1453 // unless we're doing a receiver map check.
1454 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1455
Steve Block6ded16b2010-05-10 14:33:55 +01001456 CallOptimization optimization(function);
1457 int depth = kInvalidProtoDepth;
1458 Label miss;
1459
Steve Blocka7e24c12009-10-30 11:49:00 +00001460 switch (check) {
1461 case RECEIVER_MAP_CHECK:
Steve Block6ded16b2010-05-10 14:33:55 +01001462 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1463
1464 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1465 depth = optimization.GetPrototypeDepthOfExpectedType(
1466 JSObject::cast(object), holder);
1467 }
1468
1469 if (depth != kInvalidProtoDepth) {
1470 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1471 ReserveSpaceForFastApiCall(masm(), r0);
1472 }
1473
Steve Blocka7e24c12009-10-30 11:49:00 +00001474 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001475 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
Steve Block6ded16b2010-05-10 14:33:55 +01001476 depth, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001477
1478 // Patch the receiver on the stack with the global proxy if
1479 // necessary.
1480 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001481 ASSERT(depth == kInvalidProtoDepth);
Steve Blocka7e24c12009-10-30 11:49:00 +00001482 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1483 __ str(r3, MemOperand(sp, argc * kPointerSize));
1484 }
1485 break;
1486
1487 case STRING_CHECK:
Leon Clarkee46be812010-01-19 14:06:41 +00001488 if (!function->IsBuiltin()) {
1489 // Calling non-builtins with a value as receiver requires boxing.
1490 __ jmp(&miss);
1491 } else {
1492 // Check that the object is a two-byte string or a symbol.
Andrei Popescu402d9372010-02-26 13:31:12 +00001493 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001494 __ b(hs, &miss);
1495 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001496 GenerateDirectLoadGlobalFunctionPrototype(
1497 masm(), Context::STRING_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001498 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001499 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001500 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001501 break;
1502
1503 case NUMBER_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001504 if (!function->IsBuiltin()) {
1505 // Calling non-builtins with a value as receiver requires boxing.
1506 __ jmp(&miss);
1507 } else {
1508 Label fast;
1509 // Check that the object is a smi or a heap number.
1510 __ tst(r1, Operand(kSmiTagMask));
1511 __ b(eq, &fast);
Andrei Popescu402d9372010-02-26 13:31:12 +00001512 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001513 __ b(ne, &miss);
1514 __ bind(&fast);
1515 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001516 GenerateDirectLoadGlobalFunctionPrototype(
1517 masm(), Context::NUMBER_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001518 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001519 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001520 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001521 break;
1522 }
1523
1524 case BOOLEAN_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001525 if (!function->IsBuiltin()) {
1526 // Calling non-builtins with a value as receiver requires boxing.
1527 __ jmp(&miss);
1528 } else {
1529 Label fast;
1530 // Check that the object is a boolean.
1531 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1532 __ cmp(r1, ip);
1533 __ b(eq, &fast);
1534 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1535 __ cmp(r1, ip);
1536 __ b(ne, &miss);
1537 __ bind(&fast);
1538 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001539 GenerateDirectLoadGlobalFunctionPrototype(
1540 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001541 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001542 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001543 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001544 break;
1545 }
1546
Steve Blocka7e24c12009-10-30 11:49:00 +00001547 default:
1548 UNREACHABLE();
1549 }
1550
Steve Block6ded16b2010-05-10 14:33:55 +01001551 if (depth != kInvalidProtoDepth) {
1552 GenerateFastApiCall(masm(), optimization, argc);
1553 } else {
1554 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1555 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001556
1557 // Handle call cache miss.
1558 __ bind(&miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001559 if (depth != kInvalidProtoDepth) {
1560 FreeSpaceForFastApiCall(masm());
1561 }
1562
1563 __ bind(&miss_in_smi_check);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001564 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001565
1566 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001567 return GetCode(function);
Steve Blocka7e24c12009-10-30 11:49:00 +00001568}
1569
1570
Andrei Popescu402d9372010-02-26 13:31:12 +00001571Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001572 JSObject* holder,
1573 String* name) {
1574 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001575 // -- r2 : name
1576 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001577 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001578
Steve Block6ded16b2010-05-10 14:33:55 +01001579 Label miss;
Andrei Popescu402d9372010-02-26 13:31:12 +00001580
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001581 GenerateNameCheck(name, &miss);
1582
Leon Clarke4515c472010-02-03 11:58:03 +00001583 // Get the number of arguments.
1584 const int argc = arguments().immediate();
1585
1586 LookupResult lookup;
1587 LookupPostInterceptor(holder, name, &lookup);
1588
Steve Block6ded16b2010-05-10 14:33:55 +01001589 // Get the receiver from the stack.
1590 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001591
Steve Block6ded16b2010-05-10 14:33:55 +01001592 CallInterceptorCompiler compiler(this, arguments(), r2);
1593 compiler.Compile(masm(),
1594 object,
1595 holder,
1596 name,
1597 &lookup,
1598 r1,
1599 r3,
1600 r4,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001601 r0,
Steve Block6ded16b2010-05-10 14:33:55 +01001602 &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001603
1604 // Move returned value, the function to call, to r1.
1605 __ mov(r1, r0);
Leon Clarke4515c472010-02-03 11:58:03 +00001606 // Restore receiver.
Steve Block6ded16b2010-05-10 14:33:55 +01001607 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001608
1609 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001610
1611 // Handle call cache miss.
1612 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001613 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001614
1615 // Return the generated code.
1616 return GetCode(INTERCEPTOR, name);
1617}
1618
1619
1620Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1621 GlobalObject* holder,
1622 JSGlobalPropertyCell* cell,
1623 JSFunction* function,
1624 String* name) {
1625 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001626 // -- r2 : name
1627 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001628 // -----------------------------------
1629 Label miss;
1630
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001631 GenerateNameCheck(name, &miss);
1632
Steve Blocka7e24c12009-10-30 11:49:00 +00001633 // Get the number of arguments.
1634 const int argc = arguments().immediate();
1635
1636 // Get the receiver from the stack.
1637 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1638
1639 // If the object is the holder then we know that it's a global
1640 // object which can only happen for contextual calls. In this case,
1641 // the receiver cannot be a smi.
1642 if (object != holder) {
1643 __ tst(r0, Operand(kSmiTagMask));
1644 __ b(eq, &miss);
1645 }
1646
1647 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001648 CheckPrototypes(object, r0, holder, r3, r1, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001649
1650 // Get the value from the cell.
1651 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1652 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1653
1654 // Check that the cell contains the same function.
Leon Clarkee46be812010-01-19 14:06:41 +00001655 if (Heap::InNewSpace(function)) {
1656 // We can't embed a pointer to a function in new space so we have
1657 // to verify that the shared function info is unchanged. This has
1658 // the nice side effect that multiple closures based on the same
1659 // function can all use this call IC. Before we load through the
1660 // function, we have to verify that it still is a function.
1661 __ tst(r1, Operand(kSmiTagMask));
1662 __ b(eq, &miss);
1663 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1664 __ b(ne, &miss);
1665
1666 // Check the shared function info. Make sure it hasn't changed.
1667 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
Andrei Popescu402d9372010-02-26 13:31:12 +00001668 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1669 __ cmp(r4, r3);
Leon Clarkee46be812010-01-19 14:06:41 +00001670 __ b(ne, &miss);
1671 } else {
1672 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1673 __ b(ne, &miss);
1674 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001675
1676 // Patch the receiver on the stack with the global proxy if
1677 // necessary.
1678 if (object->IsGlobalObject()) {
1679 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1680 __ str(r3, MemOperand(sp, argc * kPointerSize));
1681 }
1682
1683 // Setup the context (function already in r1).
1684 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1685
1686 // Jump to the cached code (tail call).
Steve Block6ded16b2010-05-10 14:33:55 +01001687 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001688 ASSERT(function->is_compiled());
1689 Handle<Code> code(function->code());
1690 ParameterCount expected(function->shared()->formal_parameter_count());
1691 __ InvokeCode(code, expected, arguments(),
1692 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1693
1694 // Handle call cache miss.
1695 __ bind(&miss);
1696 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001697 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001698
1699 // Return the generated code.
1700 return GetCode(NORMAL, name);
1701}
1702
1703
1704Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1705 int index,
1706 Map* transition,
1707 String* name) {
1708 // ----------- S t a t e -------------
1709 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001710 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001711 // -- r2 : name
1712 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001713 // -----------------------------------
1714 Label miss;
1715
Steve Blocka7e24c12009-10-30 11:49:00 +00001716 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001717 object,
1718 index,
1719 transition,
Andrei Popescu402d9372010-02-26 13:31:12 +00001720 r1, r2, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001721 &miss);
1722 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001723 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1724 __ Jump(ic, RelocInfo::CODE_TARGET);
1725
1726 // Return the generated code.
1727 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1728}
1729
1730
1731Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1732 AccessorInfo* callback,
1733 String* name) {
1734 // ----------- S t a t e -------------
1735 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001736 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001737 // -- r2 : name
1738 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001739 // -----------------------------------
1740 Label miss;
1741
Steve Blocka7e24c12009-10-30 11:49:00 +00001742 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001743 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001744 __ b(eq, &miss);
1745
1746 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001747 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1748 __ cmp(r3, Operand(Handle<Map>(object->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001749 __ b(ne, &miss);
1750
1751 // Perform global security token check if needed.
1752 if (object->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001753 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001754 }
1755
1756 // Stub never generated for non-global objects that require access
1757 // checks.
1758 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1759
Andrei Popescu402d9372010-02-26 13:31:12 +00001760 __ push(r1); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001761 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
Steve Block6ded16b2010-05-10 14:33:55 +01001762 __ Push(ip, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001763
1764 // Do tail-call to the runtime system.
1765 ExternalReference store_callback_property =
1766 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001767 __ TailCallExternalReference(store_callback_property, 4, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001768
1769 // Handle store cache miss.
1770 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001771 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1772 __ Jump(ic, RelocInfo::CODE_TARGET);
1773
1774 // Return the generated code.
1775 return GetCode(CALLBACKS, name);
1776}
1777
1778
1779Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1780 String* name) {
1781 // ----------- S t a t e -------------
1782 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001783 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001784 // -- r2 : name
1785 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001786 // -----------------------------------
1787 Label miss;
1788
Steve Blocka7e24c12009-10-30 11:49:00 +00001789 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001790 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001791 __ b(eq, &miss);
1792
1793 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001794 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1795 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001796 __ b(ne, &miss);
1797
1798 // Perform global security token check if needed.
1799 if (receiver->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001800 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001801 }
1802
Andrei Popescu402d9372010-02-26 13:31:12 +00001803 // Stub is never generated for non-global objects that require access
Steve Blocka7e24c12009-10-30 11:49:00 +00001804 // checks.
1805 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1806
Steve Block6ded16b2010-05-10 14:33:55 +01001807 __ Push(r1, r2, r0); // Receiver, name, value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001808
1809 // Do tail-call to the runtime system.
1810 ExternalReference store_ic_property =
1811 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001812 __ TailCallExternalReference(store_ic_property, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001813
1814 // Handle store cache miss.
1815 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001816 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1817 __ Jump(ic, RelocInfo::CODE_TARGET);
1818
1819 // Return the generated code.
1820 return GetCode(INTERCEPTOR, name);
1821}
1822
1823
1824Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1825 JSGlobalPropertyCell* cell,
1826 String* name) {
1827 // ----------- S t a t e -------------
1828 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001829 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001830 // -- r2 : name
1831 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001832 // -----------------------------------
1833 Label miss;
1834
1835 // Check that the map of the global has not changed.
Steve Blocka7e24c12009-10-30 11:49:00 +00001836 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1837 __ cmp(r3, Operand(Handle<Map>(object->map())));
1838 __ b(ne, &miss);
1839
1840 // Store the value in the cell.
1841 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1842 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
1843
Andrei Popescu402d9372010-02-26 13:31:12 +00001844 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001845 __ Ret();
1846
1847 // Handle store cache miss.
1848 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001849 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001850 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1851 __ Jump(ic, RelocInfo::CODE_TARGET);
1852
1853 // Return the generated code.
1854 return GetCode(NORMAL, name);
1855}
1856
1857
Steve Block6ded16b2010-05-10 14:33:55 +01001858Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1859 JSObject* object,
1860 JSObject* last) {
1861 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001862 // -- r0 : receiver
Steve Block6ded16b2010-05-10 14:33:55 +01001863 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001864 // -----------------------------------
1865 Label miss;
1866
Steve Block6ded16b2010-05-10 14:33:55 +01001867 // Check that receiver is not a smi.
1868 __ tst(r0, Operand(kSmiTagMask));
1869 __ b(eq, &miss);
1870
1871 // Check the maps of the full prototype chain.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001872 CheckPrototypes(object, r0, last, r3, r1, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001873
1874 // If the last object in the prototype chain is a global object,
1875 // check that the global property cell is empty.
1876 if (last->IsGlobalObject()) {
1877 Object* cell = GenerateCheckPropertyCell(masm(),
1878 GlobalObject::cast(last),
1879 name,
1880 r1,
1881 &miss);
1882 if (cell->IsFailure()) return cell;
1883 }
1884
1885 // Return undefined if maps of the full prototype chain are still the
1886 // same and no global property with this name contains a value.
1887 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1888 __ Ret();
1889
1890 __ bind(&miss);
1891 GenerateLoadMiss(masm(), Code::LOAD_IC);
1892
1893 // Return the generated code.
1894 return GetCode(NONEXISTENT, Heap::empty_string());
1895}
1896
1897
Steve Blocka7e24c12009-10-30 11:49:00 +00001898Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1899 JSObject* holder,
1900 int index,
1901 String* name) {
1902 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001903 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001904 // -- r2 : name
1905 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001906 // -----------------------------------
1907 Label miss;
1908
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001909 GenerateLoadField(object, holder, r0, r3, r1, r4, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001910 __ bind(&miss);
1911 GenerateLoadMiss(masm(), Code::LOAD_IC);
1912
1913 // Return the generated code.
1914 return GetCode(FIELD, name);
1915}
1916
1917
Leon Clarkee46be812010-01-19 14:06:41 +00001918Object* LoadStubCompiler::CompileLoadCallback(String* name,
1919 JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001920 JSObject* holder,
Leon Clarkee46be812010-01-19 14:06:41 +00001921 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001922 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001923 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001924 // -- r2 : name
1925 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001926 // -----------------------------------
1927 Label miss;
1928
Leon Clarkee46be812010-01-19 14:06:41 +00001929 Failure* failure = Failure::InternalError();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001930 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1, r4,
Leon Clarkee46be812010-01-19 14:06:41 +00001931 callback, name, &miss, &failure);
1932 if (!success) return failure;
1933
Steve Blocka7e24c12009-10-30 11:49:00 +00001934 __ bind(&miss);
1935 GenerateLoadMiss(masm(), Code::LOAD_IC);
1936
1937 // Return the generated code.
1938 return GetCode(CALLBACKS, name);
1939}
1940
1941
1942Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1943 JSObject* holder,
1944 Object* value,
1945 String* name) {
1946 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001947 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001948 // -- r2 : name
1949 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001950 // -----------------------------------
1951 Label miss;
1952
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001953 GenerateLoadConstant(object, holder, r0, r3, r1, r4, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001954 __ bind(&miss);
1955 GenerateLoadMiss(masm(), Code::LOAD_IC);
1956
1957 // Return the generated code.
1958 return GetCode(CONSTANT_FUNCTION, name);
1959}
1960
1961
1962Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1963 JSObject* holder,
1964 String* name) {
1965 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001966 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001967 // -- r2 : name
1968 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001969 // -----------------------------------
1970 Label miss;
1971
Steve Blocka7e24c12009-10-30 11:49:00 +00001972 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001973 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001974 GenerateLoadInterceptor(object,
1975 holder,
1976 &lookup,
1977 r0,
1978 r2,
1979 r3,
1980 r1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001981 r4,
Steve Blocka7e24c12009-10-30 11:49:00 +00001982 name,
1983 &miss);
1984 __ bind(&miss);
1985 GenerateLoadMiss(masm(), Code::LOAD_IC);
1986
1987 // Return the generated code.
1988 return GetCode(INTERCEPTOR, name);
1989}
1990
1991
1992Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1993 GlobalObject* holder,
1994 JSGlobalPropertyCell* cell,
1995 String* name,
1996 bool is_dont_delete) {
1997 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001998 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001999 // -- r2 : name
2000 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002001 // -----------------------------------
2002 Label miss;
2003
Steve Blocka7e24c12009-10-30 11:49:00 +00002004 // If the object is the holder then we know that it's a global
2005 // object which can only happen for contextual calls. In this case,
2006 // the receiver cannot be a smi.
2007 if (object != holder) {
Steve Block6ded16b2010-05-10 14:33:55 +01002008 __ tst(r0, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00002009 __ b(eq, &miss);
2010 }
2011
2012 // Check that the map of the global has not changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002013 CheckPrototypes(object, r0, holder, r3, r4, r1, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002014
2015 // Get the value from the cell.
2016 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
Steve Block6ded16b2010-05-10 14:33:55 +01002017 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00002018
2019 // Check for deleted property if property can actually be deleted.
2020 if (!is_dont_delete) {
2021 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
Steve Block6ded16b2010-05-10 14:33:55 +01002022 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00002023 __ b(eq, &miss);
2024 }
2025
Steve Block6ded16b2010-05-10 14:33:55 +01002026 __ mov(r0, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002027 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
2028 __ Ret();
2029
2030 __ bind(&miss);
2031 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
2032 GenerateLoadMiss(masm(), Code::LOAD_IC);
2033
2034 // Return the generated code.
2035 return GetCode(NORMAL, name);
2036}
2037
2038
2039Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
2040 JSObject* receiver,
2041 JSObject* holder,
2042 int index) {
2043 // ----------- S t a t e -------------
2044 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002045 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002046 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002047 // -----------------------------------
2048 Label miss;
2049
Steve Block6ded16b2010-05-10 14:33:55 +01002050 // Check the key is the cached one.
2051 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002052 __ b(ne, &miss);
2053
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002054 GenerateLoadField(receiver, holder, r1, r2, r3, r4, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002055 __ bind(&miss);
2056 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2057
2058 return GetCode(FIELD, name);
2059}
2060
2061
2062Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
2063 JSObject* receiver,
2064 JSObject* holder,
2065 AccessorInfo* callback) {
2066 // ----------- S t a t e -------------
2067 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002068 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002069 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002070 // -----------------------------------
2071 Label miss;
2072
Steve Block6ded16b2010-05-10 14:33:55 +01002073 // Check the key is the cached one.
2074 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002075 __ b(ne, &miss);
2076
Leon Clarkee46be812010-01-19 14:06:41 +00002077 Failure* failure = Failure::InternalError();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002078 bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3, r4,
Leon Clarkee46be812010-01-19 14:06:41 +00002079 callback, name, &miss, &failure);
2080 if (!success) return failure;
2081
Steve Blocka7e24c12009-10-30 11:49:00 +00002082 __ bind(&miss);
2083 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2084
2085 return GetCode(CALLBACKS, name);
2086}
2087
2088
2089Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
2090 JSObject* receiver,
2091 JSObject* holder,
2092 Object* value) {
2093 // ----------- S t a t e -------------
2094 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002095 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002096 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002097 // -----------------------------------
2098 Label miss;
2099
Steve Block6ded16b2010-05-10 14:33:55 +01002100 // Check the key is the cached one.
2101 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002102 __ b(ne, &miss);
2103
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002104 GenerateLoadConstant(receiver, holder, r1, r2, r3, r4, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002105 __ bind(&miss);
2106 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2107
2108 // Return the generated code.
2109 return GetCode(CONSTANT_FUNCTION, name);
2110}
2111
2112
2113Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
2114 JSObject* holder,
2115 String* name) {
2116 // ----------- S t a t e -------------
2117 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002118 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002119 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002120 // -----------------------------------
2121 Label miss;
2122
Steve Block6ded16b2010-05-10 14:33:55 +01002123 // Check the key is the cached one.
2124 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002125 __ b(ne, &miss);
2126
2127 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00002128 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00002129 GenerateLoadInterceptor(receiver,
2130 holder,
2131 &lookup,
Steve Block6ded16b2010-05-10 14:33:55 +01002132 r1,
Steve Blocka7e24c12009-10-30 11:49:00 +00002133 r0,
2134 r2,
2135 r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002136 r4,
Steve Blocka7e24c12009-10-30 11:49:00 +00002137 name,
2138 &miss);
2139 __ bind(&miss);
2140 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2141
2142 return GetCode(INTERCEPTOR, name);
2143}
2144
2145
2146Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
2147 // ----------- S t a t e -------------
2148 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002149 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002150 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002151 // -----------------------------------
2152 Label miss;
2153
Steve Block6ded16b2010-05-10 14:33:55 +01002154 // Check the key is the cached one.
2155 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002156 __ b(ne, &miss);
2157
Steve Block6ded16b2010-05-10 14:33:55 +01002158 GenerateLoadArrayLength(masm(), r1, r2, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002159 __ bind(&miss);
2160 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2161
2162 return GetCode(CALLBACKS, name);
2163}
2164
2165
2166Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
2167 // ----------- S t a t e -------------
2168 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002169 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002170 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002171 // -----------------------------------
2172 Label miss;
2173 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
2174
Steve Block6ded16b2010-05-10 14:33:55 +01002175 // Check the key is the cached one.
2176 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002177 __ b(ne, &miss);
2178
Steve Block6ded16b2010-05-10 14:33:55 +01002179 GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002180 __ bind(&miss);
2181 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
2182
2183 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2184
2185 return GetCode(CALLBACKS, name);
2186}
2187
2188
2189// TODO(1224671): implement the fast case.
2190Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
2191 // ----------- S t a t e -------------
2192 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002193 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002194 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002195 // -----------------------------------
2196 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2197
2198 return GetCode(CALLBACKS, name);
2199}
2200
2201
2202Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
2203 int index,
2204 Map* transition,
2205 String* name) {
2206 // ----------- S t a t e -------------
2207 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01002208 // -- r1 : key
2209 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002210 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002211 // -----------------------------------
2212 Label miss;
2213
Leon Clarkef7060e22010-06-03 12:02:55 +01002214 __ IncrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002215
2216 // Check that the name has not changed.
Leon Clarkef7060e22010-06-03 12:02:55 +01002217 __ cmp(r1, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002218 __ b(ne, &miss);
2219
Leon Clarkef7060e22010-06-03 12:02:55 +01002220 // r3 is used as scratch register. r1 and r2 keep their values if a jump to
2221 // the miss label is generated.
Steve Blocka7e24c12009-10-30 11:49:00 +00002222 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002223 object,
2224 index,
2225 transition,
Leon Clarkef7060e22010-06-03 12:02:55 +01002226 r2, r1, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00002227 &miss);
2228 __ bind(&miss);
2229
Leon Clarkef7060e22010-06-03 12:02:55 +01002230 __ DecrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002231 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
Leon Clarkef7060e22010-06-03 12:02:55 +01002232
Steve Blocka7e24c12009-10-30 11:49:00 +00002233 __ Jump(ic, RelocInfo::CODE_TARGET);
2234
2235 // Return the generated code.
2236 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2237}
2238
2239
2240Object* ConstructStubCompiler::CompileConstructStub(
2241 SharedFunctionInfo* shared) {
2242 // ----------- S t a t e -------------
2243 // -- r0 : argc
2244 // -- r1 : constructor
2245 // -- lr : return address
2246 // -- [sp] : last argument
2247 // -----------------------------------
2248 Label generic_stub_call;
2249
2250 // Use r7 for holding undefined which is used in several places below.
2251 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2252
2253#ifdef ENABLE_DEBUGGER_SUPPORT
2254 // Check to see whether there are any break points in the function code. If
2255 // there are jump to the generic constructor stub which calls the actual
2256 // code for the function thereby hitting the break points.
2257 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2258 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2259 __ cmp(r2, r7);
2260 __ b(ne, &generic_stub_call);
2261#endif
2262
2263 // Load the initial map and verify that it is in fact a map.
2264 // r1: constructor function
2265 // r7: undefined
2266 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2267 __ tst(r2, Operand(kSmiTagMask));
2268 __ b(eq, &generic_stub_call);
2269 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2270 __ b(ne, &generic_stub_call);
2271
2272#ifdef DEBUG
2273 // Cannot construct functions this way.
2274 // r0: argc
2275 // r1: constructor function
2276 // r2: initial map
2277 // r7: undefined
2278 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2279 __ Check(ne, "Function constructed by construct stub.");
2280#endif
2281
2282 // Now allocate the JSObject in new space.
2283 // r0: argc
2284 // r1: constructor function
2285 // r2: initial map
2286 // r7: undefined
2287 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
2288 __ AllocateInNewSpace(r3,
2289 r4,
2290 r5,
2291 r6,
2292 &generic_stub_call,
Kristian Monsen25f61362010-05-21 11:50:48 +01002293 SIZE_IN_WORDS);
Steve Blocka7e24c12009-10-30 11:49:00 +00002294
2295 // Allocated the JSObject, now initialize the fields. Map is set to initial
2296 // map and properties and elements are set to empty fixed array.
2297 // r0: argc
2298 // r1: constructor function
2299 // r2: initial map
2300 // r3: object size (in words)
2301 // r4: JSObject (not tagged)
2302 // r7: undefined
2303 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2304 __ mov(r5, r4);
2305 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2306 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2307 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2308 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2309 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2310 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2311
2312 // Calculate the location of the first argument. The stack contains only the
2313 // argc arguments.
2314 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2315
2316 // Fill all the in-object properties with undefined.
2317 // r0: argc
2318 // r1: first argument
2319 // r3: object size (in words)
2320 // r4: JSObject (not tagged)
2321 // r5: First in-object property of JSObject (not tagged)
2322 // r7: undefined
2323 // Fill the initialized properties with a constant value or a passed argument
2324 // depending on the this.x = ...; assignment in the function.
2325 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2326 if (shared->IsThisPropertyAssignmentArgument(i)) {
2327 Label not_passed, next;
2328 // Check if the argument assigned to the property is actually passed.
2329 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2330 __ cmp(r0, Operand(arg_number));
2331 __ b(le, &not_passed);
2332 // Argument passed - find it on the stack.
2333 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2334 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2335 __ b(&next);
2336 __ bind(&not_passed);
2337 // Set the property to undefined.
2338 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2339 __ bind(&next);
2340 } else {
2341 // Set the property to the constant value.
2342 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2343 __ mov(r2, Operand(constant));
2344 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2345 }
2346 }
2347
2348 // Fill the unused in-object property fields with undefined.
2349 for (int i = shared->this_property_assignments_count();
2350 i < shared->CalculateInObjectProperties();
2351 i++) {
2352 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2353 }
2354
2355 // r0: argc
2356 // r4: JSObject (not tagged)
2357 // Move argc to r1 and the JSObject to return to r0 and tag it.
2358 __ mov(r1, r0);
2359 __ mov(r0, r4);
2360 __ orr(r0, r0, Operand(kHeapObjectTag));
2361
2362 // r0: JSObject
2363 // r1: argc
2364 // Remove caller arguments and receiver from the stack and return.
2365 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2366 __ add(sp, sp, Operand(kPointerSize));
2367 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2368 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2369 __ Jump(lr);
2370
2371 // Jump to the generic stub in case the specialized code cannot handle the
2372 // construction.
2373 __ bind(&generic_stub_call);
2374 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2375 Handle<Code> generic_construct_stub(code);
2376 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2377
2378 // Return the generated code.
2379 return GetCode();
2380}
2381
2382
2383#undef __
2384
2385} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002386
2387#endif // V8_TARGET_ARCH_ARM