blob: 8c8e702d6c33cb8f28edb8557a1443570633d3f1 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
Leon Clarkef7060e22010-06-03 12:02:55 +010030#if defined(V8_TARGET_ARCH_ARM)
31
Steve Blocka7e24c12009-10-30 11:49:00 +000032#include "ic-inl.h"
33#include "codegen-inl.h"
34#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
42static void ProbeTable(MacroAssembler* masm,
43 Code::Flags flags,
44 StubCache::Table table,
45 Register name,
46 Register offset) {
47 ExternalReference key_offset(SCTableReference::keyReference(table));
48 ExternalReference value_offset(SCTableReference::valueReference(table));
49
50 Label miss;
51
52 // Save the offset on the stack.
53 __ push(offset);
54
55 // Check that the key in the entry matches the name.
56 __ mov(ip, Operand(key_offset));
57 __ ldr(ip, MemOperand(ip, offset, LSL, 1));
Steve Block6ded16b2010-05-10 14:33:55 +010058 __ cmp(name, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +000059 __ b(ne, &miss);
60
61 // Get the code entry from the cache.
62 __ mov(ip, Operand(value_offset));
63 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
64
65 // Check that the flags match what we're looking for.
66 __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
67 __ and_(offset, offset, Operand(~Code::kFlagsNotUsedInLookup));
68 __ cmp(offset, Operand(flags));
69 __ b(ne, &miss);
70
71 // Restore offset and re-load code entry from cache.
72 __ pop(offset);
73 __ mov(ip, Operand(value_offset));
74 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
75
76 // Jump to the first instruction in the code stub.
77 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
78 __ Jump(offset);
79
80 // Miss: Restore offset and fall through.
81 __ bind(&miss);
82 __ pop(offset);
83}
84
85
Ben Murdoch3bec4d22010-07-22 14:51:16 +010086// Helper function used to check that the dictionary doesn't contain
87// the property. This function may return false negatives, so miss_label
88// must always call a backup property check that is complete.
89// This function is safe to call if the receiver has fast properties.
90// Name must be a symbol and receiver must be a heap object.
91static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
92 Label* miss_label,
93 Register receiver,
94 String* name,
95 Register scratch0,
96 Register scratch1) {
97 ASSERT(name->IsSymbol());
98 __ IncrementCounter(&Counters::negative_lookups, 1, scratch0, scratch1);
99 __ IncrementCounter(&Counters::negative_lookups_miss, 1, scratch0, scratch1);
100
101 Label done;
102
103 const int kInterceptorOrAccessCheckNeededMask =
104 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
105
106 // Bail out if the receiver has a named interceptor or requires access checks.
107 Register map = scratch1;
108 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
109 __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
110 __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
111 __ b(ne, miss_label);
112
113 // Check that receiver is a JSObject.
114 __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
115 __ cmp(scratch0, Operand(FIRST_JS_OBJECT_TYPE));
116 __ b(lt, miss_label);
117
118 // Load properties array.
119 Register properties = scratch0;
120 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
121 // Check that the properties array is a dictionary.
122 __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
123 Register tmp = properties;
124 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
125 __ cmp(map, tmp);
126 __ b(ne, miss_label);
127
128 // Restore the temporarily used register.
129 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
130
131 // Compute the capacity mask.
132 const int kCapacityOffset =
133 StringDictionary::kHeaderSize +
134 StringDictionary::kCapacityIndex * kPointerSize;
135
136 // Generate an unrolled loop that performs a few probes before
137 // giving up.
138 static const int kProbes = 4;
139 const int kElementsStartOffset =
140 StringDictionary::kHeaderSize +
141 StringDictionary::kElementsStartIndex * kPointerSize;
142
143 // If names of slots in range from 1 to kProbes - 1 for the hash value are
144 // not equal to the name and kProbes-th slot is not used (its name is the
145 // undefined value), it guarantees the hash table doesn't contain the
146 // property. It's true even if some slots represent deleted properties
147 // (their names are the null value).
148 for (int i = 0; i < kProbes; i++) {
149 // scratch0 points to properties hash.
150 // Compute the masked index: (hash + i + i * i) & mask.
151 Register index = scratch1;
152 // Capacity is smi 2^n.
153 __ ldr(index, FieldMemOperand(properties, kCapacityOffset));
154 __ sub(index, index, Operand(1));
155 __ and_(index, index, Operand(
156 Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i))));
157
158 // Scale the index by multiplying by the entry size.
159 ASSERT(StringDictionary::kEntrySize == 3);
160 __ add(index, index, Operand(index, LSL, 1)); // index *= 3.
161
162 Register entity_name = scratch1;
163 // Having undefined at this place means the name is not contained.
164 ASSERT_EQ(kSmiTagSize, 1);
165 Register tmp = properties;
166 __ add(tmp, properties, Operand(index, LSL, 1));
167 __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
168
169 ASSERT(!tmp.is(entity_name));
170 __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
171 __ cmp(entity_name, tmp);
172 if (i != kProbes - 1) {
173 __ b(eq, &done);
174
175 // Stop if found the property.
176 __ cmp(entity_name, Operand(Handle<String>(name)));
177 __ b(eq, miss_label);
178
179 // Check if the entry name is not a symbol.
180 __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
181 __ ldrb(entity_name,
182 FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
183 __ tst(entity_name, Operand(kIsSymbolMask));
184 __ b(eq, miss_label);
185
186 // Restore the properties.
187 __ ldr(properties,
188 FieldMemOperand(receiver, JSObject::kPropertiesOffset));
189 } else {
190 // Give up probing if still not found the undefined value.
191 __ b(ne, miss_label);
192 }
193 }
194 __ bind(&done);
195 __ DecrementCounter(&Counters::negative_lookups_miss, 1, scratch0, scratch1);
196}
197
198
Steve Blocka7e24c12009-10-30 11:49:00 +0000199void StubCache::GenerateProbe(MacroAssembler* masm,
200 Code::Flags flags,
201 Register receiver,
202 Register name,
203 Register scratch,
204 Register extra) {
205 Label miss;
206
207 // Make sure that code is valid. The shifting code relies on the
208 // entry size being 8.
209 ASSERT(sizeof(Entry) == 8);
210
211 // Make sure the flags does not name a specific type.
212 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
213
214 // Make sure that there are no register conflicts.
215 ASSERT(!scratch.is(receiver));
216 ASSERT(!scratch.is(name));
217
218 // Check that the receiver isn't a smi.
219 __ tst(receiver, Operand(kSmiTagMask));
220 __ b(eq, &miss);
221
222 // Get the map of the receiver and compute the hash.
Steve Blockd0582a62009-12-15 09:54:21 +0000223 __ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
225 __ add(scratch, scratch, Operand(ip));
226 __ eor(scratch, scratch, Operand(flags));
227 __ and_(scratch,
228 scratch,
229 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
230
231 // Probe the primary table.
232 ProbeTable(masm, flags, kPrimary, name, scratch);
233
234 // Primary miss: Compute hash for secondary probe.
235 __ sub(scratch, scratch, Operand(name));
236 __ add(scratch, scratch, Operand(flags));
237 __ and_(scratch,
238 scratch,
239 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
240
241 // Probe the secondary table.
242 ProbeTable(masm, flags, kSecondary, name, scratch);
243
244 // Cache miss: Fall-through and let caller handle the miss by
245 // entering the runtime system.
246 __ bind(&miss);
247}
248
249
250void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
251 int index,
252 Register prototype) {
253 // Load the global or builtins object from the current context.
254 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
255 // Load the global context from the global or builtins object.
256 __ ldr(prototype,
257 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
258 // Load the function from the global context.
259 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
260 // Load the initial map. The global functions all have initial maps.
261 __ ldr(prototype,
262 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
263 // Load the prototype from the initial map.
264 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
265}
266
267
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100268void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
269 MacroAssembler* masm, int index, Register prototype) {
270 // Get the global function with the given index.
271 JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
272 // Load its initial map. The global functions all have initial maps.
273 __ Move(prototype, Handle<Map>(function->initial_map()));
274 // Load the prototype from the initial map.
275 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
276}
277
278
Steve Blocka7e24c12009-10-30 11:49:00 +0000279// Load a fast property out of a holder object (src). In-object properties
280// are loaded directly otherwise the property is loaded from the properties
281// fixed array.
282void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
283 Register dst, Register src,
284 JSObject* holder, int index) {
285 // Adjust for the number of properties stored in the holder.
286 index -= holder->map()->inobject_properties();
287 if (index < 0) {
288 // Get the property straight out of the holder.
289 int offset = holder->map()->instance_size() + (index * kPointerSize);
290 __ ldr(dst, FieldMemOperand(src, offset));
291 } else {
292 // Calculate the offset into the properties array.
293 int offset = index * kPointerSize + FixedArray::kHeaderSize;
294 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
295 __ ldr(dst, FieldMemOperand(dst, offset));
296 }
297}
298
299
300void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
301 Register receiver,
302 Register scratch,
303 Label* miss_label) {
304 // Check that the receiver isn't a smi.
305 __ tst(receiver, Operand(kSmiTagMask));
306 __ b(eq, miss_label);
307
308 // Check that the object is a JS array.
309 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
310 __ b(ne, miss_label);
311
312 // Load length directly from the JS array.
313 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
314 __ Ret();
315}
316
317
Andrei Popescu402d9372010-02-26 13:31:12 +0000318// Generate code to check if an object is a string. If the object is a
319// heap object, its map's instance type is left in the scratch1 register.
320// If this is not needed, scratch1 and scratch2 may be the same register.
Steve Blocka7e24c12009-10-30 11:49:00 +0000321static void GenerateStringCheck(MacroAssembler* masm,
322 Register receiver,
323 Register scratch1,
324 Register scratch2,
325 Label* smi,
326 Label* non_string_object) {
327 // Check that the receiver isn't a smi.
328 __ tst(receiver, Operand(kSmiTagMask));
329 __ b(eq, smi);
330
331 // Check that the object is a string.
332 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
333 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
334 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
335 // The cast is to resolve the overload for the argument of 0x0.
336 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
337 __ b(ne, non_string_object);
338}
339
340
341// Generate code to load the length from a string object and return the length.
342// If the receiver object is not a string or a wrapped string object the
343// execution continues at the miss label. The register containing the
344// receiver is potentially clobbered.
Andrei Popescu402d9372010-02-26 13:31:12 +0000345void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
346 Register receiver,
347 Register scratch1,
348 Register scratch2,
349 Label* miss) {
350 Label check_wrapper;
Steve Blocka7e24c12009-10-30 11:49:00 +0000351
Steve Blocka7e24c12009-10-30 11:49:00 +0000352 // Check if the object is a string leaving the instance type in the
353 // scratch1 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000354 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
Steve Blocka7e24c12009-10-30 11:49:00 +0000355
356 // Load length directly from the string.
Steve Blocka7e24c12009-10-30 11:49:00 +0000357 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000358 __ Ret();
359
360 // Check if the object is a JSValue wrapper.
361 __ bind(&check_wrapper);
362 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
363 __ b(ne, miss);
364
Andrei Popescu402d9372010-02-26 13:31:12 +0000365 // Unwrap the value and check if the wrapped value is a string.
366 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
367 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
368 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
Andrei Popescu402d9372010-02-26 13:31:12 +0000369 __ Ret();
Steve Blocka7e24c12009-10-30 11:49:00 +0000370}
371
372
373void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
374 Register receiver,
375 Register scratch1,
376 Register scratch2,
377 Label* miss_label) {
378 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
379 __ mov(r0, scratch1);
380 __ Ret();
381}
382
383
384// Generate StoreField code, value is passed in r0 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000385// When leaving generated code after success, the receiver_reg and name_reg
386// may be clobbered. Upon branch to miss_label, the receiver and name
387// registers have their original values.
Steve Blocka7e24c12009-10-30 11:49:00 +0000388void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Steve Blocka7e24c12009-10-30 11:49:00 +0000389 JSObject* object,
390 int index,
391 Map* transition,
392 Register receiver_reg,
393 Register name_reg,
394 Register scratch,
395 Label* miss_label) {
396 // r0 : value
397 Label exit;
398
399 // Check that the receiver isn't a smi.
400 __ tst(receiver_reg, Operand(kSmiTagMask));
401 __ b(eq, miss_label);
402
403 // Check that the map of the receiver hasn't changed.
404 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
405 __ cmp(scratch, Operand(Handle<Map>(object->map())));
406 __ b(ne, miss_label);
407
408 // Perform global security token check if needed.
409 if (object->IsJSGlobalProxy()) {
410 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
411 }
412
413 // Stub never generated for non-global objects that require access
414 // checks.
415 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
416
417 // Perform map transition for the receiver if necessary.
418 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
419 // The properties must be extended before we can store the value.
420 // We jump to a runtime call that extends the properties array.
Andrei Popescu402d9372010-02-26 13:31:12 +0000421 __ push(receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000422 __ mov(r2, Operand(Handle<Map>(transition)));
Steve Block6ded16b2010-05-10 14:33:55 +0100423 __ Push(r2, r0);
424 __ TailCallExternalReference(
Andrei Popescu402d9372010-02-26 13:31:12 +0000425 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)),
426 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000427 return;
428 }
429
430 if (transition != NULL) {
431 // Update the map of the object; no write barrier updating is
432 // needed because the map is never in new space.
433 __ mov(ip, Operand(Handle<Map>(transition)));
434 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
435 }
436
437 // Adjust for the number of properties stored in the object. Even in the
438 // face of a transition we can use the old map here because the size of the
439 // object and the number of in-object properties is not going to change.
440 index -= object->map()->inobject_properties();
441
442 if (index < 0) {
443 // Set the property straight into the object.
444 int offset = object->map()->instance_size() + (index * kPointerSize);
445 __ str(r0, FieldMemOperand(receiver_reg, offset));
446
447 // Skip updating write barrier if storing a smi.
448 __ tst(r0, Operand(kSmiTagMask));
449 __ b(eq, &exit);
450
451 // Update the write barrier for the array address.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100452 // Pass the now unused name_reg as a scratch register.
453 __ RecordWrite(receiver_reg, Operand(offset), name_reg, scratch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000454 } else {
455 // Write to the properties array.
456 int offset = index * kPointerSize + FixedArray::kHeaderSize;
457 // Get the properties array
458 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
459 __ str(r0, FieldMemOperand(scratch, offset));
460
461 // Skip updating write barrier if storing a smi.
462 __ tst(r0, Operand(kSmiTagMask));
463 __ b(eq, &exit);
464
465 // Update the write barrier for the array address.
466 // Ok to clobber receiver_reg and name_reg, since we return.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100467 __ RecordWrite(scratch, Operand(offset), name_reg, receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000468 }
469
470 // Return the value (register r0).
471 __ bind(&exit);
472 __ Ret();
473}
474
475
476void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
477 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
478 Code* code = NULL;
479 if (kind == Code::LOAD_IC) {
480 code = Builtins::builtin(Builtins::LoadIC_Miss);
481 } else {
482 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
483 }
484
485 Handle<Code> ic(code);
486 __ Jump(ic, RelocInfo::CODE_TARGET);
487}
488
489
Leon Clarke4515c472010-02-03 11:58:03 +0000490static void GenerateCallFunction(MacroAssembler* masm,
491 Object* object,
492 const ParameterCount& arguments,
493 Label* miss) {
494 // ----------- S t a t e -------------
495 // -- r0: receiver
496 // -- r1: function to call
497 // -----------------------------------
498
499 // Check that the function really is a function.
500 __ BranchOnSmi(r1, miss);
Andrei Popescu402d9372010-02-26 13:31:12 +0000501 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
Leon Clarke4515c472010-02-03 11:58:03 +0000502 __ b(ne, miss);
503
504 // Patch the receiver on the stack with the global proxy if
505 // necessary.
506 if (object->IsGlobalObject()) {
507 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
508 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
509 }
510
511 // Invoke the function.
512 __ InvokeFunction(r1, arguments, JUMP_FUNCTION);
513}
514
515
Leon Clarke4515c472010-02-03 11:58:03 +0000516static void PushInterceptorArguments(MacroAssembler* masm,
517 Register receiver,
518 Register holder,
519 Register name,
520 JSObject* holder_obj) {
Leon Clarke4515c472010-02-03 11:58:03 +0000521 __ push(name);
522 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
523 ASSERT(!Heap::InNewSpace(interceptor));
Steve Block6ded16b2010-05-10 14:33:55 +0100524 Register scratch = name;
Leon Clarke4515c472010-02-03 11:58:03 +0000525 __ mov(scratch, Operand(Handle<Object>(interceptor)));
526 __ push(scratch);
Steve Block6ded16b2010-05-10 14:33:55 +0100527 __ push(receiver);
528 __ push(holder);
Leon Clarke4515c472010-02-03 11:58:03 +0000529 __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
530 __ push(scratch);
531}
532
533
534static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
535 Register receiver,
536 Register holder,
537 Register name,
538 JSObject* holder_obj) {
539 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
540
541 ExternalReference ref =
542 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
543 __ mov(r0, Operand(5));
544 __ mov(r1, Operand(ref));
545
546 CEntryStub stub(1);
547 __ CallStub(&stub);
548}
549
550
Steve Block6ded16b2010-05-10 14:33:55 +0100551// Reserves space for the extra arguments to FastHandleApiCall in the
552// caller's frame.
553//
554// These arguments are set by CheckPrototypes and GenerateFastApiCall.
555static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
556 Register scratch) {
557 __ mov(scratch, Operand(Smi::FromInt(0)));
558 __ push(scratch);
559 __ push(scratch);
560 __ push(scratch);
561 __ push(scratch);
562}
563
564
565// Undoes the effects of ReserveSpaceForFastApiCall.
566static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
567 __ Drop(4);
568}
569
570
571// Generates call to FastHandleApiCall builtin.
572static void GenerateFastApiCall(MacroAssembler* masm,
573 const CallOptimization& optimization,
574 int argc) {
575 // Get the function and setup the context.
576 JSFunction* function = optimization.constant_function();
577 __ mov(r7, Operand(Handle<JSFunction>(function)));
578 __ ldr(cp, FieldMemOperand(r7, JSFunction::kContextOffset));
579
580 // Pass the additional arguments FastHandleApiCall expects.
581 bool info_loaded = false;
582 Object* callback = optimization.api_call_info()->callback();
583 if (Heap::InNewSpace(callback)) {
584 info_loaded = true;
585 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
586 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
587 } else {
588 __ Move(r6, Handle<Object>(callback));
589 }
590 Object* call_data = optimization.api_call_info()->data();
591 if (Heap::InNewSpace(call_data)) {
592 if (!info_loaded) {
593 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
594 }
595 __ ldr(r5, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
596 } else {
597 __ Move(r5, Handle<Object>(call_data));
598 }
599
600 __ add(sp, sp, Operand(1 * kPointerSize));
601 __ stm(ia, sp, r5.bit() | r6.bit() | r7.bit());
602 __ sub(sp, sp, Operand(1 * kPointerSize));
603
604 // Set the number of arguments.
605 __ mov(r0, Operand(argc + 4));
606
607 // Jump to the fast api call builtin (tail call).
608 Handle<Code> code = Handle<Code>(
609 Builtins::builtin(Builtins::FastHandleApiCall));
610 ParameterCount expected(0);
611 __ InvokeCode(code, expected, expected,
612 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
613}
614
615
616class CallInterceptorCompiler BASE_EMBEDDED {
617 public:
618 CallInterceptorCompiler(StubCompiler* stub_compiler,
619 const ParameterCount& arguments,
620 Register name)
621 : stub_compiler_(stub_compiler),
622 arguments_(arguments),
623 name_(name) {}
624
625 void Compile(MacroAssembler* masm,
626 JSObject* object,
627 JSObject* holder,
628 String* name,
629 LookupResult* lookup,
630 Register receiver,
631 Register scratch1,
632 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100633 Register scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100634 Label* miss) {
635 ASSERT(holder->HasNamedInterceptor());
636 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
637
638 // Check that the receiver isn't a smi.
639 __ BranchOnSmi(receiver, miss);
640
641 CallOptimization optimization(lookup);
642
643 if (optimization.is_constant_call()) {
644 CompileCacheable(masm,
645 object,
646 receiver,
647 scratch1,
648 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100649 scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100650 holder,
651 lookup,
652 name,
653 optimization,
654 miss);
655 } else {
656 CompileRegular(masm,
657 object,
658 receiver,
659 scratch1,
660 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100661 scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100662 name,
663 holder,
664 miss);
665 }
666 }
667
668 private:
669 void CompileCacheable(MacroAssembler* masm,
670 JSObject* object,
671 Register receiver,
672 Register scratch1,
673 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100674 Register scratch3,
Leon Clarkef7060e22010-06-03 12:02:55 +0100675 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100676 LookupResult* lookup,
677 String* name,
678 const CallOptimization& optimization,
679 Label* miss_label) {
680 ASSERT(optimization.is_constant_call());
681 ASSERT(!lookup->holder()->IsGlobalObject());
682
683 int depth1 = kInvalidProtoDepth;
684 int depth2 = kInvalidProtoDepth;
685 bool can_do_fast_api_call = false;
686 if (optimization.is_simple_api_call() &&
687 !lookup->holder()->IsGlobalObject()) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100688 depth1 =
689 optimization.GetPrototypeDepthOfExpectedType(object,
690 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100691 if (depth1 == kInvalidProtoDepth) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100692 depth2 =
693 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
694 lookup->holder());
Steve Block6ded16b2010-05-10 14:33:55 +0100695 }
696 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
697 (depth2 != kInvalidProtoDepth);
698 }
699
700 __ IncrementCounter(&Counters::call_const_interceptor, 1,
701 scratch1, scratch2);
702
703 if (can_do_fast_api_call) {
704 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1,
705 scratch1, scratch2);
706 ReserveSpaceForFastApiCall(masm, scratch1);
707 }
708
Leon Clarkef7060e22010-06-03 12:02:55 +0100709 // Check that the maps from receiver to interceptor's holder
710 // haven't changed and thus we can invoke interceptor.
Steve Block6ded16b2010-05-10 14:33:55 +0100711 Label miss_cleanup;
712 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
713 Register holder =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100714 stub_compiler_->CheckPrototypes(object, receiver,
715 interceptor_holder, scratch1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100716 scratch2, scratch3, name, depth1, miss);
Steve Block6ded16b2010-05-10 14:33:55 +0100717
Leon Clarkef7060e22010-06-03 12:02:55 +0100718 // Invoke an interceptor and if it provides a value,
719 // branch to |regular_invoke|.
Steve Block6ded16b2010-05-10 14:33:55 +0100720 Label regular_invoke;
Leon Clarkef7060e22010-06-03 12:02:55 +0100721 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
Steve Block6ded16b2010-05-10 14:33:55 +0100722 &regular_invoke);
723
Leon Clarkef7060e22010-06-03 12:02:55 +0100724 // Interceptor returned nothing for this property. Try to use cached
725 // constant function.
Steve Block6ded16b2010-05-10 14:33:55 +0100726
Leon Clarkef7060e22010-06-03 12:02:55 +0100727 // Check that the maps from interceptor's holder to constant function's
728 // holder haven't changed and thus we can use cached constant function.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100729 if (interceptor_holder != lookup->holder()) {
730 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
731 lookup->holder(), scratch1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100732 scratch2, scratch3, name, depth2, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100733 } else {
734 // CheckPrototypes has a side effect of fetching a 'holder'
735 // for API (object which is instanceof for the signature). It's
736 // safe to omit it here, as if present, it should be fetched
737 // by the previous CheckPrototypes.
738 ASSERT(depth2 == kInvalidProtoDepth);
739 }
Steve Block6ded16b2010-05-10 14:33:55 +0100740
Leon Clarkef7060e22010-06-03 12:02:55 +0100741 // Invoke function.
Steve Block6ded16b2010-05-10 14:33:55 +0100742 if (can_do_fast_api_call) {
743 GenerateFastApiCall(masm, optimization, arguments_.immediate());
744 } else {
745 __ InvokeFunction(optimization.constant_function(), arguments_,
746 JUMP_FUNCTION);
747 }
748
Leon Clarkef7060e22010-06-03 12:02:55 +0100749 // Deferred code for fast API call case---clean preallocated space.
Steve Block6ded16b2010-05-10 14:33:55 +0100750 if (can_do_fast_api_call) {
751 __ bind(&miss_cleanup);
752 FreeSpaceForFastApiCall(masm);
753 __ b(miss_label);
754 }
755
Leon Clarkef7060e22010-06-03 12:02:55 +0100756 // Invoke a regular function.
Steve Block6ded16b2010-05-10 14:33:55 +0100757 __ bind(&regular_invoke);
758 if (can_do_fast_api_call) {
759 FreeSpaceForFastApiCall(masm);
760 }
761 }
762
763 void CompileRegular(MacroAssembler* masm,
764 JSObject* object,
765 Register receiver,
766 Register scratch1,
767 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100768 Register scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100769 String* name,
Leon Clarkef7060e22010-06-03 12:02:55 +0100770 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100771 Label* miss_label) {
772 Register holder =
Leon Clarkef7060e22010-06-03 12:02:55 +0100773 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100774 scratch1, scratch2, scratch3, name,
Steve Block6ded16b2010-05-10 14:33:55 +0100775 miss_label);
776
777 // Call a runtime function to load the interceptor property.
778 __ EnterInternalFrame();
779 // Save the name_ register across the call.
780 __ push(name_);
781
782 PushInterceptorArguments(masm,
783 receiver,
784 holder,
785 name_,
Leon Clarkef7060e22010-06-03 12:02:55 +0100786 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100787
788 __ CallExternalReference(
789 ExternalReference(
790 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
791 5);
792
793 // Restore the name_ register.
794 __ pop(name_);
795 __ LeaveInternalFrame();
796 }
797
798 void LoadWithInterceptor(MacroAssembler* masm,
799 Register receiver,
800 Register holder,
801 JSObject* holder_obj,
802 Register scratch,
803 Label* interceptor_succeeded) {
804 __ EnterInternalFrame();
805 __ Push(holder, name_);
806
807 CompileCallLoadPropertyWithInterceptor(masm,
808 receiver,
809 holder,
810 name_,
811 holder_obj);
812
813 __ pop(name_); // Restore the name.
814 __ pop(receiver); // Restore the holder.
815 __ LeaveInternalFrame();
816
817 // If interceptor returns no-result sentinel, call the constant function.
818 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
819 __ cmp(r0, scratch);
820 __ b(ne, interceptor_succeeded);
821 }
822
823 StubCompiler* stub_compiler_;
824 const ParameterCount& arguments_;
825 Register name_;
826};
827
828
829// Generate code to check that a global property cell is empty. Create
830// the property cell at compilation time if no cell exists for the
831// property.
832static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
833 GlobalObject* global,
834 String* name,
835 Register scratch,
836 Label* miss) {
837 Object* probe = global->EnsurePropertyCell(name);
838 if (probe->IsFailure()) return probe;
839 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
840 ASSERT(cell->value()->IsTheHole());
841 __ mov(scratch, Operand(Handle<Object>(cell)));
842 __ ldr(scratch,
843 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
844 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
845 __ cmp(scratch, ip);
846 __ b(ne, miss);
847 return cell;
848}
849
850
Steve Blocka7e24c12009-10-30 11:49:00 +0000851#undef __
852#define __ ACCESS_MASM(masm())
853
854
855Register StubCompiler::CheckPrototypes(JSObject* object,
856 Register object_reg,
857 JSObject* holder,
858 Register holder_reg,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100859 Register scratch1,
860 Register scratch2,
Steve Blocka7e24c12009-10-30 11:49:00 +0000861 String* name,
Andrei Popescu402d9372010-02-26 13:31:12 +0000862 int save_at_depth,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100863 Label* miss) {
864 // Make sure there's no overlap between holder and object registers.
865 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
866 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
867 && !scratch2.is(scratch1));
868
869 // Keep track of the current object in register reg.
870 Register reg = object_reg;
871 int depth = 0;
872
873 if (save_at_depth == depth) {
874 __ str(reg, MemOperand(sp));
875 }
876
877 // Check the maps in the prototype chain.
878 // Traverse the prototype chain from the object and do map checks.
879 JSObject* current = object;
880 while (current != holder) {
881 depth++;
882
883 // Only global objects and objects that do not require access
884 // checks are allowed in stubs.
885 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
886
887 JSObject* prototype = JSObject::cast(current->GetPrototype());
888 if (!current->HasFastProperties() &&
889 !current->IsJSGlobalObject() &&
890 !current->IsJSGlobalProxy()) {
891 if (!name->IsSymbol()) {
892 Object* lookup_result = Heap::LookupSymbol(name);
893 if (lookup_result->IsFailure()) {
894 set_failure(Failure::cast(lookup_result));
895 return reg;
896 } else {
897 name = String::cast(lookup_result);
898 }
899 }
900 ASSERT(current->property_dictionary()->FindEntry(name) ==
901 StringDictionary::kNotFound);
902
903 GenerateDictionaryNegativeLookup(masm(),
904 miss,
905 reg,
906 name,
907 scratch1,
908 scratch2);
909 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
910 reg = holder_reg; // from now the object is in holder_reg
911 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
912 } else {
913 // Get the map of the current object.
914 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
915 __ cmp(scratch1, Operand(Handle<Map>(current->map())));
916
917 // Branch on the result of the map check.
918 __ b(ne, miss);
919
920 // Check access rights to the global object. This has to happen
921 // after the map check so that we know that the object is
922 // actually a global object.
923 if (current->IsJSGlobalProxy()) {
924 __ CheckAccessGlobalProxy(reg, scratch1, miss);
925 // Restore scratch register to be the map of the object. In the
926 // new space case below, we load the prototype from the map in
927 // the scratch register.
928 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
929 }
930
931 reg = holder_reg; // from now the object is in holder_reg
932 if (Heap::InNewSpace(prototype)) {
933 // The prototype is in new space; we cannot store a reference
934 // to it in the code. Load it from the map.
935 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
936 } else {
937 // The prototype is in old space; load it directly.
938 __ mov(reg, Operand(Handle<JSObject>(prototype)));
939 }
940 }
941
942 if (save_at_depth == depth) {
943 __ str(reg, MemOperand(sp));
944 }
945
946 // Go to the next object in the prototype chain.
947 current = prototype;
948 }
949
950 // Check the holder map.
951 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
952 __ cmp(scratch1, Operand(Handle<Map>(current->map())));
953 __ b(ne, miss);
954
955 // Log the check depth.
956 LOG(IntEvent("check-maps-depth", depth + 1));
957
958 // Perform security check for access to the global object and return
959 // the holder register.
960 ASSERT(current == holder);
961 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
962 if (current->IsJSGlobalProxy()) {
963 __ CheckAccessGlobalProxy(reg, scratch1, miss);
964 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000965
966 // If we've skipped any global objects, it's not enough to verify
Steve Block6ded16b2010-05-10 14:33:55 +0100967 // that their maps haven't changed. We also need to check that the
968 // property cell for the property is still empty.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100969 current = object;
970 while (current != holder) {
971 if (current->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100972 Object* cell = GenerateCheckPropertyCell(masm(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100973 GlobalObject::cast(current),
Steve Block6ded16b2010-05-10 14:33:55 +0100974 name,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100975 scratch1,
Steve Block6ded16b2010-05-10 14:33:55 +0100976 miss);
977 if (cell->IsFailure()) {
978 set_failure(Failure::cast(cell));
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100979 return reg;
Steve Blocka7e24c12009-10-30 11:49:00 +0000980 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000981 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100982 current = JSObject::cast(current->GetPrototype());
Steve Blocka7e24c12009-10-30 11:49:00 +0000983 }
984
Andrei Popescu402d9372010-02-26 13:31:12 +0000985 // Return the register containing the holder.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100986 return reg;
Steve Blocka7e24c12009-10-30 11:49:00 +0000987}
988
989
990void StubCompiler::GenerateLoadField(JSObject* object,
991 JSObject* holder,
992 Register receiver,
993 Register scratch1,
994 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100995 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +0000996 int index,
997 String* name,
998 Label* miss) {
999 // Check that the receiver isn't a smi.
1000 __ tst(receiver, Operand(kSmiTagMask));
1001 __ b(eq, miss);
1002
1003 // Check that the maps haven't changed.
1004 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001005 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1006 name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001007 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
1008 __ Ret();
1009}
1010
1011
1012void StubCompiler::GenerateLoadConstant(JSObject* object,
1013 JSObject* holder,
1014 Register receiver,
1015 Register scratch1,
1016 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001017 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001018 Object* value,
1019 String* name,
1020 Label* miss) {
1021 // Check that the receiver isn't a smi.
1022 __ tst(receiver, Operand(kSmiTagMask));
1023 __ b(eq, miss);
1024
1025 // Check that the maps haven't changed.
1026 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001027 CheckPrototypes(object, receiver, holder,
1028 scratch1, scratch2, scratch3, name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001029
1030 // Return the constant value.
1031 __ mov(r0, Operand(Handle<Object>(value)));
1032 __ Ret();
1033}
1034
1035
Leon Clarkee46be812010-01-19 14:06:41 +00001036bool StubCompiler::GenerateLoadCallback(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001037 JSObject* holder,
1038 Register receiver,
1039 Register name_reg,
1040 Register scratch1,
1041 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001042 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001043 AccessorInfo* callback,
1044 String* name,
Leon Clarkee46be812010-01-19 14:06:41 +00001045 Label* miss,
1046 Failure** failure) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001047 // Check that the receiver isn't a smi.
1048 __ tst(receiver, Operand(kSmiTagMask));
1049 __ b(eq, miss);
1050
1051 // Check that the maps haven't changed.
1052 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001053 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1054 name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001055
1056 // Push the arguments on the JS stack of the caller.
Steve Block6ded16b2010-05-10 14:33:55 +01001057 __ push(receiver); // Receiver.
1058 __ push(reg); // Holder.
Steve Blocka7e24c12009-10-30 11:49:00 +00001059 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
Steve Blocka7e24c12009-10-30 11:49:00 +00001060 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
Steve Block6ded16b2010-05-10 14:33:55 +01001061 __ Push(ip, reg, name_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +00001062
1063 // Do tail-call to the runtime system.
1064 ExternalReference load_callback_property =
1065 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001066 __ TailCallExternalReference(load_callback_property, 5, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00001067
1068 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001069}
1070
1071
1072void StubCompiler::GenerateLoadInterceptor(JSObject* object,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001073 JSObject* interceptor_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +00001074 LookupResult* lookup,
1075 Register receiver,
1076 Register name_reg,
1077 Register scratch1,
1078 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001079 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 String* name,
1081 Label* miss) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001082 ASSERT(interceptor_holder->HasNamedInterceptor());
1083 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1084
1085 // Check that the receiver isn't a smi.
1086 __ BranchOnSmi(receiver, miss);
1087
1088 // So far the most popular follow ups for interceptor loads are FIELD
1089 // and CALLBACKS, so inline only them, other cases may be added
1090 // later.
1091 bool compile_followup_inline = false;
1092 if (lookup->IsProperty() && lookup->IsCacheable()) {
1093 if (lookup->type() == FIELD) {
1094 compile_followup_inline = true;
1095 } else if (lookup->type() == CALLBACKS &&
1096 lookup->GetCallbackObject()->IsAccessorInfo() &&
1097 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
1098 compile_followup_inline = true;
1099 }
1100 }
1101
1102 if (compile_followup_inline) {
1103 // Compile the interceptor call, followed by inline code to load the
1104 // property from further up the prototype chain if the call fails.
1105 // Check that the maps haven't changed.
1106 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001107 scratch1, scratch2, scratch3,
1108 name, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001109 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1110
1111 // Save necessary data before invoking an interceptor.
1112 // Requires a frame to make GC aware of pushed pointers.
1113 __ EnterInternalFrame();
1114
1115 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1116 // CALLBACKS case needs a receiver to be passed into C++ callback.
1117 __ Push(receiver, holder_reg, name_reg);
1118 } else {
1119 __ Push(holder_reg, name_reg);
1120 }
1121
1122 // Invoke an interceptor. Note: map checks from receiver to
1123 // interceptor's holder has been compiled before (see a caller
1124 // of this method.)
1125 CompileCallLoadPropertyWithInterceptor(masm(),
1126 receiver,
1127 holder_reg,
1128 name_reg,
1129 interceptor_holder);
1130
1131 // Check if interceptor provided a value for property. If it's
1132 // the case, return immediately.
1133 Label interceptor_failed;
1134 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1135 __ cmp(r0, scratch1);
1136 __ b(eq, &interceptor_failed);
1137 __ LeaveInternalFrame();
1138 __ Ret();
1139
1140 __ bind(&interceptor_failed);
1141 __ pop(name_reg);
1142 __ pop(holder_reg);
1143 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1144 __ pop(receiver);
1145 }
1146
1147 __ LeaveInternalFrame();
1148
1149 // Check that the maps from interceptor's holder to lookup's holder
1150 // haven't changed. And load lookup's holder into |holder| register.
1151 if (interceptor_holder != lookup->holder()) {
1152 holder_reg = CheckPrototypes(interceptor_holder,
1153 holder_reg,
1154 lookup->holder(),
1155 scratch1,
1156 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001157 scratch3,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001158 name,
1159 miss);
1160 }
1161
1162 if (lookup->type() == FIELD) {
1163 // We found FIELD property in prototype chain of interceptor's holder.
1164 // Retrieve a field from field's holder.
1165 GenerateFastPropertyLoad(masm(), r0, holder_reg,
1166 lookup->holder(), lookup->GetFieldIndex());
1167 __ Ret();
1168 } else {
1169 // We found CALLBACKS property in prototype chain of interceptor's
1170 // holder.
1171 ASSERT(lookup->type() == CALLBACKS);
1172 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
1173 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1174 ASSERT(callback != NULL);
1175 ASSERT(callback->getter() != NULL);
1176
1177 // Tail call to runtime.
1178 // Important invariant in CALLBACKS case: the code above must be
1179 // structured to never clobber |receiver| register.
1180 __ Move(scratch2, Handle<AccessorInfo>(callback));
1181 // holder_reg is either receiver or scratch1.
1182 if (!receiver.is(holder_reg)) {
1183 ASSERT(scratch1.is(holder_reg));
1184 __ Push(receiver, holder_reg, scratch2);
1185 __ ldr(scratch1,
1186 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
1187 __ Push(scratch1, name_reg);
1188 } else {
1189 __ push(receiver);
1190 __ ldr(scratch1,
1191 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
1192 __ Push(holder_reg, scratch2, scratch1, name_reg);
1193 }
1194
1195 ExternalReference ref =
1196 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
1197 __ TailCallExternalReference(ref, 5, 1);
1198 }
1199 } else { // !compile_followup_inline
1200 // Call the runtime system to load the interceptor.
1201 // Check that the maps haven't changed.
1202 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001203 scratch1, scratch2, scratch3,
1204 name, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001205 PushInterceptorArguments(masm(), receiver, holder_reg,
1206 name_reg, interceptor_holder);
1207
1208 ExternalReference ref = ExternalReference(
1209 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
1210 __ TailCallExternalReference(ref, 5, 1);
1211 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001212}
1213
1214
1215Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
1216 // ----------- S t a t e -------------
1217 // -- r1: function
1218 // -- lr: return address
1219 // -----------------------------------
1220
1221 // Enter an internal frame.
1222 __ EnterInternalFrame();
1223
1224 // Preserve the function.
1225 __ push(r1);
1226
1227 // Push the function on the stack as the argument to the runtime function.
1228 __ push(r1);
1229 __ CallRuntime(Runtime::kLazyCompile, 1);
1230
1231 // Calculate the entry point.
1232 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
1233
1234 // Restore saved function.
1235 __ pop(r1);
1236
1237 // Tear down temporary frame.
1238 __ LeaveInternalFrame();
1239
1240 // Do a tail-call of the compiled function.
1241 __ Jump(r2);
1242
1243 return GetCodeWithFlags(flags, "LazyCompileStub");
1244}
1245
1246
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001247void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
1248 if (kind_ == Code::KEYED_CALL_IC) {
1249 __ cmp(r2, Operand(Handle<String>(name)));
1250 __ b(ne, miss);
1251 }
1252}
1253
1254
Ben Murdochbb769b22010-08-11 14:56:33 +01001255Object* CallStubCompiler::GenerateMissBranch() {
1256 Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
1257 if (obj->IsFailure()) return obj;
1258 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1259 return obj;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001260}
1261
1262
Andrei Popescu402d9372010-02-26 13:31:12 +00001263Object* CallStubCompiler::CompileCallField(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001264 JSObject* holder,
1265 int index,
1266 String* name) {
1267 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001268 // -- r2 : name
1269 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001270 // -----------------------------------
1271 Label miss;
1272
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001273 GenerateNameCheck(name, &miss);
1274
Steve Blocka7e24c12009-10-30 11:49:00 +00001275 const int argc = arguments().immediate();
1276
1277 // Get the receiver of the function from the stack into r0.
1278 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1279 // Check that the receiver isn't a smi.
1280 __ tst(r0, Operand(kSmiTagMask));
1281 __ b(eq, &miss);
1282
1283 // Do the right check and compute the holder register.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001284 Register reg = CheckPrototypes(object, r0, holder, r1, r3, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001285 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
1286
Leon Clarke4515c472010-02-03 11:58:03 +00001287 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001288
1289 // Handle call cache miss.
1290 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001291 Object* obj = GenerateMissBranch();
1292 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001293
1294 // Return the generated code.
1295 return GetCode(FIELD, name);
1296}
1297
1298
Steve Block6ded16b2010-05-10 14:33:55 +01001299Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1300 JSObject* holder,
1301 JSFunction* function,
1302 String* name,
1303 CheckType check) {
1304 // ----------- S t a t e -------------
1305 // -- r2 : name
1306 // -- lr : return address
1307 // -----------------------------------
1308
1309 // If object is not an array, bail out to regular call.
1310 if (!object->IsJSArray()) {
1311 return Heap::undefined_value();
1312 }
1313
1314 // TODO(639): faster implementation.
1315 ASSERT(check == RECEIVER_MAP_CHECK);
1316
1317 Label miss;
1318
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001319 GenerateNameCheck(name, &miss);
1320
Steve Block6ded16b2010-05-10 14:33:55 +01001321 // Get the receiver from the stack
1322 const int argc = arguments().immediate();
1323 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1324
1325 // Check that the receiver isn't a smi.
1326 __ tst(r1, Operand(kSmiTagMask));
1327 __ b(eq, &miss);
1328
1329 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001330 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001331
1332 if (object->IsGlobalObject()) {
1333 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1334 __ str(r3, MemOperand(sp, argc * kPointerSize));
1335 }
1336
1337 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1338 argc + 1,
1339 1);
1340
1341 // Handle call cache miss.
1342 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001343 Object* obj = GenerateMissBranch();
1344 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +01001345
1346 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001347 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001348}
1349
1350
1351Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1352 JSObject* holder,
1353 JSFunction* function,
1354 String* name,
1355 CheckType check) {
1356 // ----------- S t a t e -------------
1357 // -- r2 : name
1358 // -- lr : return address
1359 // -----------------------------------
1360
1361 // If object is not an array, bail out to regular call.
1362 if (!object->IsJSArray()) {
1363 return Heap::undefined_value();
1364 }
1365
1366 // TODO(642): faster implementation.
1367 ASSERT(check == RECEIVER_MAP_CHECK);
1368
1369 Label miss;
1370
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001371 GenerateNameCheck(name, &miss);
1372
Steve Block6ded16b2010-05-10 14:33:55 +01001373 // Get the receiver from the stack
1374 const int argc = arguments().immediate();
1375 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1376
1377 // Check that the receiver isn't a smi.
1378 __ tst(r1, Operand(kSmiTagMask));
1379 __ b(eq, &miss);
1380
1381 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001382 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001383
1384 if (object->IsGlobalObject()) {
1385 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1386 __ str(r3, MemOperand(sp, argc * kPointerSize));
1387 }
1388
1389 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1390 argc + 1,
1391 1);
1392
1393 // Handle call cache miss.
1394 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001395 Object* obj = GenerateMissBranch();
1396 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +01001397
1398 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001399 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001400}
1401
1402
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001403Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
1404 JSObject* holder,
1405 JSFunction* function,
1406 String* name,
1407 CheckType check) {
1408 // TODO(722): implement this.
1409 return Heap::undefined_value();
1410}
1411
1412
1413Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
1414 JSObject* holder,
1415 JSFunction* function,
1416 String* name,
1417 CheckType check) {
1418 // TODO(722): implement this.
1419 return Heap::undefined_value();
1420}
1421
1422
Steve Blocka7e24c12009-10-30 11:49:00 +00001423Object* CallStubCompiler::CompileCallConstant(Object* object,
1424 JSObject* holder,
1425 JSFunction* function,
1426 String* name,
1427 CheckType check) {
1428 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001429 // -- r2 : name
1430 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001431 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001432 SharedFunctionInfo* function_info = function->shared();
1433 if (function_info->HasCustomCallGenerator()) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001434 const int id = function_info->custom_call_generator_id();
1435 Object* result =
1436 CompileCustomCall(id, object, holder, function, name, check);
Steve Block6ded16b2010-05-10 14:33:55 +01001437 // undefined means bail out to regular compiler.
1438 if (!result->IsUndefined()) {
1439 return result;
1440 }
1441 }
1442
1443 Label miss_in_smi_check;
Steve Blocka7e24c12009-10-30 11:49:00 +00001444
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001445 GenerateNameCheck(name, &miss_in_smi_check);
1446
Steve Blocka7e24c12009-10-30 11:49:00 +00001447 // Get the receiver from the stack
1448 const int argc = arguments().immediate();
1449 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1450
1451 // Check that the receiver isn't a smi.
1452 if (check != NUMBER_CHECK) {
1453 __ tst(r1, Operand(kSmiTagMask));
Steve Block6ded16b2010-05-10 14:33:55 +01001454 __ b(eq, &miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001455 }
1456
1457 // Make sure that it's okay not to patch the on stack receiver
1458 // unless we're doing a receiver map check.
1459 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1460
Steve Block6ded16b2010-05-10 14:33:55 +01001461 CallOptimization optimization(function);
1462 int depth = kInvalidProtoDepth;
1463 Label miss;
1464
Steve Blocka7e24c12009-10-30 11:49:00 +00001465 switch (check) {
1466 case RECEIVER_MAP_CHECK:
Steve Block6ded16b2010-05-10 14:33:55 +01001467 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1468
1469 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1470 depth = optimization.GetPrototypeDepthOfExpectedType(
1471 JSObject::cast(object), holder);
1472 }
1473
1474 if (depth != kInvalidProtoDepth) {
1475 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1476 ReserveSpaceForFastApiCall(masm(), r0);
1477 }
1478
Steve Blocka7e24c12009-10-30 11:49:00 +00001479 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001480 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
Steve Block6ded16b2010-05-10 14:33:55 +01001481 depth, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001482
1483 // Patch the receiver on the stack with the global proxy if
1484 // necessary.
1485 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001486 ASSERT(depth == kInvalidProtoDepth);
Steve Blocka7e24c12009-10-30 11:49:00 +00001487 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1488 __ str(r3, MemOperand(sp, argc * kPointerSize));
1489 }
1490 break;
1491
1492 case STRING_CHECK:
Leon Clarkee46be812010-01-19 14:06:41 +00001493 if (!function->IsBuiltin()) {
1494 // Calling non-builtins with a value as receiver requires boxing.
1495 __ jmp(&miss);
1496 } else {
1497 // Check that the object is a two-byte string or a symbol.
Andrei Popescu402d9372010-02-26 13:31:12 +00001498 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001499 __ b(hs, &miss);
1500 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001501 GenerateDirectLoadGlobalFunctionPrototype(
1502 masm(), Context::STRING_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001503 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001504 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001505 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001506 break;
1507
1508 case NUMBER_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001509 if (!function->IsBuiltin()) {
1510 // Calling non-builtins with a value as receiver requires boxing.
1511 __ jmp(&miss);
1512 } else {
1513 Label fast;
1514 // Check that the object is a smi or a heap number.
1515 __ tst(r1, Operand(kSmiTagMask));
1516 __ b(eq, &fast);
Andrei Popescu402d9372010-02-26 13:31:12 +00001517 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001518 __ b(ne, &miss);
1519 __ bind(&fast);
1520 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001521 GenerateDirectLoadGlobalFunctionPrototype(
1522 masm(), Context::NUMBER_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001523 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001524 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001525 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001526 break;
1527 }
1528
1529 case BOOLEAN_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001530 if (!function->IsBuiltin()) {
1531 // Calling non-builtins with a value as receiver requires boxing.
1532 __ jmp(&miss);
1533 } else {
1534 Label fast;
1535 // Check that the object is a boolean.
1536 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1537 __ cmp(r1, ip);
1538 __ b(eq, &fast);
1539 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1540 __ cmp(r1, ip);
1541 __ b(ne, &miss);
1542 __ bind(&fast);
1543 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001544 GenerateDirectLoadGlobalFunctionPrototype(
1545 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001546 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001547 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001548 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001549 break;
1550 }
1551
Steve Blocka7e24c12009-10-30 11:49:00 +00001552 default:
1553 UNREACHABLE();
1554 }
1555
Steve Block6ded16b2010-05-10 14:33:55 +01001556 if (depth != kInvalidProtoDepth) {
1557 GenerateFastApiCall(masm(), optimization, argc);
1558 } else {
1559 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1560 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001561
1562 // Handle call cache miss.
1563 __ bind(&miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001564 if (depth != kInvalidProtoDepth) {
1565 FreeSpaceForFastApiCall(masm());
1566 }
1567
1568 __ bind(&miss_in_smi_check);
Ben Murdochbb769b22010-08-11 14:56:33 +01001569 Object* obj = GenerateMissBranch();
1570 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001571
1572 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001573 return GetCode(function);
Steve Blocka7e24c12009-10-30 11:49:00 +00001574}
1575
1576
Andrei Popescu402d9372010-02-26 13:31:12 +00001577Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001578 JSObject* holder,
1579 String* name) {
1580 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001581 // -- r2 : name
1582 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001583 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001584
Steve Block6ded16b2010-05-10 14:33:55 +01001585 Label miss;
Andrei Popescu402d9372010-02-26 13:31:12 +00001586
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001587 GenerateNameCheck(name, &miss);
1588
Leon Clarke4515c472010-02-03 11:58:03 +00001589 // Get the number of arguments.
1590 const int argc = arguments().immediate();
1591
1592 LookupResult lookup;
1593 LookupPostInterceptor(holder, name, &lookup);
1594
Steve Block6ded16b2010-05-10 14:33:55 +01001595 // Get the receiver from the stack.
1596 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001597
Steve Block6ded16b2010-05-10 14:33:55 +01001598 CallInterceptorCompiler compiler(this, arguments(), r2);
1599 compiler.Compile(masm(),
1600 object,
1601 holder,
1602 name,
1603 &lookup,
1604 r1,
1605 r3,
1606 r4,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001607 r0,
Steve Block6ded16b2010-05-10 14:33:55 +01001608 &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001609
1610 // Move returned value, the function to call, to r1.
1611 __ mov(r1, r0);
Leon Clarke4515c472010-02-03 11:58:03 +00001612 // Restore receiver.
Steve Block6ded16b2010-05-10 14:33:55 +01001613 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001614
1615 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001616
1617 // Handle call cache miss.
1618 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001619 Object* obj = GenerateMissBranch();
1620 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001621
1622 // Return the generated code.
1623 return GetCode(INTERCEPTOR, name);
1624}
1625
1626
1627Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1628 GlobalObject* holder,
1629 JSGlobalPropertyCell* cell,
1630 JSFunction* function,
1631 String* name) {
1632 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001633 // -- r2 : name
1634 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001635 // -----------------------------------
1636 Label miss;
1637
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001638 GenerateNameCheck(name, &miss);
1639
Steve Blocka7e24c12009-10-30 11:49:00 +00001640 // Get the number of arguments.
1641 const int argc = arguments().immediate();
1642
1643 // Get the receiver from the stack.
1644 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1645
1646 // If the object is the holder then we know that it's a global
1647 // object which can only happen for contextual calls. In this case,
1648 // the receiver cannot be a smi.
1649 if (object != holder) {
1650 __ tst(r0, Operand(kSmiTagMask));
1651 __ b(eq, &miss);
1652 }
1653
1654 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001655 CheckPrototypes(object, r0, holder, r3, r1, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001656
1657 // Get the value from the cell.
1658 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1659 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1660
1661 // Check that the cell contains the same function.
Leon Clarkee46be812010-01-19 14:06:41 +00001662 if (Heap::InNewSpace(function)) {
1663 // We can't embed a pointer to a function in new space so we have
1664 // to verify that the shared function info is unchanged. This has
1665 // the nice side effect that multiple closures based on the same
1666 // function can all use this call IC. Before we load through the
1667 // function, we have to verify that it still is a function.
1668 __ tst(r1, Operand(kSmiTagMask));
1669 __ b(eq, &miss);
1670 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1671 __ b(ne, &miss);
1672
1673 // Check the shared function info. Make sure it hasn't changed.
1674 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
Andrei Popescu402d9372010-02-26 13:31:12 +00001675 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1676 __ cmp(r4, r3);
Leon Clarkee46be812010-01-19 14:06:41 +00001677 __ b(ne, &miss);
1678 } else {
1679 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1680 __ b(ne, &miss);
1681 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001682
1683 // Patch the receiver on the stack with the global proxy if
1684 // necessary.
1685 if (object->IsGlobalObject()) {
1686 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1687 __ str(r3, MemOperand(sp, argc * kPointerSize));
1688 }
1689
1690 // Setup the context (function already in r1).
1691 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1692
1693 // Jump to the cached code (tail call).
Steve Block6ded16b2010-05-10 14:33:55 +01001694 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001695 ASSERT(function->is_compiled());
1696 Handle<Code> code(function->code());
1697 ParameterCount expected(function->shared()->formal_parameter_count());
1698 __ InvokeCode(code, expected, arguments(),
1699 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1700
1701 // Handle call cache miss.
1702 __ bind(&miss);
1703 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
Ben Murdochbb769b22010-08-11 14:56:33 +01001704 Object* obj = GenerateMissBranch();
1705 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001706
1707 // Return the generated code.
1708 return GetCode(NORMAL, name);
1709}
1710
1711
1712Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1713 int index,
1714 Map* transition,
1715 String* name) {
1716 // ----------- S t a t e -------------
1717 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001718 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001719 // -- r2 : name
1720 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001721 // -----------------------------------
1722 Label miss;
1723
Steve Blocka7e24c12009-10-30 11:49:00 +00001724 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001725 object,
1726 index,
1727 transition,
Andrei Popescu402d9372010-02-26 13:31:12 +00001728 r1, r2, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001729 &miss);
1730 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001731 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1732 __ Jump(ic, RelocInfo::CODE_TARGET);
1733
1734 // Return the generated code.
1735 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1736}
1737
1738
1739Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1740 AccessorInfo* callback,
1741 String* name) {
1742 // ----------- S t a t e -------------
1743 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001744 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001745 // -- r2 : name
1746 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001747 // -----------------------------------
1748 Label miss;
1749
Steve Blocka7e24c12009-10-30 11:49:00 +00001750 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001751 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001752 __ b(eq, &miss);
1753
1754 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001755 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1756 __ cmp(r3, Operand(Handle<Map>(object->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001757 __ b(ne, &miss);
1758
1759 // Perform global security token check if needed.
1760 if (object->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001761 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001762 }
1763
1764 // Stub never generated for non-global objects that require access
1765 // checks.
1766 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1767
Andrei Popescu402d9372010-02-26 13:31:12 +00001768 __ push(r1); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001769 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
Steve Block6ded16b2010-05-10 14:33:55 +01001770 __ Push(ip, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001771
1772 // Do tail-call to the runtime system.
1773 ExternalReference store_callback_property =
1774 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001775 __ TailCallExternalReference(store_callback_property, 4, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001776
1777 // Handle store cache miss.
1778 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001779 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1780 __ Jump(ic, RelocInfo::CODE_TARGET);
1781
1782 // Return the generated code.
1783 return GetCode(CALLBACKS, name);
1784}
1785
1786
1787Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1788 String* name) {
1789 // ----------- S t a t e -------------
1790 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001791 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001792 // -- r2 : name
1793 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001794 // -----------------------------------
1795 Label miss;
1796
Steve Blocka7e24c12009-10-30 11:49:00 +00001797 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001798 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001799 __ b(eq, &miss);
1800
1801 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001802 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1803 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001804 __ b(ne, &miss);
1805
1806 // Perform global security token check if needed.
1807 if (receiver->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001808 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001809 }
1810
Andrei Popescu402d9372010-02-26 13:31:12 +00001811 // Stub is never generated for non-global objects that require access
Steve Blocka7e24c12009-10-30 11:49:00 +00001812 // checks.
1813 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1814
Steve Block6ded16b2010-05-10 14:33:55 +01001815 __ Push(r1, r2, r0); // Receiver, name, value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001816
1817 // Do tail-call to the runtime system.
1818 ExternalReference store_ic_property =
1819 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001820 __ TailCallExternalReference(store_ic_property, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001821
1822 // Handle store cache miss.
1823 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001824 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1825 __ Jump(ic, RelocInfo::CODE_TARGET);
1826
1827 // Return the generated code.
1828 return GetCode(INTERCEPTOR, name);
1829}
1830
1831
1832Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1833 JSGlobalPropertyCell* cell,
1834 String* name) {
1835 // ----------- S t a t e -------------
1836 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001837 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001838 // -- r2 : name
1839 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001840 // -----------------------------------
1841 Label miss;
1842
1843 // Check that the map of the global has not changed.
Steve Blocka7e24c12009-10-30 11:49:00 +00001844 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1845 __ cmp(r3, Operand(Handle<Map>(object->map())));
1846 __ b(ne, &miss);
1847
1848 // Store the value in the cell.
1849 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1850 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
1851
Andrei Popescu402d9372010-02-26 13:31:12 +00001852 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001853 __ Ret();
1854
1855 // Handle store cache miss.
1856 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001857 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001858 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1859 __ Jump(ic, RelocInfo::CODE_TARGET);
1860
1861 // Return the generated code.
1862 return GetCode(NORMAL, name);
1863}
1864
1865
Steve Block6ded16b2010-05-10 14:33:55 +01001866Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1867 JSObject* object,
1868 JSObject* last) {
1869 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001870 // -- r0 : receiver
Steve Block6ded16b2010-05-10 14:33:55 +01001871 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001872 // -----------------------------------
1873 Label miss;
1874
Steve Block6ded16b2010-05-10 14:33:55 +01001875 // Check that receiver is not a smi.
1876 __ tst(r0, Operand(kSmiTagMask));
1877 __ b(eq, &miss);
1878
1879 // Check the maps of the full prototype chain.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001880 CheckPrototypes(object, r0, last, r3, r1, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001881
1882 // If the last object in the prototype chain is a global object,
1883 // check that the global property cell is empty.
1884 if (last->IsGlobalObject()) {
1885 Object* cell = GenerateCheckPropertyCell(masm(),
1886 GlobalObject::cast(last),
1887 name,
1888 r1,
1889 &miss);
1890 if (cell->IsFailure()) return cell;
1891 }
1892
1893 // Return undefined if maps of the full prototype chain are still the
1894 // same and no global property with this name contains a value.
1895 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1896 __ Ret();
1897
1898 __ bind(&miss);
1899 GenerateLoadMiss(masm(), Code::LOAD_IC);
1900
1901 // Return the generated code.
1902 return GetCode(NONEXISTENT, Heap::empty_string());
1903}
1904
1905
Steve Blocka7e24c12009-10-30 11:49:00 +00001906Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1907 JSObject* holder,
1908 int index,
1909 String* name) {
1910 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001911 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001912 // -- r2 : name
1913 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001914 // -----------------------------------
1915 Label miss;
1916
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001917 GenerateLoadField(object, holder, r0, r3, r1, r4, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001918 __ bind(&miss);
1919 GenerateLoadMiss(masm(), Code::LOAD_IC);
1920
1921 // Return the generated code.
1922 return GetCode(FIELD, name);
1923}
1924
1925
Leon Clarkee46be812010-01-19 14:06:41 +00001926Object* LoadStubCompiler::CompileLoadCallback(String* name,
1927 JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001928 JSObject* holder,
Leon Clarkee46be812010-01-19 14:06:41 +00001929 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001930 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001931 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001932 // -- r2 : name
1933 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001934 // -----------------------------------
1935 Label miss;
1936
Leon Clarkee46be812010-01-19 14:06:41 +00001937 Failure* failure = Failure::InternalError();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001938 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1, r4,
Leon Clarkee46be812010-01-19 14:06:41 +00001939 callback, name, &miss, &failure);
1940 if (!success) return failure;
1941
Steve Blocka7e24c12009-10-30 11:49:00 +00001942 __ bind(&miss);
1943 GenerateLoadMiss(masm(), Code::LOAD_IC);
1944
1945 // Return the generated code.
1946 return GetCode(CALLBACKS, name);
1947}
1948
1949
1950Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1951 JSObject* holder,
1952 Object* value,
1953 String* name) {
1954 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001955 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001956 // -- r2 : name
1957 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001958 // -----------------------------------
1959 Label miss;
1960
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001961 GenerateLoadConstant(object, holder, r0, r3, r1, r4, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001962 __ bind(&miss);
1963 GenerateLoadMiss(masm(), Code::LOAD_IC);
1964
1965 // Return the generated code.
1966 return GetCode(CONSTANT_FUNCTION, name);
1967}
1968
1969
1970Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1971 JSObject* holder,
1972 String* name) {
1973 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001974 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001975 // -- r2 : name
1976 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001977 // -----------------------------------
1978 Label miss;
1979
Steve Blocka7e24c12009-10-30 11:49:00 +00001980 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001981 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001982 GenerateLoadInterceptor(object,
1983 holder,
1984 &lookup,
1985 r0,
1986 r2,
1987 r3,
1988 r1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001989 r4,
Steve Blocka7e24c12009-10-30 11:49:00 +00001990 name,
1991 &miss);
1992 __ bind(&miss);
1993 GenerateLoadMiss(masm(), Code::LOAD_IC);
1994
1995 // Return the generated code.
1996 return GetCode(INTERCEPTOR, name);
1997}
1998
1999
2000Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
2001 GlobalObject* holder,
2002 JSGlobalPropertyCell* cell,
2003 String* name,
2004 bool is_dont_delete) {
2005 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002006 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002007 // -- r2 : name
2008 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002009 // -----------------------------------
2010 Label miss;
2011
Steve Blocka7e24c12009-10-30 11:49:00 +00002012 // If the object is the holder then we know that it's a global
2013 // object which can only happen for contextual calls. In this case,
2014 // the receiver cannot be a smi.
2015 if (object != holder) {
Steve Block6ded16b2010-05-10 14:33:55 +01002016 __ tst(r0, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00002017 __ b(eq, &miss);
2018 }
2019
2020 // Check that the map of the global has not changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002021 CheckPrototypes(object, r0, holder, r3, r4, r1, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002022
2023 // Get the value from the cell.
2024 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
Steve Block6ded16b2010-05-10 14:33:55 +01002025 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00002026
2027 // Check for deleted property if property can actually be deleted.
2028 if (!is_dont_delete) {
2029 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
Steve Block6ded16b2010-05-10 14:33:55 +01002030 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00002031 __ b(eq, &miss);
2032 }
2033
Steve Block6ded16b2010-05-10 14:33:55 +01002034 __ mov(r0, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002035 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
2036 __ Ret();
2037
2038 __ bind(&miss);
2039 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
2040 GenerateLoadMiss(masm(), Code::LOAD_IC);
2041
2042 // Return the generated code.
2043 return GetCode(NORMAL, name);
2044}
2045
2046
2047Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
2048 JSObject* receiver,
2049 JSObject* holder,
2050 int index) {
2051 // ----------- S t a t e -------------
2052 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002053 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002054 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002055 // -----------------------------------
2056 Label miss;
2057
Steve Block6ded16b2010-05-10 14:33:55 +01002058 // Check the key is the cached one.
2059 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002060 __ b(ne, &miss);
2061
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002062 GenerateLoadField(receiver, holder, r1, r2, r3, r4, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002063 __ bind(&miss);
2064 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2065
2066 return GetCode(FIELD, name);
2067}
2068
2069
2070Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
2071 JSObject* receiver,
2072 JSObject* holder,
2073 AccessorInfo* callback) {
2074 // ----------- S t a t e -------------
2075 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002076 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002077 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002078 // -----------------------------------
2079 Label miss;
2080
Steve Block6ded16b2010-05-10 14:33:55 +01002081 // Check the key is the cached one.
2082 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002083 __ b(ne, &miss);
2084
Leon Clarkee46be812010-01-19 14:06:41 +00002085 Failure* failure = Failure::InternalError();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002086 bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3, r4,
Leon Clarkee46be812010-01-19 14:06:41 +00002087 callback, name, &miss, &failure);
2088 if (!success) return failure;
2089
Steve Blocka7e24c12009-10-30 11:49:00 +00002090 __ bind(&miss);
2091 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2092
2093 return GetCode(CALLBACKS, name);
2094}
2095
2096
2097Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
2098 JSObject* receiver,
2099 JSObject* holder,
2100 Object* value) {
2101 // ----------- S t a t e -------------
2102 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002103 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002104 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002105 // -----------------------------------
2106 Label miss;
2107
Steve Block6ded16b2010-05-10 14:33:55 +01002108 // Check the key is the cached one.
2109 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002110 __ b(ne, &miss);
2111
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002112 GenerateLoadConstant(receiver, holder, r1, r2, r3, r4, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002113 __ bind(&miss);
2114 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2115
2116 // Return the generated code.
2117 return GetCode(CONSTANT_FUNCTION, name);
2118}
2119
2120
2121Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
2122 JSObject* holder,
2123 String* name) {
2124 // ----------- S t a t e -------------
2125 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002126 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002127 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002128 // -----------------------------------
2129 Label miss;
2130
Steve Block6ded16b2010-05-10 14:33:55 +01002131 // Check the key is the cached one.
2132 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002133 __ b(ne, &miss);
2134
2135 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00002136 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00002137 GenerateLoadInterceptor(receiver,
2138 holder,
2139 &lookup,
Steve Block6ded16b2010-05-10 14:33:55 +01002140 r1,
Steve Blocka7e24c12009-10-30 11:49:00 +00002141 r0,
2142 r2,
2143 r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002144 r4,
Steve Blocka7e24c12009-10-30 11:49:00 +00002145 name,
2146 &miss);
2147 __ bind(&miss);
2148 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2149
2150 return GetCode(INTERCEPTOR, name);
2151}
2152
2153
2154Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
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
Steve Block6ded16b2010-05-10 14:33:55 +01002166 GenerateLoadArrayLength(masm(), r1, r2, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002167 __ bind(&miss);
2168 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2169
2170 return GetCode(CALLBACKS, name);
2171}
2172
2173
2174Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
2175 // ----------- S t a t e -------------
2176 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002177 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002178 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002179 // -----------------------------------
2180 Label miss;
2181 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
2182
Steve Block6ded16b2010-05-10 14:33:55 +01002183 // Check the key is the cached one.
2184 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002185 __ b(ne, &miss);
2186
Steve Block6ded16b2010-05-10 14:33:55 +01002187 GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002188 __ bind(&miss);
2189 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
2190
2191 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2192
2193 return GetCode(CALLBACKS, name);
2194}
2195
2196
2197// TODO(1224671): implement the fast case.
2198Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
2199 // ----------- S t a t e -------------
2200 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002201 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002202 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002203 // -----------------------------------
2204 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2205
2206 return GetCode(CALLBACKS, name);
2207}
2208
2209
2210Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
2211 int index,
2212 Map* transition,
2213 String* name) {
2214 // ----------- S t a t e -------------
2215 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01002216 // -- r1 : key
2217 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002218 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002219 // -----------------------------------
2220 Label miss;
2221
Leon Clarkef7060e22010-06-03 12:02:55 +01002222 __ IncrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002223
2224 // Check that the name has not changed.
Leon Clarkef7060e22010-06-03 12:02:55 +01002225 __ cmp(r1, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002226 __ b(ne, &miss);
2227
Leon Clarkef7060e22010-06-03 12:02:55 +01002228 // r3 is used as scratch register. r1 and r2 keep their values if a jump to
2229 // the miss label is generated.
Steve Blocka7e24c12009-10-30 11:49:00 +00002230 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002231 object,
2232 index,
2233 transition,
Leon Clarkef7060e22010-06-03 12:02:55 +01002234 r2, r1, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00002235 &miss);
2236 __ bind(&miss);
2237
Leon Clarkef7060e22010-06-03 12:02:55 +01002238 __ DecrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002239 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
Leon Clarkef7060e22010-06-03 12:02:55 +01002240
Steve Blocka7e24c12009-10-30 11:49:00 +00002241 __ Jump(ic, RelocInfo::CODE_TARGET);
2242
2243 // Return the generated code.
2244 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2245}
2246
2247
2248Object* ConstructStubCompiler::CompileConstructStub(
2249 SharedFunctionInfo* shared) {
2250 // ----------- S t a t e -------------
2251 // -- r0 : argc
2252 // -- r1 : constructor
2253 // -- lr : return address
2254 // -- [sp] : last argument
2255 // -----------------------------------
2256 Label generic_stub_call;
2257
2258 // Use r7 for holding undefined which is used in several places below.
2259 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2260
2261#ifdef ENABLE_DEBUGGER_SUPPORT
2262 // Check to see whether there are any break points in the function code. If
2263 // there are jump to the generic constructor stub which calls the actual
2264 // code for the function thereby hitting the break points.
2265 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2266 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2267 __ cmp(r2, r7);
2268 __ b(ne, &generic_stub_call);
2269#endif
2270
2271 // Load the initial map and verify that it is in fact a map.
2272 // r1: constructor function
2273 // r7: undefined
2274 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2275 __ tst(r2, Operand(kSmiTagMask));
2276 __ b(eq, &generic_stub_call);
2277 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2278 __ b(ne, &generic_stub_call);
2279
2280#ifdef DEBUG
2281 // Cannot construct functions this way.
2282 // r0: argc
2283 // r1: constructor function
2284 // r2: initial map
2285 // r7: undefined
2286 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2287 __ Check(ne, "Function constructed by construct stub.");
2288#endif
2289
2290 // Now allocate the JSObject in new space.
2291 // r0: argc
2292 // r1: constructor function
2293 // r2: initial map
2294 // r7: undefined
2295 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
2296 __ AllocateInNewSpace(r3,
2297 r4,
2298 r5,
2299 r6,
2300 &generic_stub_call,
Kristian Monsen25f61362010-05-21 11:50:48 +01002301 SIZE_IN_WORDS);
Steve Blocka7e24c12009-10-30 11:49:00 +00002302
2303 // Allocated the JSObject, now initialize the fields. Map is set to initial
2304 // map and properties and elements are set to empty fixed array.
2305 // r0: argc
2306 // r1: constructor function
2307 // r2: initial map
2308 // r3: object size (in words)
2309 // r4: JSObject (not tagged)
2310 // r7: undefined
2311 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2312 __ mov(r5, r4);
2313 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2314 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2315 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2316 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2317 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2318 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2319
2320 // Calculate the location of the first argument. The stack contains only the
2321 // argc arguments.
2322 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2323
2324 // Fill all the in-object properties with undefined.
2325 // r0: argc
2326 // r1: first argument
2327 // r3: object size (in words)
2328 // r4: JSObject (not tagged)
2329 // r5: First in-object property of JSObject (not tagged)
2330 // r7: undefined
2331 // Fill the initialized properties with a constant value or a passed argument
2332 // depending on the this.x = ...; assignment in the function.
2333 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2334 if (shared->IsThisPropertyAssignmentArgument(i)) {
2335 Label not_passed, next;
2336 // Check if the argument assigned to the property is actually passed.
2337 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2338 __ cmp(r0, Operand(arg_number));
2339 __ b(le, &not_passed);
2340 // Argument passed - find it on the stack.
2341 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2342 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2343 __ b(&next);
2344 __ bind(&not_passed);
2345 // Set the property to undefined.
2346 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2347 __ bind(&next);
2348 } else {
2349 // Set the property to the constant value.
2350 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2351 __ mov(r2, Operand(constant));
2352 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2353 }
2354 }
2355
2356 // Fill the unused in-object property fields with undefined.
2357 for (int i = shared->this_property_assignments_count();
2358 i < shared->CalculateInObjectProperties();
2359 i++) {
2360 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2361 }
2362
2363 // r0: argc
2364 // r4: JSObject (not tagged)
2365 // Move argc to r1 and the JSObject to return to r0 and tag it.
2366 __ mov(r1, r0);
2367 __ mov(r0, r4);
2368 __ orr(r0, r0, Operand(kHeapObjectTag));
2369
2370 // r0: JSObject
2371 // r1: argc
2372 // Remove caller arguments and receiver from the stack and return.
2373 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2374 __ add(sp, sp, Operand(kPointerSize));
2375 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2376 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2377 __ Jump(lr);
2378
2379 // Jump to the generic stub in case the specialized code cannot handle the
2380 // construction.
2381 __ bind(&generic_stub_call);
2382 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2383 Handle<Code> generic_construct_stub(code);
2384 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2385
2386 // Return the generated code.
2387 return GetCode();
2388}
2389
2390
2391#undef __
2392
2393} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002394
2395#endif // V8_TARGET_ARCH_ARM