blob: 344cb6fb9031da5ed2909a27692de72fbfec07c5 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
Leon Clarkef7060e22010-06-03 12:02:55 +010030#if defined(V8_TARGET_ARCH_ARM)
31
Steve Blocka7e24c12009-10-30 11:49:00 +000032#include "ic-inl.h"
33#include "codegen-inl.h"
34#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
42static void ProbeTable(MacroAssembler* masm,
43 Code::Flags flags,
44 StubCache::Table table,
45 Register name,
46 Register offset) {
47 ExternalReference key_offset(SCTableReference::keyReference(table));
48 ExternalReference value_offset(SCTableReference::valueReference(table));
49
50 Label miss;
51
52 // Save the offset on the stack.
53 __ push(offset);
54
55 // Check that the key in the entry matches the name.
56 __ mov(ip, Operand(key_offset));
57 __ ldr(ip, MemOperand(ip, offset, LSL, 1));
Steve Block6ded16b2010-05-10 14:33:55 +010058 __ cmp(name, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +000059 __ b(ne, &miss);
60
61 // Get the code entry from the cache.
62 __ mov(ip, Operand(value_offset));
63 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
64
65 // Check that the flags match what we're looking for.
66 __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
67 __ and_(offset, offset, Operand(~Code::kFlagsNotUsedInLookup));
68 __ cmp(offset, Operand(flags));
69 __ b(ne, &miss);
70
71 // Restore offset and re-load code entry from cache.
72 __ pop(offset);
73 __ mov(ip, Operand(value_offset));
74 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
75
76 // Jump to the first instruction in the code stub.
77 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
78 __ Jump(offset);
79
80 // Miss: Restore offset and fall through.
81 __ bind(&miss);
82 __ pop(offset);
83}
84
85
Ben Murdoch3bec4d22010-07-22 14:51:16 +010086// Helper function used to check that the dictionary doesn't contain
87// the property. This function may return false negatives, so miss_label
88// must always call a backup property check that is complete.
89// This function is safe to call if the receiver has fast properties.
90// Name must be a symbol and receiver must be a heap object.
91static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
92 Label* miss_label,
93 Register receiver,
94 String* name,
95 Register scratch0,
96 Register scratch1) {
97 ASSERT(name->IsSymbol());
98 __ IncrementCounter(&Counters::negative_lookups, 1, scratch0, scratch1);
99 __ IncrementCounter(&Counters::negative_lookups_miss, 1, scratch0, scratch1);
100
101 Label done;
102
103 const int kInterceptorOrAccessCheckNeededMask =
104 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
105
106 // Bail out if the receiver has a named interceptor or requires access checks.
107 Register map = scratch1;
108 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
109 __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
110 __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
111 __ b(ne, miss_label);
112
113 // Check that receiver is a JSObject.
114 __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
115 __ cmp(scratch0, Operand(FIRST_JS_OBJECT_TYPE));
116 __ b(lt, miss_label);
117
118 // Load properties array.
119 Register properties = scratch0;
120 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
121 // Check that the properties array is a dictionary.
122 __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
123 Register tmp = properties;
124 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
125 __ cmp(map, tmp);
126 __ b(ne, miss_label);
127
128 // Restore the temporarily used register.
129 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
130
131 // Compute the capacity mask.
132 const int kCapacityOffset =
133 StringDictionary::kHeaderSize +
134 StringDictionary::kCapacityIndex * kPointerSize;
135
136 // Generate an unrolled loop that performs a few probes before
137 // giving up.
138 static const int kProbes = 4;
139 const int kElementsStartOffset =
140 StringDictionary::kHeaderSize +
141 StringDictionary::kElementsStartIndex * kPointerSize;
142
143 // If names of slots in range from 1 to kProbes - 1 for the hash value are
144 // not equal to the name and kProbes-th slot is not used (its name is the
145 // undefined value), it guarantees the hash table doesn't contain the
146 // property. It's true even if some slots represent deleted properties
147 // (their names are the null value).
148 for (int i = 0; i < kProbes; i++) {
149 // scratch0 points to properties hash.
150 // Compute the masked index: (hash + i + i * i) & mask.
151 Register index = scratch1;
152 // Capacity is smi 2^n.
153 __ ldr(index, FieldMemOperand(properties, kCapacityOffset));
154 __ sub(index, index, Operand(1));
155 __ and_(index, index, Operand(
156 Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i))));
157
158 // Scale the index by multiplying by the entry size.
159 ASSERT(StringDictionary::kEntrySize == 3);
160 __ add(index, index, Operand(index, LSL, 1)); // index *= 3.
161
162 Register entity_name = scratch1;
163 // Having undefined at this place means the name is not contained.
164 ASSERT_EQ(kSmiTagSize, 1);
165 Register tmp = properties;
166 __ add(tmp, properties, Operand(index, LSL, 1));
167 __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
168
169 ASSERT(!tmp.is(entity_name));
170 __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
171 __ cmp(entity_name, tmp);
172 if (i != kProbes - 1) {
173 __ b(eq, &done);
174
175 // Stop if found the property.
176 __ cmp(entity_name, Operand(Handle<String>(name)));
177 __ b(eq, miss_label);
178
179 // Check if the entry name is not a symbol.
180 __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
181 __ ldrb(entity_name,
182 FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
183 __ tst(entity_name, Operand(kIsSymbolMask));
184 __ b(eq, miss_label);
185
186 // Restore the properties.
187 __ ldr(properties,
188 FieldMemOperand(receiver, JSObject::kPropertiesOffset));
189 } else {
190 // Give up probing if still not found the undefined value.
191 __ b(ne, miss_label);
192 }
193 }
194 __ bind(&done);
195 __ DecrementCounter(&Counters::negative_lookups_miss, 1, scratch0, scratch1);
196}
197
198
Steve Blocka7e24c12009-10-30 11:49:00 +0000199void StubCache::GenerateProbe(MacroAssembler* masm,
200 Code::Flags flags,
201 Register receiver,
202 Register name,
203 Register scratch,
204 Register extra) {
205 Label miss;
206
207 // Make sure that code is valid. The shifting code relies on the
208 // entry size being 8.
209 ASSERT(sizeof(Entry) == 8);
210
211 // Make sure the flags does not name a specific type.
212 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
213
214 // Make sure that there are no register conflicts.
215 ASSERT(!scratch.is(receiver));
216 ASSERT(!scratch.is(name));
217
218 // Check that the receiver isn't a smi.
219 __ tst(receiver, Operand(kSmiTagMask));
220 __ b(eq, &miss);
221
222 // Get the map of the receiver and compute the hash.
Steve Blockd0582a62009-12-15 09:54:21 +0000223 __ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
225 __ add(scratch, scratch, Operand(ip));
226 __ eor(scratch, scratch, Operand(flags));
227 __ and_(scratch,
228 scratch,
229 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
230
231 // Probe the primary table.
232 ProbeTable(masm, flags, kPrimary, name, scratch);
233
234 // Primary miss: Compute hash for secondary probe.
235 __ sub(scratch, scratch, Operand(name));
236 __ add(scratch, scratch, Operand(flags));
237 __ and_(scratch,
238 scratch,
239 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
240
241 // Probe the secondary table.
242 ProbeTable(masm, flags, kSecondary, name, scratch);
243
244 // Cache miss: Fall-through and let caller handle the miss by
245 // entering the runtime system.
246 __ bind(&miss);
247}
248
249
250void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
251 int index,
252 Register prototype) {
253 // Load the global or builtins object from the current context.
254 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
255 // Load the global context from the global or builtins object.
256 __ ldr(prototype,
257 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
258 // Load the function from the global context.
259 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
260 // Load the initial map. The global functions all have initial maps.
261 __ ldr(prototype,
262 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
263 // Load the prototype from the initial map.
264 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
265}
266
267
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100268void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
269 MacroAssembler* masm, int index, Register prototype) {
270 // Get the global function with the given index.
271 JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
272 // Load its initial map. The global functions all have initial maps.
273 __ Move(prototype, Handle<Map>(function->initial_map()));
274 // Load the prototype from the initial map.
275 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
276}
277
278
Steve Blocka7e24c12009-10-30 11:49:00 +0000279// Load a fast property out of a holder object (src). In-object properties
280// are loaded directly otherwise the property is loaded from the properties
281// fixed array.
282void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
283 Register dst, Register src,
284 JSObject* holder, int index) {
285 // Adjust for the number of properties stored in the holder.
286 index -= holder->map()->inobject_properties();
287 if (index < 0) {
288 // Get the property straight out of the holder.
289 int offset = holder->map()->instance_size() + (index * kPointerSize);
290 __ ldr(dst, FieldMemOperand(src, offset));
291 } else {
292 // Calculate the offset into the properties array.
293 int offset = index * kPointerSize + FixedArray::kHeaderSize;
294 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
295 __ ldr(dst, FieldMemOperand(dst, offset));
296 }
297}
298
299
300void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
301 Register receiver,
302 Register scratch,
303 Label* miss_label) {
304 // Check that the receiver isn't a smi.
305 __ tst(receiver, Operand(kSmiTagMask));
306 __ b(eq, miss_label);
307
308 // Check that the object is a JS array.
309 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
310 __ b(ne, miss_label);
311
312 // Load length directly from the JS array.
313 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
314 __ Ret();
315}
316
317
Andrei Popescu402d9372010-02-26 13:31:12 +0000318// Generate code to check if an object is a string. If the object is a
319// heap object, its map's instance type is left in the scratch1 register.
320// If this is not needed, scratch1 and scratch2 may be the same register.
Steve Blocka7e24c12009-10-30 11:49:00 +0000321static void GenerateStringCheck(MacroAssembler* masm,
322 Register receiver,
323 Register scratch1,
324 Register scratch2,
325 Label* smi,
326 Label* non_string_object) {
327 // Check that the receiver isn't a smi.
328 __ tst(receiver, Operand(kSmiTagMask));
329 __ b(eq, smi);
330
331 // Check that the object is a string.
332 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
333 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
334 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
335 // The cast is to resolve the overload for the argument of 0x0.
336 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
337 __ b(ne, non_string_object);
338}
339
340
341// Generate code to load the length from a string object and return the length.
342// If the receiver object is not a string or a wrapped string object the
343// execution continues at the miss label. The register containing the
344// receiver is potentially clobbered.
Andrei Popescu402d9372010-02-26 13:31:12 +0000345void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
346 Register receiver,
347 Register scratch1,
348 Register scratch2,
349 Label* miss) {
350 Label check_wrapper;
Steve Blocka7e24c12009-10-30 11:49:00 +0000351
Steve Blocka7e24c12009-10-30 11:49:00 +0000352 // Check if the object is a string leaving the instance type in the
353 // scratch1 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000354 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
Steve Blocka7e24c12009-10-30 11:49:00 +0000355
356 // Load length directly from the string.
Steve Blocka7e24c12009-10-30 11:49:00 +0000357 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000358 __ Ret();
359
360 // Check if the object is a JSValue wrapper.
361 __ bind(&check_wrapper);
362 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
363 __ b(ne, miss);
364
Andrei Popescu402d9372010-02-26 13:31:12 +0000365 // Unwrap the value and check if the wrapped value is a string.
366 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
367 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
368 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
Andrei Popescu402d9372010-02-26 13:31:12 +0000369 __ Ret();
Steve Blocka7e24c12009-10-30 11:49:00 +0000370}
371
372
373void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
374 Register receiver,
375 Register scratch1,
376 Register scratch2,
377 Label* miss_label) {
378 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
379 __ mov(r0, scratch1);
380 __ Ret();
381}
382
383
384// Generate StoreField code, value is passed in r0 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000385// When leaving generated code after success, the receiver_reg and name_reg
386// may be clobbered. Upon branch to miss_label, the receiver and name
387// registers have their original values.
Steve Blocka7e24c12009-10-30 11:49:00 +0000388void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Steve Blocka7e24c12009-10-30 11:49:00 +0000389 JSObject* object,
390 int index,
391 Map* transition,
392 Register receiver_reg,
393 Register name_reg,
394 Register scratch,
395 Label* miss_label) {
396 // r0 : value
397 Label exit;
398
399 // Check that the receiver isn't a smi.
400 __ tst(receiver_reg, Operand(kSmiTagMask));
401 __ b(eq, miss_label);
402
403 // Check that the map of the receiver hasn't changed.
404 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
405 __ cmp(scratch, Operand(Handle<Map>(object->map())));
406 __ b(ne, miss_label);
407
408 // Perform global security token check if needed.
409 if (object->IsJSGlobalProxy()) {
410 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
411 }
412
413 // Stub never generated for non-global objects that require access
414 // checks.
415 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
416
417 // Perform map transition for the receiver if necessary.
418 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
419 // The properties must be extended before we can store the value.
420 // We jump to a runtime call that extends the properties array.
Andrei Popescu402d9372010-02-26 13:31:12 +0000421 __ push(receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000422 __ mov(r2, Operand(Handle<Map>(transition)));
Steve Block6ded16b2010-05-10 14:33:55 +0100423 __ Push(r2, r0);
424 __ TailCallExternalReference(
Andrei Popescu402d9372010-02-26 13:31:12 +0000425 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)),
426 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000427 return;
428 }
429
430 if (transition != NULL) {
431 // Update the map of the object; no write barrier updating is
432 // needed because the map is never in new space.
433 __ mov(ip, Operand(Handle<Map>(transition)));
434 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
435 }
436
437 // Adjust for the number of properties stored in the object. Even in the
438 // face of a transition we can use the old map here because the size of the
439 // object and the number of in-object properties is not going to change.
440 index -= object->map()->inobject_properties();
441
442 if (index < 0) {
443 // Set the property straight into the object.
444 int offset = object->map()->instance_size() + (index * kPointerSize);
445 __ str(r0, FieldMemOperand(receiver_reg, offset));
446
447 // Skip updating write barrier if storing a smi.
448 __ tst(r0, Operand(kSmiTagMask));
449 __ b(eq, &exit);
450
451 // Update the write barrier for the array address.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100452 // Pass the now unused name_reg as a scratch register.
453 __ RecordWrite(receiver_reg, Operand(offset), name_reg, scratch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000454 } else {
455 // Write to the properties array.
456 int offset = index * kPointerSize + FixedArray::kHeaderSize;
457 // Get the properties array
458 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
459 __ str(r0, FieldMemOperand(scratch, offset));
460
461 // Skip updating write barrier if storing a smi.
462 __ tst(r0, Operand(kSmiTagMask));
463 __ b(eq, &exit);
464
465 // Update the write barrier for the array address.
466 // Ok to clobber receiver_reg and name_reg, since we return.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100467 __ RecordWrite(scratch, Operand(offset), name_reg, receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000468 }
469
470 // Return the value (register r0).
471 __ bind(&exit);
472 __ Ret();
473}
474
475
476void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
477 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
478 Code* code = NULL;
479 if (kind == Code::LOAD_IC) {
480 code = Builtins::builtin(Builtins::LoadIC_Miss);
481 } else {
482 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
483 }
484
485 Handle<Code> ic(code);
486 __ Jump(ic, RelocInfo::CODE_TARGET);
487}
488
489
Leon Clarke4515c472010-02-03 11:58:03 +0000490static void GenerateCallFunction(MacroAssembler* masm,
491 Object* object,
492 const ParameterCount& arguments,
493 Label* miss) {
494 // ----------- S t a t e -------------
495 // -- r0: receiver
496 // -- r1: function to call
497 // -----------------------------------
498
499 // Check that the function really is a function.
500 __ BranchOnSmi(r1, miss);
Andrei Popescu402d9372010-02-26 13:31:12 +0000501 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
Leon Clarke4515c472010-02-03 11:58:03 +0000502 __ b(ne, miss);
503
504 // Patch the receiver on the stack with the global proxy if
505 // necessary.
506 if (object->IsGlobalObject()) {
507 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
508 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
509 }
510
511 // Invoke the function.
512 __ InvokeFunction(r1, arguments, JUMP_FUNCTION);
513}
514
515
Leon Clarke4515c472010-02-03 11:58:03 +0000516static void PushInterceptorArguments(MacroAssembler* masm,
517 Register receiver,
518 Register holder,
519 Register name,
520 JSObject* holder_obj) {
Leon Clarke4515c472010-02-03 11:58:03 +0000521 __ push(name);
522 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
523 ASSERT(!Heap::InNewSpace(interceptor));
Steve Block6ded16b2010-05-10 14:33:55 +0100524 Register scratch = name;
Leon Clarke4515c472010-02-03 11:58:03 +0000525 __ mov(scratch, Operand(Handle<Object>(interceptor)));
526 __ push(scratch);
Steve Block6ded16b2010-05-10 14:33:55 +0100527 __ push(receiver);
528 __ push(holder);
Leon Clarke4515c472010-02-03 11:58:03 +0000529 __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
530 __ push(scratch);
531}
532
533
534static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
535 Register receiver,
536 Register holder,
537 Register name,
538 JSObject* holder_obj) {
539 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
540
541 ExternalReference ref =
542 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
543 __ mov(r0, Operand(5));
544 __ mov(r1, Operand(ref));
545
546 CEntryStub stub(1);
547 __ CallStub(&stub);
548}
549
550
Steve Block6ded16b2010-05-10 14:33:55 +0100551// Reserves space for the extra arguments to FastHandleApiCall in the
552// caller's frame.
553//
554// These arguments are set by CheckPrototypes and GenerateFastApiCall.
555static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
556 Register scratch) {
557 __ mov(scratch, Operand(Smi::FromInt(0)));
558 __ push(scratch);
559 __ push(scratch);
560 __ push(scratch);
561 __ push(scratch);
562}
563
564
565// Undoes the effects of ReserveSpaceForFastApiCall.
566static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
567 __ Drop(4);
568}
569
570
571// Generates call to FastHandleApiCall builtin.
572static void GenerateFastApiCall(MacroAssembler* masm,
573 const CallOptimization& optimization,
574 int argc) {
575 // Get the function and setup the context.
576 JSFunction* function = optimization.constant_function();
577 __ mov(r7, Operand(Handle<JSFunction>(function)));
578 __ ldr(cp, FieldMemOperand(r7, JSFunction::kContextOffset));
579
580 // Pass the additional arguments FastHandleApiCall expects.
581 bool info_loaded = false;
582 Object* callback = optimization.api_call_info()->callback();
583 if (Heap::InNewSpace(callback)) {
584 info_loaded = true;
585 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
586 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
587 } else {
588 __ Move(r6, Handle<Object>(callback));
589 }
590 Object* call_data = optimization.api_call_info()->data();
591 if (Heap::InNewSpace(call_data)) {
592 if (!info_loaded) {
593 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
594 }
595 __ ldr(r5, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
596 } else {
597 __ Move(r5, Handle<Object>(call_data));
598 }
599
600 __ add(sp, sp, Operand(1 * kPointerSize));
601 __ stm(ia, sp, r5.bit() | r6.bit() | r7.bit());
602 __ sub(sp, sp, Operand(1 * kPointerSize));
603
604 // Set the number of arguments.
605 __ mov(r0, Operand(argc + 4));
606
607 // Jump to the fast api call builtin (tail call).
608 Handle<Code> code = Handle<Code>(
609 Builtins::builtin(Builtins::FastHandleApiCall));
610 ParameterCount expected(0);
611 __ InvokeCode(code, expected, expected,
612 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
613}
614
615
616class CallInterceptorCompiler BASE_EMBEDDED {
617 public:
618 CallInterceptorCompiler(StubCompiler* stub_compiler,
619 const ParameterCount& arguments,
620 Register name)
621 : stub_compiler_(stub_compiler),
622 arguments_(arguments),
623 name_(name) {}
624
625 void Compile(MacroAssembler* masm,
626 JSObject* object,
627 JSObject* holder,
628 String* name,
629 LookupResult* lookup,
630 Register receiver,
631 Register scratch1,
632 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100633 Register scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100634 Label* miss) {
635 ASSERT(holder->HasNamedInterceptor());
636 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
637
638 // Check that the receiver isn't a smi.
639 __ BranchOnSmi(receiver, miss);
640
641 CallOptimization optimization(lookup);
642
643 if (optimization.is_constant_call()) {
644 CompileCacheable(masm,
645 object,
646 receiver,
647 scratch1,
648 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100649 scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100650 holder,
651 lookup,
652 name,
653 optimization,
654 miss);
655 } else {
656 CompileRegular(masm,
657 object,
658 receiver,
659 scratch1,
660 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100661 scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100662 name,
663 holder,
664 miss);
665 }
666 }
667
668 private:
669 void CompileCacheable(MacroAssembler* masm,
670 JSObject* object,
671 Register receiver,
672 Register scratch1,
673 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100674 Register scratch3,
Leon Clarkef7060e22010-06-03 12:02:55 +0100675 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100676 LookupResult* lookup,
677 String* name,
678 const CallOptimization& optimization,
679 Label* miss_label) {
680 ASSERT(optimization.is_constant_call());
681 ASSERT(!lookup->holder()->IsGlobalObject());
682
683 int depth1 = kInvalidProtoDepth;
684 int depth2 = kInvalidProtoDepth;
685 bool can_do_fast_api_call = false;
686 if (optimization.is_simple_api_call() &&
687 !lookup->holder()->IsGlobalObject()) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100688 depth1 =
689 optimization.GetPrototypeDepthOfExpectedType(object,
690 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100691 if (depth1 == kInvalidProtoDepth) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100692 depth2 =
693 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
694 lookup->holder());
Steve Block6ded16b2010-05-10 14:33:55 +0100695 }
696 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
697 (depth2 != kInvalidProtoDepth);
698 }
699
700 __ IncrementCounter(&Counters::call_const_interceptor, 1,
701 scratch1, scratch2);
702
703 if (can_do_fast_api_call) {
704 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1,
705 scratch1, scratch2);
706 ReserveSpaceForFastApiCall(masm, scratch1);
707 }
708
Leon Clarkef7060e22010-06-03 12:02:55 +0100709 // Check that the maps from receiver to interceptor's holder
710 // haven't changed and thus we can invoke interceptor.
Steve Block6ded16b2010-05-10 14:33:55 +0100711 Label miss_cleanup;
712 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
713 Register holder =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100714 stub_compiler_->CheckPrototypes(object, receiver,
715 interceptor_holder, scratch1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100716 scratch2, scratch3, name, depth1, miss);
Steve Block6ded16b2010-05-10 14:33:55 +0100717
Leon Clarkef7060e22010-06-03 12:02:55 +0100718 // Invoke an interceptor and if it provides a value,
719 // branch to |regular_invoke|.
Steve Block6ded16b2010-05-10 14:33:55 +0100720 Label regular_invoke;
Leon Clarkef7060e22010-06-03 12:02:55 +0100721 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
Steve Block6ded16b2010-05-10 14:33:55 +0100722 &regular_invoke);
723
Leon Clarkef7060e22010-06-03 12:02:55 +0100724 // Interceptor returned nothing for this property. Try to use cached
725 // constant function.
Steve Block6ded16b2010-05-10 14:33:55 +0100726
Leon Clarkef7060e22010-06-03 12:02:55 +0100727 // Check that the maps from interceptor's holder to constant function's
728 // holder haven't changed and thus we can use cached constant function.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100729 if (interceptor_holder != lookup->holder()) {
730 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
731 lookup->holder(), scratch1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100732 scratch2, scratch3, name, depth2, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100733 } else {
734 // CheckPrototypes has a side effect of fetching a 'holder'
735 // for API (object which is instanceof for the signature). It's
736 // safe to omit it here, as if present, it should be fetched
737 // by the previous CheckPrototypes.
738 ASSERT(depth2 == kInvalidProtoDepth);
739 }
Steve Block6ded16b2010-05-10 14:33:55 +0100740
Leon Clarkef7060e22010-06-03 12:02:55 +0100741 // Invoke function.
Steve Block6ded16b2010-05-10 14:33:55 +0100742 if (can_do_fast_api_call) {
743 GenerateFastApiCall(masm, optimization, arguments_.immediate());
744 } else {
745 __ InvokeFunction(optimization.constant_function(), arguments_,
746 JUMP_FUNCTION);
747 }
748
Leon Clarkef7060e22010-06-03 12:02:55 +0100749 // Deferred code for fast API call case---clean preallocated space.
Steve Block6ded16b2010-05-10 14:33:55 +0100750 if (can_do_fast_api_call) {
751 __ bind(&miss_cleanup);
752 FreeSpaceForFastApiCall(masm);
753 __ b(miss_label);
754 }
755
Leon Clarkef7060e22010-06-03 12:02:55 +0100756 // Invoke a regular function.
Steve Block6ded16b2010-05-10 14:33:55 +0100757 __ bind(&regular_invoke);
758 if (can_do_fast_api_call) {
759 FreeSpaceForFastApiCall(masm);
760 }
761 }
762
763 void CompileRegular(MacroAssembler* masm,
764 JSObject* object,
765 Register receiver,
766 Register scratch1,
767 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100768 Register scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100769 String* name,
Leon Clarkef7060e22010-06-03 12:02:55 +0100770 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100771 Label* miss_label) {
772 Register holder =
Leon Clarkef7060e22010-06-03 12:02:55 +0100773 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100774 scratch1, scratch2, scratch3, name,
Steve Block6ded16b2010-05-10 14:33:55 +0100775 miss_label);
776
777 // Call a runtime function to load the interceptor property.
778 __ EnterInternalFrame();
779 // Save the name_ register across the call.
780 __ push(name_);
781
782 PushInterceptorArguments(masm,
783 receiver,
784 holder,
785 name_,
Leon Clarkef7060e22010-06-03 12:02:55 +0100786 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100787
788 __ CallExternalReference(
789 ExternalReference(
790 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
791 5);
792
793 // Restore the name_ register.
794 __ pop(name_);
795 __ LeaveInternalFrame();
796 }
797
798 void LoadWithInterceptor(MacroAssembler* masm,
799 Register receiver,
800 Register holder,
801 JSObject* holder_obj,
802 Register scratch,
803 Label* interceptor_succeeded) {
804 __ EnterInternalFrame();
805 __ Push(holder, name_);
806
807 CompileCallLoadPropertyWithInterceptor(masm,
808 receiver,
809 holder,
810 name_,
811 holder_obj);
812
813 __ pop(name_); // Restore the name.
814 __ pop(receiver); // Restore the holder.
815 __ LeaveInternalFrame();
816
817 // If interceptor returns no-result sentinel, call the constant function.
818 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
819 __ cmp(r0, scratch);
820 __ b(ne, interceptor_succeeded);
821 }
822
823 StubCompiler* stub_compiler_;
824 const ParameterCount& arguments_;
825 Register name_;
826};
827
828
829// Generate code to check that a global property cell is empty. Create
830// the property cell at compilation time if no cell exists for the
831// property.
832static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
833 GlobalObject* global,
834 String* name,
835 Register scratch,
836 Label* miss) {
837 Object* probe = global->EnsurePropertyCell(name);
838 if (probe->IsFailure()) return probe;
839 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
840 ASSERT(cell->value()->IsTheHole());
841 __ mov(scratch, Operand(Handle<Object>(cell)));
842 __ ldr(scratch,
843 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
844 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
845 __ cmp(scratch, ip);
846 __ b(ne, miss);
847 return cell;
848}
849
850
Steve Blocka7e24c12009-10-30 11:49:00 +0000851#undef __
852#define __ ACCESS_MASM(masm())
853
854
855Register StubCompiler::CheckPrototypes(JSObject* object,
856 Register object_reg,
857 JSObject* holder,
858 Register holder_reg,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100859 Register scratch1,
860 Register scratch2,
Steve Blocka7e24c12009-10-30 11:49:00 +0000861 String* name,
Andrei Popescu402d9372010-02-26 13:31:12 +0000862 int save_at_depth,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100863 Label* miss) {
864 // Make sure there's no overlap between holder and object registers.
865 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
866 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
867 && !scratch2.is(scratch1));
868
869 // Keep track of the current object in register reg.
870 Register reg = object_reg;
871 int depth = 0;
872
873 if (save_at_depth == depth) {
874 __ str(reg, MemOperand(sp));
875 }
876
877 // Check the maps in the prototype chain.
878 // Traverse the prototype chain from the object and do map checks.
879 JSObject* current = object;
880 while (current != holder) {
881 depth++;
882
883 // Only global objects and objects that do not require access
884 // checks are allowed in stubs.
885 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
886
887 JSObject* prototype = JSObject::cast(current->GetPrototype());
888 if (!current->HasFastProperties() &&
889 !current->IsJSGlobalObject() &&
890 !current->IsJSGlobalProxy()) {
891 if (!name->IsSymbol()) {
892 Object* lookup_result = Heap::LookupSymbol(name);
893 if (lookup_result->IsFailure()) {
894 set_failure(Failure::cast(lookup_result));
895 return reg;
896 } else {
897 name = String::cast(lookup_result);
898 }
899 }
900 ASSERT(current->property_dictionary()->FindEntry(name) ==
901 StringDictionary::kNotFound);
902
903 GenerateDictionaryNegativeLookup(masm(),
904 miss,
905 reg,
906 name,
907 scratch1,
908 scratch2);
909 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
910 reg = holder_reg; // from now the object is in holder_reg
911 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
912 } else {
913 // Get the map of the current object.
914 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
915 __ cmp(scratch1, Operand(Handle<Map>(current->map())));
916
917 // Branch on the result of the map check.
918 __ b(ne, miss);
919
920 // Check access rights to the global object. This has to happen
921 // after the map check so that we know that the object is
922 // actually a global object.
923 if (current->IsJSGlobalProxy()) {
924 __ CheckAccessGlobalProxy(reg, scratch1, miss);
925 // Restore scratch register to be the map of the object. In the
926 // new space case below, we load the prototype from the map in
927 // the scratch register.
928 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
929 }
930
931 reg = holder_reg; // from now the object is in holder_reg
932 if (Heap::InNewSpace(prototype)) {
933 // The prototype is in new space; we cannot store a reference
934 // to it in the code. Load it from the map.
935 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
936 } else {
937 // The prototype is in old space; load it directly.
938 __ mov(reg, Operand(Handle<JSObject>(prototype)));
939 }
940 }
941
942 if (save_at_depth == depth) {
943 __ str(reg, MemOperand(sp));
944 }
945
946 // Go to the next object in the prototype chain.
947 current = prototype;
948 }
949
950 // Check the holder map.
951 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
952 __ cmp(scratch1, Operand(Handle<Map>(current->map())));
953 __ b(ne, miss);
954
955 // Log the check depth.
956 LOG(IntEvent("check-maps-depth", depth + 1));
957
958 // Perform security check for access to the global object and return
959 // the holder register.
960 ASSERT(current == holder);
961 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
962 if (current->IsJSGlobalProxy()) {
963 __ CheckAccessGlobalProxy(reg, scratch1, miss);
964 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000965
966 // If we've skipped any global objects, it's not enough to verify
Steve Block6ded16b2010-05-10 14:33:55 +0100967 // that their maps haven't changed. We also need to check that the
968 // property cell for the property is still empty.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100969 current = object;
970 while (current != holder) {
971 if (current->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100972 Object* cell = GenerateCheckPropertyCell(masm(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100973 GlobalObject::cast(current),
Steve Block6ded16b2010-05-10 14:33:55 +0100974 name,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100975 scratch1,
Steve Block6ded16b2010-05-10 14:33:55 +0100976 miss);
977 if (cell->IsFailure()) {
978 set_failure(Failure::cast(cell));
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100979 return reg;
Steve Blocka7e24c12009-10-30 11:49:00 +0000980 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000981 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100982 current = JSObject::cast(current->GetPrototype());
Steve Blocka7e24c12009-10-30 11:49:00 +0000983 }
984
Andrei Popescu402d9372010-02-26 13:31:12 +0000985 // Return the register containing the holder.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100986 return reg;
Steve Blocka7e24c12009-10-30 11:49:00 +0000987}
988
989
990void StubCompiler::GenerateLoadField(JSObject* object,
991 JSObject* holder,
992 Register receiver,
993 Register scratch1,
994 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100995 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +0000996 int index,
997 String* name,
998 Label* miss) {
999 // Check that the receiver isn't a smi.
1000 __ tst(receiver, Operand(kSmiTagMask));
1001 __ b(eq, miss);
1002
1003 // Check that the maps haven't changed.
1004 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001005 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1006 name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001007 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
1008 __ Ret();
1009}
1010
1011
1012void StubCompiler::GenerateLoadConstant(JSObject* object,
1013 JSObject* holder,
1014 Register receiver,
1015 Register scratch1,
1016 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001017 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001018 Object* value,
1019 String* name,
1020 Label* miss) {
1021 // Check that the receiver isn't a smi.
1022 __ tst(receiver, Operand(kSmiTagMask));
1023 __ b(eq, miss);
1024
1025 // Check that the maps haven't changed.
1026 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001027 CheckPrototypes(object, receiver, holder,
1028 scratch1, scratch2, scratch3, name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001029
1030 // Return the constant value.
1031 __ mov(r0, Operand(Handle<Object>(value)));
1032 __ Ret();
1033}
1034
1035
Leon Clarkee46be812010-01-19 14:06:41 +00001036bool StubCompiler::GenerateLoadCallback(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001037 JSObject* holder,
1038 Register receiver,
1039 Register name_reg,
1040 Register scratch1,
1041 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001042 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001043 AccessorInfo* callback,
1044 String* name,
Leon Clarkee46be812010-01-19 14:06:41 +00001045 Label* miss,
1046 Failure** failure) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001047 // Check that the receiver isn't a smi.
1048 __ tst(receiver, Operand(kSmiTagMask));
1049 __ b(eq, miss);
1050
1051 // Check that the maps haven't changed.
1052 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001053 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1054 name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001055
1056 // Push the arguments on the JS stack of the caller.
Steve Block6ded16b2010-05-10 14:33:55 +01001057 __ push(receiver); // Receiver.
1058 __ push(reg); // Holder.
Steve Blocka7e24c12009-10-30 11:49:00 +00001059 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
Steve Blocka7e24c12009-10-30 11:49:00 +00001060 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
Steve Block6ded16b2010-05-10 14:33:55 +01001061 __ Push(ip, reg, name_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +00001062
1063 // Do tail-call to the runtime system.
1064 ExternalReference load_callback_property =
1065 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001066 __ TailCallExternalReference(load_callback_property, 5, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00001067
1068 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001069}
1070
1071
1072void StubCompiler::GenerateLoadInterceptor(JSObject* object,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001073 JSObject* interceptor_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +00001074 LookupResult* lookup,
1075 Register receiver,
1076 Register name_reg,
1077 Register scratch1,
1078 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001079 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 String* name,
1081 Label* miss) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001082 ASSERT(interceptor_holder->HasNamedInterceptor());
1083 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1084
1085 // Check that the receiver isn't a smi.
1086 __ BranchOnSmi(receiver, miss);
1087
1088 // So far the most popular follow ups for interceptor loads are FIELD
1089 // and CALLBACKS, so inline only them, other cases may be added
1090 // later.
1091 bool compile_followup_inline = false;
1092 if (lookup->IsProperty() && lookup->IsCacheable()) {
1093 if (lookup->type() == FIELD) {
1094 compile_followup_inline = true;
1095 } else if (lookup->type() == CALLBACKS &&
1096 lookup->GetCallbackObject()->IsAccessorInfo() &&
1097 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
1098 compile_followup_inline = true;
1099 }
1100 }
1101
1102 if (compile_followup_inline) {
1103 // Compile the interceptor call, followed by inline code to load the
1104 // property from further up the prototype chain if the call fails.
1105 // Check that the maps haven't changed.
1106 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001107 scratch1, scratch2, scratch3,
1108 name, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001109 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1110
1111 // Save necessary data before invoking an interceptor.
1112 // Requires a frame to make GC aware of pushed pointers.
1113 __ EnterInternalFrame();
1114
1115 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1116 // CALLBACKS case needs a receiver to be passed into C++ callback.
1117 __ Push(receiver, holder_reg, name_reg);
1118 } else {
1119 __ Push(holder_reg, name_reg);
1120 }
1121
1122 // Invoke an interceptor. Note: map checks from receiver to
1123 // interceptor's holder has been compiled before (see a caller
1124 // of this method.)
1125 CompileCallLoadPropertyWithInterceptor(masm(),
1126 receiver,
1127 holder_reg,
1128 name_reg,
1129 interceptor_holder);
1130
1131 // Check if interceptor provided a value for property. If it's
1132 // the case, return immediately.
1133 Label interceptor_failed;
1134 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1135 __ cmp(r0, scratch1);
1136 __ b(eq, &interceptor_failed);
1137 __ LeaveInternalFrame();
1138 __ Ret();
1139
1140 __ bind(&interceptor_failed);
1141 __ pop(name_reg);
1142 __ pop(holder_reg);
1143 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1144 __ pop(receiver);
1145 }
1146
1147 __ LeaveInternalFrame();
1148
1149 // Check that the maps from interceptor's holder to lookup's holder
1150 // haven't changed. And load lookup's holder into |holder| register.
1151 if (interceptor_holder != lookup->holder()) {
1152 holder_reg = CheckPrototypes(interceptor_holder,
1153 holder_reg,
1154 lookup->holder(),
1155 scratch1,
1156 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001157 scratch3,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001158 name,
1159 miss);
1160 }
1161
1162 if (lookup->type() == FIELD) {
1163 // We found FIELD property in prototype chain of interceptor's holder.
1164 // Retrieve a field from field's holder.
1165 GenerateFastPropertyLoad(masm(), r0, holder_reg,
1166 lookup->holder(), lookup->GetFieldIndex());
1167 __ Ret();
1168 } else {
1169 // We found CALLBACKS property in prototype chain of interceptor's
1170 // holder.
1171 ASSERT(lookup->type() == CALLBACKS);
1172 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
1173 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1174 ASSERT(callback != NULL);
1175 ASSERT(callback->getter() != NULL);
1176
1177 // Tail call to runtime.
1178 // Important invariant in CALLBACKS case: the code above must be
1179 // structured to never clobber |receiver| register.
1180 __ Move(scratch2, Handle<AccessorInfo>(callback));
1181 // holder_reg is either receiver or scratch1.
1182 if (!receiver.is(holder_reg)) {
1183 ASSERT(scratch1.is(holder_reg));
1184 __ Push(receiver, holder_reg, scratch2);
1185 __ ldr(scratch1,
1186 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
1187 __ Push(scratch1, name_reg);
1188 } else {
1189 __ push(receiver);
1190 __ ldr(scratch1,
1191 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
1192 __ Push(holder_reg, scratch2, scratch1, name_reg);
1193 }
1194
1195 ExternalReference ref =
1196 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
1197 __ TailCallExternalReference(ref, 5, 1);
1198 }
1199 } else { // !compile_followup_inline
1200 // Call the runtime system to load the interceptor.
1201 // Check that the maps haven't changed.
1202 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001203 scratch1, scratch2, scratch3,
1204 name, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001205 PushInterceptorArguments(masm(), receiver, holder_reg,
1206 name_reg, interceptor_holder);
1207
1208 ExternalReference ref = ExternalReference(
1209 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
1210 __ TailCallExternalReference(ref, 5, 1);
1211 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001212}
1213
1214
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001215void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
1216 if (kind_ == Code::KEYED_CALL_IC) {
1217 __ cmp(r2, Operand(Handle<String>(name)));
1218 __ b(ne, miss);
1219 }
1220}
1221
1222
Ben Murdochbb769b22010-08-11 14:56:33 +01001223Object* CallStubCompiler::GenerateMissBranch() {
1224 Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
1225 if (obj->IsFailure()) return obj;
1226 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1227 return obj;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001228}
1229
1230
Andrei Popescu402d9372010-02-26 13:31:12 +00001231Object* CallStubCompiler::CompileCallField(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001232 JSObject* holder,
1233 int index,
1234 String* name) {
1235 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001236 // -- r2 : name
1237 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001238 // -----------------------------------
1239 Label miss;
1240
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001241 GenerateNameCheck(name, &miss);
1242
Steve Blocka7e24c12009-10-30 11:49:00 +00001243 const int argc = arguments().immediate();
1244
1245 // Get the receiver of the function from the stack into r0.
1246 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1247 // Check that the receiver isn't a smi.
1248 __ tst(r0, Operand(kSmiTagMask));
1249 __ b(eq, &miss);
1250
1251 // Do the right check and compute the holder register.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001252 Register reg = CheckPrototypes(object, r0, holder, r1, r3, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001253 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
1254
Leon Clarke4515c472010-02-03 11:58:03 +00001255 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001256
1257 // Handle call cache miss.
1258 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001259 Object* obj = GenerateMissBranch();
1260 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001261
1262 // Return the generated code.
1263 return GetCode(FIELD, name);
1264}
1265
1266
Steve Block6ded16b2010-05-10 14:33:55 +01001267Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1268 JSObject* holder,
1269 JSFunction* function,
1270 String* name,
1271 CheckType check) {
1272 // ----------- S t a t e -------------
1273 // -- r2 : name
1274 // -- lr : return address
1275 // -----------------------------------
1276
1277 // If object is not an array, bail out to regular call.
1278 if (!object->IsJSArray()) {
1279 return Heap::undefined_value();
1280 }
1281
1282 // TODO(639): faster implementation.
1283 ASSERT(check == RECEIVER_MAP_CHECK);
1284
1285 Label miss;
1286
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001287 GenerateNameCheck(name, &miss);
1288
Steve Block6ded16b2010-05-10 14:33:55 +01001289 // Get the receiver from the stack
1290 const int argc = arguments().immediate();
1291 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1292
1293 // Check that the receiver isn't a smi.
1294 __ tst(r1, Operand(kSmiTagMask));
1295 __ b(eq, &miss);
1296
1297 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001298 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001299
Steve Block6ded16b2010-05-10 14:33:55 +01001300 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1301 argc + 1,
1302 1);
1303
1304 // Handle call cache miss.
1305 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001306 Object* obj = GenerateMissBranch();
1307 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +01001308
1309 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001310 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001311}
1312
1313
1314Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1315 JSObject* holder,
1316 JSFunction* function,
1317 String* name,
1318 CheckType check) {
1319 // ----------- S t a t e -------------
1320 // -- r2 : name
1321 // -- lr : return address
1322 // -----------------------------------
1323
1324 // If object is not an array, bail out to regular call.
1325 if (!object->IsJSArray()) {
1326 return Heap::undefined_value();
1327 }
1328
1329 // TODO(642): faster implementation.
1330 ASSERT(check == RECEIVER_MAP_CHECK);
1331
1332 Label miss;
1333
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001334 GenerateNameCheck(name, &miss);
1335
Steve Block6ded16b2010-05-10 14:33:55 +01001336 // Get the receiver from the stack
1337 const int argc = arguments().immediate();
1338 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1339
1340 // Check that the receiver isn't a smi.
1341 __ tst(r1, Operand(kSmiTagMask));
1342 __ b(eq, &miss);
1343
1344 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001345 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001346
Steve Block6ded16b2010-05-10 14:33:55 +01001347 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1348 argc + 1,
1349 1);
1350
1351 // Handle call cache miss.
1352 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001353 Object* obj = GenerateMissBranch();
1354 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +01001355
1356 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001357 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001358}
1359
1360
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001361Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
1362 JSObject* holder,
1363 JSFunction* function,
1364 String* name,
1365 CheckType check) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001366 // ----------- S t a t e -------------
1367 // -- r2 : function name
1368 // -- lr : return address
1369 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1370 // -- ...
1371 // -- sp[argc * 4] : receiver
1372 // -----------------------------------
1373
1374 // If object is not a string, bail out to regular call.
1375 if (!object->IsString()) return Heap::undefined_value();
1376
1377 const int argc = arguments().immediate();
1378
1379 Label miss;
1380 Label index_out_of_range;
1381 GenerateNameCheck(name, &miss);
1382
1383 // Check that the maps starting from the prototype haven't changed.
1384 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1385 Context::STRING_FUNCTION_INDEX,
1386 r0);
1387 ASSERT(object != holder);
1388 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder,
1389 r1, r3, r4, name, &miss);
1390
1391 Register receiver = r1;
1392 Register index = r4;
1393 Register scratch = r3;
1394 Register result = r0;
1395 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
1396 if (argc > 0) {
1397 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
1398 } else {
1399 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1400 }
1401
1402 StringCharCodeAtGenerator char_code_at_generator(receiver,
1403 index,
1404 scratch,
1405 result,
1406 &miss, // When not a string.
1407 &miss, // When not a number.
1408 &index_out_of_range,
1409 STRING_INDEX_IS_NUMBER);
1410 char_code_at_generator.GenerateFast(masm());
1411 __ Drop(argc + 1);
1412 __ Ret();
1413
1414 ICRuntimeCallHelper call_helper;
1415 char_code_at_generator.GenerateSlow(masm(), call_helper);
1416
1417 __ bind(&index_out_of_range);
1418 __ LoadRoot(r0, Heap::kNanValueRootIndex);
1419 __ Drop(argc + 1);
1420 __ Ret();
1421
1422 __ bind(&miss);
1423 Object* obj = GenerateMissBranch();
1424 if (obj->IsFailure()) return obj;
1425
1426 // Return the generated code.
1427 return GetCode(function);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001428}
1429
1430
1431Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
1432 JSObject* holder,
1433 JSFunction* function,
1434 String* name,
1435 CheckType check) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001436 // ----------- S t a t e -------------
1437 // -- r2 : function name
1438 // -- lr : return address
1439 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1440 // -- ...
1441 // -- sp[argc * 4] : receiver
1442 // -----------------------------------
1443
1444 // If object is not a string, bail out to regular call.
1445 if (!object->IsString()) return Heap::undefined_value();
1446
1447 const int argc = arguments().immediate();
1448
1449 Label miss;
1450 Label index_out_of_range;
1451
1452 GenerateNameCheck(name, &miss);
1453
1454 // Check that the maps starting from the prototype haven't changed.
1455 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1456 Context::STRING_FUNCTION_INDEX,
1457 r0);
1458 ASSERT(object != holder);
1459 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder,
1460 r1, r3, r4, name, &miss);
1461
1462 Register receiver = r0;
1463 Register index = r4;
1464 Register scratch1 = r1;
1465 Register scratch2 = r3;
1466 Register result = r0;
1467 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
1468 if (argc > 0) {
1469 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
1470 } else {
1471 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1472 }
1473
1474 StringCharAtGenerator char_at_generator(receiver,
1475 index,
1476 scratch1,
1477 scratch2,
1478 result,
1479 &miss, // When not a string.
1480 &miss, // When not a number.
1481 &index_out_of_range,
1482 STRING_INDEX_IS_NUMBER);
1483 char_at_generator.GenerateFast(masm());
1484 __ Drop(argc + 1);
1485 __ Ret();
1486
1487 ICRuntimeCallHelper call_helper;
1488 char_at_generator.GenerateSlow(masm(), call_helper);
1489
1490 __ bind(&index_out_of_range);
1491 __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
1492 __ Drop(argc + 1);
1493 __ Ret();
1494
1495 __ bind(&miss);
1496 Object* obj = GenerateMissBranch();
1497 if (obj->IsFailure()) return obj;
1498
1499 // Return the generated code.
1500 return GetCode(function);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001501}
1502
1503
Steve Blocka7e24c12009-10-30 11:49:00 +00001504Object* CallStubCompiler::CompileCallConstant(Object* object,
1505 JSObject* holder,
1506 JSFunction* function,
1507 String* name,
1508 CheckType check) {
1509 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001510 // -- r2 : name
1511 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001512 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001513 SharedFunctionInfo* function_info = function->shared();
1514 if (function_info->HasCustomCallGenerator()) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001515 const int id = function_info->custom_call_generator_id();
1516 Object* result =
1517 CompileCustomCall(id, object, holder, function, name, check);
Steve Block6ded16b2010-05-10 14:33:55 +01001518 // undefined means bail out to regular compiler.
1519 if (!result->IsUndefined()) {
1520 return result;
1521 }
1522 }
1523
1524 Label miss_in_smi_check;
Steve Blocka7e24c12009-10-30 11:49:00 +00001525
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001526 GenerateNameCheck(name, &miss_in_smi_check);
1527
Steve Blocka7e24c12009-10-30 11:49:00 +00001528 // Get the receiver from the stack
1529 const int argc = arguments().immediate();
1530 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1531
1532 // Check that the receiver isn't a smi.
1533 if (check != NUMBER_CHECK) {
1534 __ tst(r1, Operand(kSmiTagMask));
Steve Block6ded16b2010-05-10 14:33:55 +01001535 __ b(eq, &miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001536 }
1537
1538 // Make sure that it's okay not to patch the on stack receiver
1539 // unless we're doing a receiver map check.
1540 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1541
Steve Block6ded16b2010-05-10 14:33:55 +01001542 CallOptimization optimization(function);
1543 int depth = kInvalidProtoDepth;
1544 Label miss;
1545
Steve Blocka7e24c12009-10-30 11:49:00 +00001546 switch (check) {
1547 case RECEIVER_MAP_CHECK:
Steve Block6ded16b2010-05-10 14:33:55 +01001548 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1549
1550 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1551 depth = optimization.GetPrototypeDepthOfExpectedType(
1552 JSObject::cast(object), holder);
1553 }
1554
1555 if (depth != kInvalidProtoDepth) {
1556 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1557 ReserveSpaceForFastApiCall(masm(), r0);
1558 }
1559
Steve Blocka7e24c12009-10-30 11:49:00 +00001560 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001561 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
Steve Block6ded16b2010-05-10 14:33:55 +01001562 depth, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001563
1564 // Patch the receiver on the stack with the global proxy if
1565 // necessary.
1566 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001567 ASSERT(depth == kInvalidProtoDepth);
Steve Blocka7e24c12009-10-30 11:49:00 +00001568 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1569 __ str(r3, MemOperand(sp, argc * kPointerSize));
1570 }
1571 break;
1572
1573 case STRING_CHECK:
Leon Clarkee46be812010-01-19 14:06:41 +00001574 if (!function->IsBuiltin()) {
1575 // Calling non-builtins with a value as receiver requires boxing.
1576 __ jmp(&miss);
1577 } else {
1578 // Check that the object is a two-byte string or a symbol.
Andrei Popescu402d9372010-02-26 13:31:12 +00001579 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001580 __ b(hs, &miss);
1581 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001582 GenerateDirectLoadGlobalFunctionPrototype(
1583 masm(), Context::STRING_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001584 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001585 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001586 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001587 break;
1588
1589 case NUMBER_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001590 if (!function->IsBuiltin()) {
1591 // Calling non-builtins with a value as receiver requires boxing.
1592 __ jmp(&miss);
1593 } else {
1594 Label fast;
1595 // Check that the object is a smi or a heap number.
1596 __ tst(r1, Operand(kSmiTagMask));
1597 __ b(eq, &fast);
Andrei Popescu402d9372010-02-26 13:31:12 +00001598 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001599 __ b(ne, &miss);
1600 __ bind(&fast);
1601 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001602 GenerateDirectLoadGlobalFunctionPrototype(
1603 masm(), Context::NUMBER_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001604 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001605 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001606 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001607 break;
1608 }
1609
1610 case BOOLEAN_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001611 if (!function->IsBuiltin()) {
1612 // Calling non-builtins with a value as receiver requires boxing.
1613 __ jmp(&miss);
1614 } else {
1615 Label fast;
1616 // Check that the object is a boolean.
1617 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1618 __ cmp(r1, ip);
1619 __ b(eq, &fast);
1620 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1621 __ cmp(r1, ip);
1622 __ b(ne, &miss);
1623 __ bind(&fast);
1624 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001625 GenerateDirectLoadGlobalFunctionPrototype(
1626 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001627 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001628 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001629 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001630 break;
1631 }
1632
Steve Blocka7e24c12009-10-30 11:49:00 +00001633 default:
1634 UNREACHABLE();
1635 }
1636
Steve Block6ded16b2010-05-10 14:33:55 +01001637 if (depth != kInvalidProtoDepth) {
1638 GenerateFastApiCall(masm(), optimization, argc);
1639 } else {
1640 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1641 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001642
1643 // Handle call cache miss.
1644 __ bind(&miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001645 if (depth != kInvalidProtoDepth) {
1646 FreeSpaceForFastApiCall(masm());
1647 }
1648
1649 __ bind(&miss_in_smi_check);
Ben Murdochbb769b22010-08-11 14:56:33 +01001650 Object* obj = GenerateMissBranch();
1651 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001652
1653 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001654 return GetCode(function);
Steve Blocka7e24c12009-10-30 11:49:00 +00001655}
1656
1657
Andrei Popescu402d9372010-02-26 13:31:12 +00001658Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001659 JSObject* holder,
1660 String* name) {
1661 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001662 // -- r2 : name
1663 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001664 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001665
Steve Block6ded16b2010-05-10 14:33:55 +01001666 Label miss;
Andrei Popescu402d9372010-02-26 13:31:12 +00001667
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001668 GenerateNameCheck(name, &miss);
1669
Leon Clarke4515c472010-02-03 11:58:03 +00001670 // Get the number of arguments.
1671 const int argc = arguments().immediate();
1672
1673 LookupResult lookup;
1674 LookupPostInterceptor(holder, name, &lookup);
1675
Steve Block6ded16b2010-05-10 14:33:55 +01001676 // Get the receiver from the stack.
1677 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001678
Steve Block6ded16b2010-05-10 14:33:55 +01001679 CallInterceptorCompiler compiler(this, arguments(), r2);
1680 compiler.Compile(masm(),
1681 object,
1682 holder,
1683 name,
1684 &lookup,
1685 r1,
1686 r3,
1687 r4,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001688 r0,
Steve Block6ded16b2010-05-10 14:33:55 +01001689 &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001690
1691 // Move returned value, the function to call, to r1.
1692 __ mov(r1, r0);
Leon Clarke4515c472010-02-03 11:58:03 +00001693 // Restore receiver.
Steve Block6ded16b2010-05-10 14:33:55 +01001694 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001695
1696 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001697
1698 // Handle call cache miss.
1699 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001700 Object* obj = GenerateMissBranch();
1701 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001702
1703 // Return the generated code.
1704 return GetCode(INTERCEPTOR, name);
1705}
1706
1707
1708Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1709 GlobalObject* holder,
1710 JSGlobalPropertyCell* cell,
1711 JSFunction* function,
1712 String* name) {
1713 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001714 // -- r2 : name
1715 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001716 // -----------------------------------
1717 Label miss;
1718
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001719 GenerateNameCheck(name, &miss);
1720
Steve Blocka7e24c12009-10-30 11:49:00 +00001721 // Get the number of arguments.
1722 const int argc = arguments().immediate();
1723
1724 // Get the receiver from the stack.
1725 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1726
1727 // If the object is the holder then we know that it's a global
1728 // object which can only happen for contextual calls. In this case,
1729 // the receiver cannot be a smi.
1730 if (object != holder) {
1731 __ tst(r0, Operand(kSmiTagMask));
1732 __ b(eq, &miss);
1733 }
1734
1735 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001736 CheckPrototypes(object, r0, holder, r3, r1, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001737
1738 // Get the value from the cell.
1739 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1740 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1741
1742 // Check that the cell contains the same function.
Leon Clarkee46be812010-01-19 14:06:41 +00001743 if (Heap::InNewSpace(function)) {
1744 // We can't embed a pointer to a function in new space so we have
1745 // to verify that the shared function info is unchanged. This has
1746 // the nice side effect that multiple closures based on the same
1747 // function can all use this call IC. Before we load through the
1748 // function, we have to verify that it still is a function.
1749 __ tst(r1, Operand(kSmiTagMask));
1750 __ b(eq, &miss);
1751 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1752 __ b(ne, &miss);
1753
1754 // Check the shared function info. Make sure it hasn't changed.
1755 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
Andrei Popescu402d9372010-02-26 13:31:12 +00001756 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1757 __ cmp(r4, r3);
Leon Clarkee46be812010-01-19 14:06:41 +00001758 __ b(ne, &miss);
1759 } else {
1760 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1761 __ b(ne, &miss);
1762 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001763
1764 // Patch the receiver on the stack with the global proxy if
1765 // necessary.
1766 if (object->IsGlobalObject()) {
1767 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1768 __ str(r3, MemOperand(sp, argc * kPointerSize));
1769 }
1770
1771 // Setup the context (function already in r1).
1772 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1773
1774 // Jump to the cached code (tail call).
Steve Block6ded16b2010-05-10 14:33:55 +01001775 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001776 ASSERT(function->is_compiled());
1777 Handle<Code> code(function->code());
1778 ParameterCount expected(function->shared()->formal_parameter_count());
1779 __ InvokeCode(code, expected, arguments(),
1780 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1781
1782 // Handle call cache miss.
1783 __ bind(&miss);
1784 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
Ben Murdochbb769b22010-08-11 14:56:33 +01001785 Object* obj = GenerateMissBranch();
1786 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001787
1788 // Return the generated code.
1789 return GetCode(NORMAL, name);
1790}
1791
1792
1793Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1794 int index,
1795 Map* transition,
1796 String* name) {
1797 // ----------- S t a t e -------------
1798 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001799 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001800 // -- r2 : name
1801 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001802 // -----------------------------------
1803 Label miss;
1804
Steve Blocka7e24c12009-10-30 11:49:00 +00001805 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001806 object,
1807 index,
1808 transition,
Andrei Popescu402d9372010-02-26 13:31:12 +00001809 r1, r2, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001810 &miss);
1811 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001812 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1813 __ Jump(ic, RelocInfo::CODE_TARGET);
1814
1815 // Return the generated code.
1816 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1817}
1818
1819
1820Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1821 AccessorInfo* callback,
1822 String* name) {
1823 // ----------- S t a t e -------------
1824 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001825 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001826 // -- r2 : name
1827 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001828 // -----------------------------------
1829 Label miss;
1830
Steve Blocka7e24c12009-10-30 11:49:00 +00001831 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001832 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001833 __ b(eq, &miss);
1834
1835 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001836 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1837 __ cmp(r3, Operand(Handle<Map>(object->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001838 __ b(ne, &miss);
1839
1840 // Perform global security token check if needed.
1841 if (object->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001842 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001843 }
1844
1845 // Stub never generated for non-global objects that require access
1846 // checks.
1847 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1848
Andrei Popescu402d9372010-02-26 13:31:12 +00001849 __ push(r1); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001850 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
Steve Block6ded16b2010-05-10 14:33:55 +01001851 __ Push(ip, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001852
1853 // Do tail-call to the runtime system.
1854 ExternalReference store_callback_property =
1855 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001856 __ TailCallExternalReference(store_callback_property, 4, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001857
1858 // Handle store cache miss.
1859 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001860 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1861 __ Jump(ic, RelocInfo::CODE_TARGET);
1862
1863 // Return the generated code.
1864 return GetCode(CALLBACKS, name);
1865}
1866
1867
1868Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1869 String* name) {
1870 // ----------- S t a t e -------------
1871 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001872 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001873 // -- r2 : name
1874 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001875 // -----------------------------------
1876 Label miss;
1877
Steve Blocka7e24c12009-10-30 11:49:00 +00001878 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001879 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001880 __ b(eq, &miss);
1881
1882 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001883 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1884 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001885 __ b(ne, &miss);
1886
1887 // Perform global security token check if needed.
1888 if (receiver->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001889 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001890 }
1891
Andrei Popescu402d9372010-02-26 13:31:12 +00001892 // Stub is never generated for non-global objects that require access
Steve Blocka7e24c12009-10-30 11:49:00 +00001893 // checks.
1894 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1895
Steve Block6ded16b2010-05-10 14:33:55 +01001896 __ Push(r1, r2, r0); // Receiver, name, value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001897
1898 // Do tail-call to the runtime system.
1899 ExternalReference store_ic_property =
1900 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001901 __ TailCallExternalReference(store_ic_property, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001902
1903 // Handle store cache miss.
1904 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001905 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1906 __ Jump(ic, RelocInfo::CODE_TARGET);
1907
1908 // Return the generated code.
1909 return GetCode(INTERCEPTOR, name);
1910}
1911
1912
1913Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1914 JSGlobalPropertyCell* cell,
1915 String* name) {
1916 // ----------- S t a t e -------------
1917 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001918 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001919 // -- r2 : name
1920 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001921 // -----------------------------------
1922 Label miss;
1923
1924 // Check that the map of the global has not changed.
Steve Blocka7e24c12009-10-30 11:49:00 +00001925 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1926 __ cmp(r3, Operand(Handle<Map>(object->map())));
1927 __ b(ne, &miss);
1928
1929 // Store the value in the cell.
1930 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1931 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
1932
Andrei Popescu402d9372010-02-26 13:31:12 +00001933 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001934 __ Ret();
1935
1936 // Handle store cache miss.
1937 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001938 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001939 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1940 __ Jump(ic, RelocInfo::CODE_TARGET);
1941
1942 // Return the generated code.
1943 return GetCode(NORMAL, name);
1944}
1945
1946
Steve Block6ded16b2010-05-10 14:33:55 +01001947Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1948 JSObject* object,
1949 JSObject* last) {
1950 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001951 // -- r0 : receiver
Steve Block6ded16b2010-05-10 14:33:55 +01001952 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001953 // -----------------------------------
1954 Label miss;
1955
Steve Block6ded16b2010-05-10 14:33:55 +01001956 // Check that receiver is not a smi.
1957 __ tst(r0, Operand(kSmiTagMask));
1958 __ b(eq, &miss);
1959
1960 // Check the maps of the full prototype chain.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001961 CheckPrototypes(object, r0, last, r3, r1, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001962
1963 // If the last object in the prototype chain is a global object,
1964 // check that the global property cell is empty.
1965 if (last->IsGlobalObject()) {
1966 Object* cell = GenerateCheckPropertyCell(masm(),
1967 GlobalObject::cast(last),
1968 name,
1969 r1,
1970 &miss);
1971 if (cell->IsFailure()) return cell;
1972 }
1973
1974 // Return undefined if maps of the full prototype chain are still the
1975 // same and no global property with this name contains a value.
1976 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1977 __ Ret();
1978
1979 __ bind(&miss);
1980 GenerateLoadMiss(masm(), Code::LOAD_IC);
1981
1982 // Return the generated code.
1983 return GetCode(NONEXISTENT, Heap::empty_string());
1984}
1985
1986
Steve Blocka7e24c12009-10-30 11:49:00 +00001987Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1988 JSObject* holder,
1989 int index,
1990 String* name) {
1991 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001992 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001993 // -- r2 : name
1994 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001995 // -----------------------------------
1996 Label miss;
1997
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001998 GenerateLoadField(object, holder, r0, r3, r1, r4, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001999 __ bind(&miss);
2000 GenerateLoadMiss(masm(), Code::LOAD_IC);
2001
2002 // Return the generated code.
2003 return GetCode(FIELD, name);
2004}
2005
2006
Leon Clarkee46be812010-01-19 14:06:41 +00002007Object* LoadStubCompiler::CompileLoadCallback(String* name,
2008 JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00002009 JSObject* holder,
Leon Clarkee46be812010-01-19 14:06:41 +00002010 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002011 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002012 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002013 // -- r2 : name
2014 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002015 // -----------------------------------
2016 Label miss;
2017
Leon Clarkee46be812010-01-19 14:06:41 +00002018 Failure* failure = Failure::InternalError();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002019 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1, r4,
Leon Clarkee46be812010-01-19 14:06:41 +00002020 callback, name, &miss, &failure);
2021 if (!success) return failure;
2022
Steve Blocka7e24c12009-10-30 11:49:00 +00002023 __ bind(&miss);
2024 GenerateLoadMiss(masm(), Code::LOAD_IC);
2025
2026 // Return the generated code.
2027 return GetCode(CALLBACKS, name);
2028}
2029
2030
2031Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
2032 JSObject* holder,
2033 Object* value,
2034 String* name) {
2035 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002036 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002037 // -- r2 : name
2038 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002039 // -----------------------------------
2040 Label miss;
2041
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002042 GenerateLoadConstant(object, holder, r0, r3, r1, r4, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002043 __ bind(&miss);
2044 GenerateLoadMiss(masm(), Code::LOAD_IC);
2045
2046 // Return the generated code.
2047 return GetCode(CONSTANT_FUNCTION, name);
2048}
2049
2050
2051Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
2052 JSObject* holder,
2053 String* name) {
2054 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002055 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002056 // -- r2 : name
2057 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002058 // -----------------------------------
2059 Label miss;
2060
Steve Blocka7e24c12009-10-30 11:49:00 +00002061 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00002062 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00002063 GenerateLoadInterceptor(object,
2064 holder,
2065 &lookup,
2066 r0,
2067 r2,
2068 r3,
2069 r1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002070 r4,
Steve Blocka7e24c12009-10-30 11:49:00 +00002071 name,
2072 &miss);
2073 __ bind(&miss);
2074 GenerateLoadMiss(masm(), Code::LOAD_IC);
2075
2076 // Return the generated code.
2077 return GetCode(INTERCEPTOR, name);
2078}
2079
2080
2081Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
2082 GlobalObject* holder,
2083 JSGlobalPropertyCell* cell,
2084 String* name,
2085 bool is_dont_delete) {
2086 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002087 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002088 // -- r2 : name
2089 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002090 // -----------------------------------
2091 Label miss;
2092
Steve Blocka7e24c12009-10-30 11:49:00 +00002093 // If the object is the holder then we know that it's a global
2094 // object which can only happen for contextual calls. In this case,
2095 // the receiver cannot be a smi.
2096 if (object != holder) {
Steve Block6ded16b2010-05-10 14:33:55 +01002097 __ tst(r0, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00002098 __ b(eq, &miss);
2099 }
2100
2101 // Check that the map of the global has not changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002102 CheckPrototypes(object, r0, holder, r3, r4, r1, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002103
2104 // Get the value from the cell.
2105 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
Steve Block6ded16b2010-05-10 14:33:55 +01002106 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00002107
2108 // Check for deleted property if property can actually be deleted.
2109 if (!is_dont_delete) {
2110 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
Steve Block6ded16b2010-05-10 14:33:55 +01002111 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00002112 __ b(eq, &miss);
2113 }
2114
Steve Block6ded16b2010-05-10 14:33:55 +01002115 __ mov(r0, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002116 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
2117 __ Ret();
2118
2119 __ bind(&miss);
2120 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
2121 GenerateLoadMiss(masm(), Code::LOAD_IC);
2122
2123 // Return the generated code.
2124 return GetCode(NORMAL, name);
2125}
2126
2127
2128Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
2129 JSObject* receiver,
2130 JSObject* holder,
2131 int index) {
2132 // ----------- S t a t e -------------
2133 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002134 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002135 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002136 // -----------------------------------
2137 Label miss;
2138
Steve Block6ded16b2010-05-10 14:33:55 +01002139 // Check the key is the cached one.
2140 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002141 __ b(ne, &miss);
2142
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002143 GenerateLoadField(receiver, holder, r1, r2, r3, r4, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002144 __ bind(&miss);
2145 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2146
2147 return GetCode(FIELD, name);
2148}
2149
2150
2151Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
2152 JSObject* receiver,
2153 JSObject* holder,
2154 AccessorInfo* callback) {
2155 // ----------- S t a t e -------------
2156 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002157 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002158 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002159 // -----------------------------------
2160 Label miss;
2161
Steve Block6ded16b2010-05-10 14:33:55 +01002162 // Check the key is the cached one.
2163 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002164 __ b(ne, &miss);
2165
Leon Clarkee46be812010-01-19 14:06:41 +00002166 Failure* failure = Failure::InternalError();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002167 bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3, r4,
Leon Clarkee46be812010-01-19 14:06:41 +00002168 callback, name, &miss, &failure);
2169 if (!success) return failure;
2170
Steve Blocka7e24c12009-10-30 11:49:00 +00002171 __ bind(&miss);
2172 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2173
2174 return GetCode(CALLBACKS, name);
2175}
2176
2177
2178Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
2179 JSObject* receiver,
2180 JSObject* holder,
2181 Object* value) {
2182 // ----------- S t a t e -------------
2183 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002184 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002185 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002186 // -----------------------------------
2187 Label miss;
2188
Steve Block6ded16b2010-05-10 14:33:55 +01002189 // Check the key is the cached one.
2190 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002191 __ b(ne, &miss);
2192
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002193 GenerateLoadConstant(receiver, holder, r1, r2, r3, r4, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002194 __ bind(&miss);
2195 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2196
2197 // Return the generated code.
2198 return GetCode(CONSTANT_FUNCTION, name);
2199}
2200
2201
2202Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
2203 JSObject* holder,
2204 String* name) {
2205 // ----------- S t a t e -------------
2206 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002207 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002208 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002209 // -----------------------------------
2210 Label miss;
2211
Steve Block6ded16b2010-05-10 14:33:55 +01002212 // Check the key is the cached one.
2213 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002214 __ b(ne, &miss);
2215
2216 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00002217 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00002218 GenerateLoadInterceptor(receiver,
2219 holder,
2220 &lookup,
Steve Block6ded16b2010-05-10 14:33:55 +01002221 r1,
Steve Blocka7e24c12009-10-30 11:49:00 +00002222 r0,
2223 r2,
2224 r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002225 r4,
Steve Blocka7e24c12009-10-30 11:49:00 +00002226 name,
2227 &miss);
2228 __ bind(&miss);
2229 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2230
2231 return GetCode(INTERCEPTOR, name);
2232}
2233
2234
2235Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
2236 // ----------- S t a t e -------------
2237 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002238 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002239 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002240 // -----------------------------------
2241 Label miss;
2242
Steve Block6ded16b2010-05-10 14:33:55 +01002243 // Check the key is the cached one.
2244 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002245 __ b(ne, &miss);
2246
Steve Block6ded16b2010-05-10 14:33:55 +01002247 GenerateLoadArrayLength(masm(), r1, r2, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002248 __ bind(&miss);
2249 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2250
2251 return GetCode(CALLBACKS, name);
2252}
2253
2254
2255Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
2256 // ----------- S t a t e -------------
2257 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002258 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002259 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002260 // -----------------------------------
2261 Label miss;
2262 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
2263
Steve Block6ded16b2010-05-10 14:33:55 +01002264 // Check the key is the cached one.
2265 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002266 __ b(ne, &miss);
2267
Steve Block6ded16b2010-05-10 14:33:55 +01002268 GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002269 __ bind(&miss);
2270 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
2271
2272 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2273
2274 return GetCode(CALLBACKS, name);
2275}
2276
2277
2278// TODO(1224671): implement the fast case.
2279Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
2280 // ----------- S t a t e -------------
2281 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002282 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002283 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002284 // -----------------------------------
2285 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2286
2287 return GetCode(CALLBACKS, name);
2288}
2289
2290
2291Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
2292 int index,
2293 Map* transition,
2294 String* name) {
2295 // ----------- S t a t e -------------
2296 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01002297 // -- r1 : key
2298 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002299 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002300 // -----------------------------------
2301 Label miss;
2302
Leon Clarkef7060e22010-06-03 12:02:55 +01002303 __ IncrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002304
2305 // Check that the name has not changed.
Leon Clarkef7060e22010-06-03 12:02:55 +01002306 __ cmp(r1, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002307 __ b(ne, &miss);
2308
Leon Clarkef7060e22010-06-03 12:02:55 +01002309 // r3 is used as scratch register. r1 and r2 keep their values if a jump to
2310 // the miss label is generated.
Steve Blocka7e24c12009-10-30 11:49:00 +00002311 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002312 object,
2313 index,
2314 transition,
Leon Clarkef7060e22010-06-03 12:02:55 +01002315 r2, r1, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00002316 &miss);
2317 __ bind(&miss);
2318
Leon Clarkef7060e22010-06-03 12:02:55 +01002319 __ DecrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002320 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
Leon Clarkef7060e22010-06-03 12:02:55 +01002321
Steve Blocka7e24c12009-10-30 11:49:00 +00002322 __ Jump(ic, RelocInfo::CODE_TARGET);
2323
2324 // Return the generated code.
2325 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2326}
2327
2328
2329Object* ConstructStubCompiler::CompileConstructStub(
2330 SharedFunctionInfo* shared) {
2331 // ----------- S t a t e -------------
2332 // -- r0 : argc
2333 // -- r1 : constructor
2334 // -- lr : return address
2335 // -- [sp] : last argument
2336 // -----------------------------------
2337 Label generic_stub_call;
2338
2339 // Use r7 for holding undefined which is used in several places below.
2340 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2341
2342#ifdef ENABLE_DEBUGGER_SUPPORT
2343 // Check to see whether there are any break points in the function code. If
2344 // there are jump to the generic constructor stub which calls the actual
2345 // code for the function thereby hitting the break points.
2346 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2347 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2348 __ cmp(r2, r7);
2349 __ b(ne, &generic_stub_call);
2350#endif
2351
2352 // Load the initial map and verify that it is in fact a map.
2353 // r1: constructor function
2354 // r7: undefined
2355 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2356 __ tst(r2, Operand(kSmiTagMask));
2357 __ b(eq, &generic_stub_call);
2358 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2359 __ b(ne, &generic_stub_call);
2360
2361#ifdef DEBUG
2362 // Cannot construct functions this way.
2363 // r0: argc
2364 // r1: constructor function
2365 // r2: initial map
2366 // r7: undefined
2367 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2368 __ Check(ne, "Function constructed by construct stub.");
2369#endif
2370
2371 // Now allocate the JSObject in new space.
2372 // r0: argc
2373 // r1: constructor function
2374 // r2: initial map
2375 // r7: undefined
2376 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
2377 __ AllocateInNewSpace(r3,
2378 r4,
2379 r5,
2380 r6,
2381 &generic_stub_call,
Kristian Monsen25f61362010-05-21 11:50:48 +01002382 SIZE_IN_WORDS);
Steve Blocka7e24c12009-10-30 11:49:00 +00002383
2384 // Allocated the JSObject, now initialize the fields. Map is set to initial
2385 // map and properties and elements are set to empty fixed array.
2386 // r0: argc
2387 // r1: constructor function
2388 // r2: initial map
2389 // r3: object size (in words)
2390 // r4: JSObject (not tagged)
2391 // r7: undefined
2392 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2393 __ mov(r5, r4);
2394 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2395 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2396 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2397 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2398 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2399 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2400
2401 // Calculate the location of the first argument. The stack contains only the
2402 // argc arguments.
2403 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2404
2405 // Fill all the in-object properties with undefined.
2406 // r0: argc
2407 // r1: first argument
2408 // r3: object size (in words)
2409 // r4: JSObject (not tagged)
2410 // r5: First in-object property of JSObject (not tagged)
2411 // r7: undefined
2412 // Fill the initialized properties with a constant value or a passed argument
2413 // depending on the this.x = ...; assignment in the function.
2414 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2415 if (shared->IsThisPropertyAssignmentArgument(i)) {
2416 Label not_passed, next;
2417 // Check if the argument assigned to the property is actually passed.
2418 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2419 __ cmp(r0, Operand(arg_number));
2420 __ b(le, &not_passed);
2421 // Argument passed - find it on the stack.
2422 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2423 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2424 __ b(&next);
2425 __ bind(&not_passed);
2426 // Set the property to undefined.
2427 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2428 __ bind(&next);
2429 } else {
2430 // Set the property to the constant value.
2431 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2432 __ mov(r2, Operand(constant));
2433 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2434 }
2435 }
2436
2437 // Fill the unused in-object property fields with undefined.
2438 for (int i = shared->this_property_assignments_count();
2439 i < shared->CalculateInObjectProperties();
2440 i++) {
2441 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2442 }
2443
2444 // r0: argc
2445 // r4: JSObject (not tagged)
2446 // Move argc to r1 and the JSObject to return to r0 and tag it.
2447 __ mov(r1, r0);
2448 __ mov(r0, r4);
2449 __ orr(r0, r0, Operand(kHeapObjectTag));
2450
2451 // r0: JSObject
2452 // r1: argc
2453 // Remove caller arguments and receiver from the stack and return.
2454 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2455 __ add(sp, sp, Operand(kPointerSize));
2456 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2457 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2458 __ Jump(lr);
2459
2460 // Jump to the generic stub in case the specialized code cannot handle the
2461 // construction.
2462 __ bind(&generic_stub_call);
2463 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2464 Handle<Code> generic_construct_stub(code);
2465 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2466
2467 // Return the generated code.
2468 return GetCode();
2469}
2470
2471
2472#undef __
2473
2474} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002475
2476#endif // V8_TARGET_ARCH_ARM