blob: 97f94952d7dc30d44b911d13f57c59fa07b22e42 [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(
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100269 MacroAssembler* masm, int index, Register prototype, Label* miss) {
270 // Check we're still in the same context.
271 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
272 __ Move(ip, Top::global());
273 __ cmp(prototype, ip);
274 __ b(ne, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100275 // Get the global function with the given index.
276 JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
277 // Load its initial map. The global functions all have initial maps.
278 __ Move(prototype, Handle<Map>(function->initial_map()));
279 // Load the prototype from the initial map.
280 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
281}
282
283
Steve Blocka7e24c12009-10-30 11:49:00 +0000284// Load a fast property out of a holder object (src). In-object properties
285// are loaded directly otherwise the property is loaded from the properties
286// fixed array.
287void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
288 Register dst, Register src,
289 JSObject* holder, int index) {
290 // Adjust for the number of properties stored in the holder.
291 index -= holder->map()->inobject_properties();
292 if (index < 0) {
293 // Get the property straight out of the holder.
294 int offset = holder->map()->instance_size() + (index * kPointerSize);
295 __ ldr(dst, FieldMemOperand(src, offset));
296 } else {
297 // Calculate the offset into the properties array.
298 int offset = index * kPointerSize + FixedArray::kHeaderSize;
299 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
300 __ ldr(dst, FieldMemOperand(dst, offset));
301 }
302}
303
304
305void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
306 Register receiver,
307 Register scratch,
308 Label* miss_label) {
309 // Check that the receiver isn't a smi.
310 __ tst(receiver, Operand(kSmiTagMask));
311 __ b(eq, miss_label);
312
313 // Check that the object is a JS array.
314 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
315 __ b(ne, miss_label);
316
317 // Load length directly from the JS array.
318 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
319 __ Ret();
320}
321
322
Andrei Popescu402d9372010-02-26 13:31:12 +0000323// Generate code to check if an object is a string. If the object is a
324// heap object, its map's instance type is left in the scratch1 register.
325// If this is not needed, scratch1 and scratch2 may be the same register.
Steve Blocka7e24c12009-10-30 11:49:00 +0000326static void GenerateStringCheck(MacroAssembler* masm,
327 Register receiver,
328 Register scratch1,
329 Register scratch2,
330 Label* smi,
331 Label* non_string_object) {
332 // Check that the receiver isn't a smi.
333 __ tst(receiver, Operand(kSmiTagMask));
334 __ b(eq, smi);
335
336 // Check that the object is a string.
337 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
338 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
339 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
340 // The cast is to resolve the overload for the argument of 0x0.
341 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
342 __ b(ne, non_string_object);
343}
344
345
346// Generate code to load the length from a string object and return the length.
347// If the receiver object is not a string or a wrapped string object the
348// execution continues at the miss label. The register containing the
349// receiver is potentially clobbered.
Andrei Popescu402d9372010-02-26 13:31:12 +0000350void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
351 Register receiver,
352 Register scratch1,
353 Register scratch2,
354 Label* miss) {
355 Label check_wrapper;
Steve Blocka7e24c12009-10-30 11:49:00 +0000356
Steve Blocka7e24c12009-10-30 11:49:00 +0000357 // Check if the object is a string leaving the instance type in the
358 // scratch1 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000359 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
Steve Blocka7e24c12009-10-30 11:49:00 +0000360
361 // Load length directly from the string.
Steve Blocka7e24c12009-10-30 11:49:00 +0000362 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000363 __ Ret();
364
365 // Check if the object is a JSValue wrapper.
366 __ bind(&check_wrapper);
367 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
368 __ b(ne, miss);
369
Andrei Popescu402d9372010-02-26 13:31:12 +0000370 // Unwrap the value and check if the wrapped value is a string.
371 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
372 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
373 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
Andrei Popescu402d9372010-02-26 13:31:12 +0000374 __ Ret();
Steve Blocka7e24c12009-10-30 11:49:00 +0000375}
376
377
378void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
379 Register receiver,
380 Register scratch1,
381 Register scratch2,
382 Label* miss_label) {
383 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
384 __ mov(r0, scratch1);
385 __ Ret();
386}
387
388
389// Generate StoreField code, value is passed in r0 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000390// When leaving generated code after success, the receiver_reg and name_reg
391// may be clobbered. Upon branch to miss_label, the receiver and name
392// registers have their original values.
Steve Blocka7e24c12009-10-30 11:49:00 +0000393void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Steve Blocka7e24c12009-10-30 11:49:00 +0000394 JSObject* object,
395 int index,
396 Map* transition,
397 Register receiver_reg,
398 Register name_reg,
399 Register scratch,
400 Label* miss_label) {
401 // r0 : value
402 Label exit;
403
404 // Check that the receiver isn't a smi.
405 __ tst(receiver_reg, Operand(kSmiTagMask));
406 __ b(eq, miss_label);
407
408 // Check that the map of the receiver hasn't changed.
409 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
410 __ cmp(scratch, Operand(Handle<Map>(object->map())));
411 __ b(ne, miss_label);
412
413 // Perform global security token check if needed.
414 if (object->IsJSGlobalProxy()) {
415 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
416 }
417
418 // Stub never generated for non-global objects that require access
419 // checks.
420 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
421
422 // Perform map transition for the receiver if necessary.
423 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
424 // The properties must be extended before we can store the value.
425 // We jump to a runtime call that extends the properties array.
Andrei Popescu402d9372010-02-26 13:31:12 +0000426 __ push(receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000427 __ mov(r2, Operand(Handle<Map>(transition)));
Steve Block6ded16b2010-05-10 14:33:55 +0100428 __ Push(r2, r0);
429 __ TailCallExternalReference(
Andrei Popescu402d9372010-02-26 13:31:12 +0000430 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)),
431 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000432 return;
433 }
434
435 if (transition != NULL) {
436 // Update the map of the object; no write barrier updating is
437 // needed because the map is never in new space.
438 __ mov(ip, Operand(Handle<Map>(transition)));
439 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
440 }
441
442 // Adjust for the number of properties stored in the object. Even in the
443 // face of a transition we can use the old map here because the size of the
444 // object and the number of in-object properties is not going to change.
445 index -= object->map()->inobject_properties();
446
447 if (index < 0) {
448 // Set the property straight into the object.
449 int offset = object->map()->instance_size() + (index * kPointerSize);
450 __ str(r0, FieldMemOperand(receiver_reg, offset));
451
452 // Skip updating write barrier if storing a smi.
453 __ tst(r0, Operand(kSmiTagMask));
454 __ b(eq, &exit);
455
456 // Update the write barrier for the array address.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100457 // Pass the now unused name_reg as a scratch register.
458 __ RecordWrite(receiver_reg, Operand(offset), name_reg, scratch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000459 } else {
460 // Write to the properties array.
461 int offset = index * kPointerSize + FixedArray::kHeaderSize;
462 // Get the properties array
463 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
464 __ str(r0, FieldMemOperand(scratch, offset));
465
466 // Skip updating write barrier if storing a smi.
467 __ tst(r0, Operand(kSmiTagMask));
468 __ b(eq, &exit);
469
470 // Update the write barrier for the array address.
471 // Ok to clobber receiver_reg and name_reg, since we return.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100472 __ RecordWrite(scratch, Operand(offset), name_reg, receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000473 }
474
475 // Return the value (register r0).
476 __ bind(&exit);
477 __ Ret();
478}
479
480
481void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
482 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
483 Code* code = NULL;
484 if (kind == Code::LOAD_IC) {
485 code = Builtins::builtin(Builtins::LoadIC_Miss);
486 } else {
487 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
488 }
489
490 Handle<Code> ic(code);
491 __ Jump(ic, RelocInfo::CODE_TARGET);
492}
493
494
Leon Clarke4515c472010-02-03 11:58:03 +0000495static void GenerateCallFunction(MacroAssembler* masm,
496 Object* object,
497 const ParameterCount& arguments,
498 Label* miss) {
499 // ----------- S t a t e -------------
500 // -- r0: receiver
501 // -- r1: function to call
502 // -----------------------------------
503
504 // Check that the function really is a function.
505 __ BranchOnSmi(r1, miss);
Andrei Popescu402d9372010-02-26 13:31:12 +0000506 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
Leon Clarke4515c472010-02-03 11:58:03 +0000507 __ b(ne, miss);
508
509 // Patch the receiver on the stack with the global proxy if
510 // necessary.
511 if (object->IsGlobalObject()) {
512 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
513 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
514 }
515
516 // Invoke the function.
517 __ InvokeFunction(r1, arguments, JUMP_FUNCTION);
518}
519
520
Leon Clarke4515c472010-02-03 11:58:03 +0000521static void PushInterceptorArguments(MacroAssembler* masm,
522 Register receiver,
523 Register holder,
524 Register name,
525 JSObject* holder_obj) {
Leon Clarke4515c472010-02-03 11:58:03 +0000526 __ push(name);
527 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
528 ASSERT(!Heap::InNewSpace(interceptor));
Steve Block6ded16b2010-05-10 14:33:55 +0100529 Register scratch = name;
Leon Clarke4515c472010-02-03 11:58:03 +0000530 __ mov(scratch, Operand(Handle<Object>(interceptor)));
531 __ push(scratch);
Steve Block6ded16b2010-05-10 14:33:55 +0100532 __ push(receiver);
533 __ push(holder);
Leon Clarke4515c472010-02-03 11:58:03 +0000534 __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
535 __ push(scratch);
536}
537
538
539static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
540 Register receiver,
541 Register holder,
542 Register name,
543 JSObject* holder_obj) {
544 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
545
546 ExternalReference ref =
547 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
548 __ mov(r0, Operand(5));
549 __ mov(r1, Operand(ref));
550
551 CEntryStub stub(1);
552 __ CallStub(&stub);
553}
554
555
Steve Block6ded16b2010-05-10 14:33:55 +0100556// Reserves space for the extra arguments to FastHandleApiCall in the
557// caller's frame.
558//
559// These arguments are set by CheckPrototypes and GenerateFastApiCall.
560static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
561 Register scratch) {
562 __ mov(scratch, Operand(Smi::FromInt(0)));
563 __ push(scratch);
564 __ push(scratch);
565 __ push(scratch);
566 __ push(scratch);
567}
568
569
570// Undoes the effects of ReserveSpaceForFastApiCall.
571static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
572 __ Drop(4);
573}
574
575
576// Generates call to FastHandleApiCall builtin.
577static void GenerateFastApiCall(MacroAssembler* masm,
578 const CallOptimization& optimization,
579 int argc) {
580 // Get the function and setup the context.
581 JSFunction* function = optimization.constant_function();
582 __ mov(r7, Operand(Handle<JSFunction>(function)));
583 __ ldr(cp, FieldMemOperand(r7, JSFunction::kContextOffset));
584
585 // Pass the additional arguments FastHandleApiCall expects.
586 bool info_loaded = false;
587 Object* callback = optimization.api_call_info()->callback();
588 if (Heap::InNewSpace(callback)) {
589 info_loaded = true;
590 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
591 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
592 } else {
593 __ Move(r6, Handle<Object>(callback));
594 }
595 Object* call_data = optimization.api_call_info()->data();
596 if (Heap::InNewSpace(call_data)) {
597 if (!info_loaded) {
598 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
599 }
600 __ ldr(r5, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
601 } else {
602 __ Move(r5, Handle<Object>(call_data));
603 }
604
605 __ add(sp, sp, Operand(1 * kPointerSize));
606 __ stm(ia, sp, r5.bit() | r6.bit() | r7.bit());
607 __ sub(sp, sp, Operand(1 * kPointerSize));
608
609 // Set the number of arguments.
610 __ mov(r0, Operand(argc + 4));
611
612 // Jump to the fast api call builtin (tail call).
613 Handle<Code> code = Handle<Code>(
614 Builtins::builtin(Builtins::FastHandleApiCall));
615 ParameterCount expected(0);
616 __ InvokeCode(code, expected, expected,
617 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
618}
619
620
621class CallInterceptorCompiler BASE_EMBEDDED {
622 public:
623 CallInterceptorCompiler(StubCompiler* stub_compiler,
624 const ParameterCount& arguments,
625 Register name)
626 : stub_compiler_(stub_compiler),
627 arguments_(arguments),
628 name_(name) {}
629
630 void Compile(MacroAssembler* masm,
631 JSObject* object,
632 JSObject* holder,
633 String* name,
634 LookupResult* lookup,
635 Register receiver,
636 Register scratch1,
637 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100638 Register scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100639 Label* miss) {
640 ASSERT(holder->HasNamedInterceptor());
641 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
642
643 // Check that the receiver isn't a smi.
644 __ BranchOnSmi(receiver, miss);
645
646 CallOptimization optimization(lookup);
647
648 if (optimization.is_constant_call()) {
649 CompileCacheable(masm,
650 object,
651 receiver,
652 scratch1,
653 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100654 scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100655 holder,
656 lookup,
657 name,
658 optimization,
659 miss);
660 } else {
661 CompileRegular(masm,
662 object,
663 receiver,
664 scratch1,
665 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100666 scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100667 name,
668 holder,
669 miss);
670 }
671 }
672
673 private:
674 void CompileCacheable(MacroAssembler* masm,
675 JSObject* object,
676 Register receiver,
677 Register scratch1,
678 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100679 Register scratch3,
Leon Clarkef7060e22010-06-03 12:02:55 +0100680 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100681 LookupResult* lookup,
682 String* name,
683 const CallOptimization& optimization,
684 Label* miss_label) {
685 ASSERT(optimization.is_constant_call());
686 ASSERT(!lookup->holder()->IsGlobalObject());
687
688 int depth1 = kInvalidProtoDepth;
689 int depth2 = kInvalidProtoDepth;
690 bool can_do_fast_api_call = false;
691 if (optimization.is_simple_api_call() &&
692 !lookup->holder()->IsGlobalObject()) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100693 depth1 =
694 optimization.GetPrototypeDepthOfExpectedType(object,
695 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100696 if (depth1 == kInvalidProtoDepth) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100697 depth2 =
698 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
699 lookup->holder());
Steve Block6ded16b2010-05-10 14:33:55 +0100700 }
701 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
702 (depth2 != kInvalidProtoDepth);
703 }
704
705 __ IncrementCounter(&Counters::call_const_interceptor, 1,
706 scratch1, scratch2);
707
708 if (can_do_fast_api_call) {
709 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1,
710 scratch1, scratch2);
711 ReserveSpaceForFastApiCall(masm, scratch1);
712 }
713
Leon Clarkef7060e22010-06-03 12:02:55 +0100714 // Check that the maps from receiver to interceptor's holder
715 // haven't changed and thus we can invoke interceptor.
Steve Block6ded16b2010-05-10 14:33:55 +0100716 Label miss_cleanup;
717 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
718 Register holder =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100719 stub_compiler_->CheckPrototypes(object, receiver,
720 interceptor_holder, scratch1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100721 scratch2, scratch3, name, depth1, miss);
Steve Block6ded16b2010-05-10 14:33:55 +0100722
Leon Clarkef7060e22010-06-03 12:02:55 +0100723 // Invoke an interceptor and if it provides a value,
724 // branch to |regular_invoke|.
Steve Block6ded16b2010-05-10 14:33:55 +0100725 Label regular_invoke;
Leon Clarkef7060e22010-06-03 12:02:55 +0100726 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
Steve Block6ded16b2010-05-10 14:33:55 +0100727 &regular_invoke);
728
Leon Clarkef7060e22010-06-03 12:02:55 +0100729 // Interceptor returned nothing for this property. Try to use cached
730 // constant function.
Steve Block6ded16b2010-05-10 14:33:55 +0100731
Leon Clarkef7060e22010-06-03 12:02:55 +0100732 // Check that the maps from interceptor's holder to constant function's
733 // holder haven't changed and thus we can use cached constant function.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100734 if (interceptor_holder != lookup->holder()) {
735 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
736 lookup->holder(), scratch1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100737 scratch2, scratch3, name, depth2, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100738 } else {
739 // CheckPrototypes has a side effect of fetching a 'holder'
740 // for API (object which is instanceof for the signature). It's
741 // safe to omit it here, as if present, it should be fetched
742 // by the previous CheckPrototypes.
743 ASSERT(depth2 == kInvalidProtoDepth);
744 }
Steve Block6ded16b2010-05-10 14:33:55 +0100745
Leon Clarkef7060e22010-06-03 12:02:55 +0100746 // Invoke function.
Steve Block6ded16b2010-05-10 14:33:55 +0100747 if (can_do_fast_api_call) {
748 GenerateFastApiCall(masm, optimization, arguments_.immediate());
749 } else {
750 __ InvokeFunction(optimization.constant_function(), arguments_,
751 JUMP_FUNCTION);
752 }
753
Leon Clarkef7060e22010-06-03 12:02:55 +0100754 // Deferred code for fast API call case---clean preallocated space.
Steve Block6ded16b2010-05-10 14:33:55 +0100755 if (can_do_fast_api_call) {
756 __ bind(&miss_cleanup);
757 FreeSpaceForFastApiCall(masm);
758 __ b(miss_label);
759 }
760
Leon Clarkef7060e22010-06-03 12:02:55 +0100761 // Invoke a regular function.
Steve Block6ded16b2010-05-10 14:33:55 +0100762 __ bind(&regular_invoke);
763 if (can_do_fast_api_call) {
764 FreeSpaceForFastApiCall(masm);
765 }
766 }
767
768 void CompileRegular(MacroAssembler* masm,
769 JSObject* object,
770 Register receiver,
771 Register scratch1,
772 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100773 Register scratch3,
Steve Block6ded16b2010-05-10 14:33:55 +0100774 String* name,
Leon Clarkef7060e22010-06-03 12:02:55 +0100775 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100776 Label* miss_label) {
777 Register holder =
Leon Clarkef7060e22010-06-03 12:02:55 +0100778 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100779 scratch1, scratch2, scratch3, name,
Steve Block6ded16b2010-05-10 14:33:55 +0100780 miss_label);
781
782 // Call a runtime function to load the interceptor property.
783 __ EnterInternalFrame();
784 // Save the name_ register across the call.
785 __ push(name_);
786
787 PushInterceptorArguments(masm,
788 receiver,
789 holder,
790 name_,
Leon Clarkef7060e22010-06-03 12:02:55 +0100791 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100792
793 __ CallExternalReference(
794 ExternalReference(
795 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
796 5);
797
798 // Restore the name_ register.
799 __ pop(name_);
800 __ LeaveInternalFrame();
801 }
802
803 void LoadWithInterceptor(MacroAssembler* masm,
804 Register receiver,
805 Register holder,
806 JSObject* holder_obj,
807 Register scratch,
808 Label* interceptor_succeeded) {
809 __ EnterInternalFrame();
810 __ Push(holder, name_);
811
812 CompileCallLoadPropertyWithInterceptor(masm,
813 receiver,
814 holder,
815 name_,
816 holder_obj);
817
818 __ pop(name_); // Restore the name.
819 __ pop(receiver); // Restore the holder.
820 __ LeaveInternalFrame();
821
822 // If interceptor returns no-result sentinel, call the constant function.
823 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
824 __ cmp(r0, scratch);
825 __ b(ne, interceptor_succeeded);
826 }
827
828 StubCompiler* stub_compiler_;
829 const ParameterCount& arguments_;
830 Register name_;
831};
832
833
834// Generate code to check that a global property cell is empty. Create
835// the property cell at compilation time if no cell exists for the
836// property.
837static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
838 GlobalObject* global,
839 String* name,
840 Register scratch,
841 Label* miss) {
842 Object* probe = global->EnsurePropertyCell(name);
843 if (probe->IsFailure()) return probe;
844 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
845 ASSERT(cell->value()->IsTheHole());
846 __ mov(scratch, Operand(Handle<Object>(cell)));
847 __ ldr(scratch,
848 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
849 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
850 __ cmp(scratch, ip);
851 __ b(ne, miss);
852 return cell;
853}
854
855
Steve Blocka7e24c12009-10-30 11:49:00 +0000856#undef __
857#define __ ACCESS_MASM(masm())
858
859
860Register StubCompiler::CheckPrototypes(JSObject* object,
861 Register object_reg,
862 JSObject* holder,
863 Register holder_reg,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100864 Register scratch1,
865 Register scratch2,
Steve Blocka7e24c12009-10-30 11:49:00 +0000866 String* name,
Andrei Popescu402d9372010-02-26 13:31:12 +0000867 int save_at_depth,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100868 Label* miss) {
869 // Make sure there's no overlap between holder and object registers.
870 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
871 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
872 && !scratch2.is(scratch1));
873
874 // Keep track of the current object in register reg.
875 Register reg = object_reg;
876 int depth = 0;
877
878 if (save_at_depth == depth) {
879 __ str(reg, MemOperand(sp));
880 }
881
882 // Check the maps in the prototype chain.
883 // Traverse the prototype chain from the object and do map checks.
884 JSObject* current = object;
885 while (current != holder) {
886 depth++;
887
888 // Only global objects and objects that do not require access
889 // checks are allowed in stubs.
890 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
891
892 JSObject* prototype = JSObject::cast(current->GetPrototype());
893 if (!current->HasFastProperties() &&
894 !current->IsJSGlobalObject() &&
895 !current->IsJSGlobalProxy()) {
896 if (!name->IsSymbol()) {
897 Object* lookup_result = Heap::LookupSymbol(name);
898 if (lookup_result->IsFailure()) {
899 set_failure(Failure::cast(lookup_result));
900 return reg;
901 } else {
902 name = String::cast(lookup_result);
903 }
904 }
905 ASSERT(current->property_dictionary()->FindEntry(name) ==
906 StringDictionary::kNotFound);
907
908 GenerateDictionaryNegativeLookup(masm(),
909 miss,
910 reg,
911 name,
912 scratch1,
913 scratch2);
914 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
915 reg = holder_reg; // from now the object is in holder_reg
916 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
917 } else {
918 // Get the map of the current object.
919 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
920 __ cmp(scratch1, Operand(Handle<Map>(current->map())));
921
922 // Branch on the result of the map check.
923 __ b(ne, miss);
924
925 // Check access rights to the global object. This has to happen
926 // after the map check so that we know that the object is
927 // actually a global object.
928 if (current->IsJSGlobalProxy()) {
929 __ CheckAccessGlobalProxy(reg, scratch1, miss);
930 // Restore scratch register to be the map of the object. In the
931 // new space case below, we load the prototype from the map in
932 // the scratch register.
933 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
934 }
935
936 reg = holder_reg; // from now the object is in holder_reg
937 if (Heap::InNewSpace(prototype)) {
938 // The prototype is in new space; we cannot store a reference
939 // to it in the code. Load it from the map.
940 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
941 } else {
942 // The prototype is in old space; load it directly.
943 __ mov(reg, Operand(Handle<JSObject>(prototype)));
944 }
945 }
946
947 if (save_at_depth == depth) {
948 __ str(reg, MemOperand(sp));
949 }
950
951 // Go to the next object in the prototype chain.
952 current = prototype;
953 }
954
955 // Check the holder map.
956 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
957 __ cmp(scratch1, Operand(Handle<Map>(current->map())));
958 __ b(ne, miss);
959
960 // Log the check depth.
961 LOG(IntEvent("check-maps-depth", depth + 1));
962
963 // Perform security check for access to the global object and return
964 // the holder register.
965 ASSERT(current == holder);
966 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
967 if (current->IsJSGlobalProxy()) {
968 __ CheckAccessGlobalProxy(reg, scratch1, miss);
969 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000970
971 // If we've skipped any global objects, it's not enough to verify
Steve Block6ded16b2010-05-10 14:33:55 +0100972 // that their maps haven't changed. We also need to check that the
973 // property cell for the property is still empty.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100974 current = object;
975 while (current != holder) {
976 if (current->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100977 Object* cell = GenerateCheckPropertyCell(masm(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100978 GlobalObject::cast(current),
Steve Block6ded16b2010-05-10 14:33:55 +0100979 name,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100980 scratch1,
Steve Block6ded16b2010-05-10 14:33:55 +0100981 miss);
982 if (cell->IsFailure()) {
983 set_failure(Failure::cast(cell));
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100984 return reg;
Steve Blocka7e24c12009-10-30 11:49:00 +0000985 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000986 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100987 current = JSObject::cast(current->GetPrototype());
Steve Blocka7e24c12009-10-30 11:49:00 +0000988 }
989
Andrei Popescu402d9372010-02-26 13:31:12 +0000990 // Return the register containing the holder.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100991 return reg;
Steve Blocka7e24c12009-10-30 11:49:00 +0000992}
993
994
995void StubCompiler::GenerateLoadField(JSObject* object,
996 JSObject* holder,
997 Register receiver,
998 Register scratch1,
999 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001000 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001001 int index,
1002 String* name,
1003 Label* miss) {
1004 // Check that the receiver isn't a smi.
1005 __ tst(receiver, Operand(kSmiTagMask));
1006 __ b(eq, miss);
1007
1008 // Check that the maps haven't changed.
1009 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001010 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1011 name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001012 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
1013 __ Ret();
1014}
1015
1016
1017void StubCompiler::GenerateLoadConstant(JSObject* object,
1018 JSObject* holder,
1019 Register receiver,
1020 Register scratch1,
1021 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001022 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001023 Object* value,
1024 String* name,
1025 Label* miss) {
1026 // Check that the receiver isn't a smi.
1027 __ tst(receiver, Operand(kSmiTagMask));
1028 __ b(eq, miss);
1029
1030 // Check that the maps haven't changed.
1031 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001032 CheckPrototypes(object, receiver, holder,
1033 scratch1, scratch2, scratch3, name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001034
1035 // Return the constant value.
1036 __ mov(r0, Operand(Handle<Object>(value)));
1037 __ Ret();
1038}
1039
1040
Leon Clarkee46be812010-01-19 14:06:41 +00001041bool StubCompiler::GenerateLoadCallback(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001042 JSObject* holder,
1043 Register receiver,
1044 Register name_reg,
1045 Register scratch1,
1046 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001047 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001048 AccessorInfo* callback,
1049 String* name,
Leon Clarkee46be812010-01-19 14:06:41 +00001050 Label* miss,
1051 Failure** failure) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001052 // Check that the receiver isn't a smi.
1053 __ tst(receiver, Operand(kSmiTagMask));
1054 __ b(eq, miss);
1055
1056 // Check that the maps haven't changed.
1057 Register reg =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001058 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1059 name, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001060
1061 // Push the arguments on the JS stack of the caller.
Steve Block6ded16b2010-05-10 14:33:55 +01001062 __ push(receiver); // Receiver.
1063 __ push(reg); // Holder.
Steve Blocka7e24c12009-10-30 11:49:00 +00001064 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
Steve Blocka7e24c12009-10-30 11:49:00 +00001065 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
Steve Block6ded16b2010-05-10 14:33:55 +01001066 __ Push(ip, reg, name_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +00001067
1068 // Do tail-call to the runtime system.
1069 ExternalReference load_callback_property =
1070 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001071 __ TailCallExternalReference(load_callback_property, 5, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00001072
1073 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001074}
1075
1076
1077void StubCompiler::GenerateLoadInterceptor(JSObject* object,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001078 JSObject* interceptor_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +00001079 LookupResult* lookup,
1080 Register receiver,
1081 Register name_reg,
1082 Register scratch1,
1083 Register scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001084 Register scratch3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001085 String* name,
1086 Label* miss) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001087 ASSERT(interceptor_holder->HasNamedInterceptor());
1088 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1089
1090 // Check that the receiver isn't a smi.
1091 __ BranchOnSmi(receiver, miss);
1092
1093 // So far the most popular follow ups for interceptor loads are FIELD
1094 // and CALLBACKS, so inline only them, other cases may be added
1095 // later.
1096 bool compile_followup_inline = false;
1097 if (lookup->IsProperty() && lookup->IsCacheable()) {
1098 if (lookup->type() == FIELD) {
1099 compile_followup_inline = true;
1100 } else if (lookup->type() == CALLBACKS &&
1101 lookup->GetCallbackObject()->IsAccessorInfo() &&
1102 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
1103 compile_followup_inline = true;
1104 }
1105 }
1106
1107 if (compile_followup_inline) {
1108 // Compile the interceptor call, followed by inline code to load the
1109 // property from further up the prototype chain if the call fails.
1110 // Check that the maps haven't changed.
1111 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001112 scratch1, scratch2, scratch3,
1113 name, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001114 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1115
1116 // Save necessary data before invoking an interceptor.
1117 // Requires a frame to make GC aware of pushed pointers.
1118 __ EnterInternalFrame();
1119
1120 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1121 // CALLBACKS case needs a receiver to be passed into C++ callback.
1122 __ Push(receiver, holder_reg, name_reg);
1123 } else {
1124 __ Push(holder_reg, name_reg);
1125 }
1126
1127 // Invoke an interceptor. Note: map checks from receiver to
1128 // interceptor's holder has been compiled before (see a caller
1129 // of this method.)
1130 CompileCallLoadPropertyWithInterceptor(masm(),
1131 receiver,
1132 holder_reg,
1133 name_reg,
1134 interceptor_holder);
1135
1136 // Check if interceptor provided a value for property. If it's
1137 // the case, return immediately.
1138 Label interceptor_failed;
1139 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1140 __ cmp(r0, scratch1);
1141 __ b(eq, &interceptor_failed);
1142 __ LeaveInternalFrame();
1143 __ Ret();
1144
1145 __ bind(&interceptor_failed);
1146 __ pop(name_reg);
1147 __ pop(holder_reg);
1148 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1149 __ pop(receiver);
1150 }
1151
1152 __ LeaveInternalFrame();
1153
1154 // Check that the maps from interceptor's holder to lookup's holder
1155 // haven't changed. And load lookup's holder into |holder| register.
1156 if (interceptor_holder != lookup->holder()) {
1157 holder_reg = CheckPrototypes(interceptor_holder,
1158 holder_reg,
1159 lookup->holder(),
1160 scratch1,
1161 scratch2,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001162 scratch3,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001163 name,
1164 miss);
1165 }
1166
1167 if (lookup->type() == FIELD) {
1168 // We found FIELD property in prototype chain of interceptor's holder.
1169 // Retrieve a field from field's holder.
1170 GenerateFastPropertyLoad(masm(), r0, holder_reg,
1171 lookup->holder(), lookup->GetFieldIndex());
1172 __ Ret();
1173 } else {
1174 // We found CALLBACKS property in prototype chain of interceptor's
1175 // holder.
1176 ASSERT(lookup->type() == CALLBACKS);
1177 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
1178 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1179 ASSERT(callback != NULL);
1180 ASSERT(callback->getter() != NULL);
1181
1182 // Tail call to runtime.
1183 // Important invariant in CALLBACKS case: the code above must be
1184 // structured to never clobber |receiver| register.
1185 __ Move(scratch2, Handle<AccessorInfo>(callback));
1186 // holder_reg is either receiver or scratch1.
1187 if (!receiver.is(holder_reg)) {
1188 ASSERT(scratch1.is(holder_reg));
1189 __ Push(receiver, holder_reg, scratch2);
1190 __ ldr(scratch1,
1191 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
1192 __ Push(scratch1, name_reg);
1193 } else {
1194 __ push(receiver);
1195 __ ldr(scratch1,
1196 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
1197 __ Push(holder_reg, scratch2, scratch1, name_reg);
1198 }
1199
1200 ExternalReference ref =
1201 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
1202 __ TailCallExternalReference(ref, 5, 1);
1203 }
1204 } else { // !compile_followup_inline
1205 // Call the runtime system to load the interceptor.
1206 // Check that the maps haven't changed.
1207 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001208 scratch1, scratch2, scratch3,
1209 name, miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001210 PushInterceptorArguments(masm(), receiver, holder_reg,
1211 name_reg, interceptor_holder);
1212
1213 ExternalReference ref = ExternalReference(
1214 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
1215 __ TailCallExternalReference(ref, 5, 1);
1216 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001217}
1218
1219
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001220void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
1221 if (kind_ == Code::KEYED_CALL_IC) {
1222 __ cmp(r2, Operand(Handle<String>(name)));
1223 __ b(ne, miss);
1224 }
1225}
1226
1227
Steve Block59151502010-09-22 15:07:15 +01001228void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
1229 JSObject* holder,
1230 String* name,
1231 Label* miss) {
1232 ASSERT(holder->IsGlobalObject());
1233
1234 // Get the number of arguments.
1235 const int argc = arguments().immediate();
1236
1237 // Get the receiver from the stack.
1238 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1239
1240 // If the object is the holder then we know that it's a global
1241 // object which can only happen for contextual calls. In this case,
1242 // the receiver cannot be a smi.
1243 if (object != holder) {
1244 __ tst(r0, Operand(kSmiTagMask));
1245 __ b(eq, miss);
1246 }
1247
1248 // Check that the maps haven't changed.
1249 CheckPrototypes(object, r0, holder, r3, r1, r4, name, miss);
1250}
1251
1252
1253void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
1254 JSFunction* function,
1255 Label* miss) {
1256 // Get the value from the cell.
1257 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1258 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1259
1260 // Check that the cell contains the same function.
1261 if (Heap::InNewSpace(function)) {
1262 // We can't embed a pointer to a function in new space so we have
1263 // to verify that the shared function info is unchanged. This has
1264 // the nice side effect that multiple closures based on the same
1265 // function can all use this call IC. Before we load through the
1266 // function, we have to verify that it still is a function.
1267 __ tst(r1, Operand(kSmiTagMask));
1268 __ b(eq, miss);
1269 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1270 __ b(ne, miss);
1271
1272 // Check the shared function info. Make sure it hasn't changed.
1273 __ Move(r3, Handle<SharedFunctionInfo>(function->shared()));
1274 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1275 __ cmp(r4, r3);
1276 __ b(ne, miss);
1277 } else {
1278 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1279 __ b(ne, miss);
1280 }
1281}
1282
1283
Ben Murdochbb769b22010-08-11 14:56:33 +01001284Object* CallStubCompiler::GenerateMissBranch() {
1285 Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
1286 if (obj->IsFailure()) return obj;
1287 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1288 return obj;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001289}
1290
1291
Andrei Popescu402d9372010-02-26 13:31:12 +00001292Object* CallStubCompiler::CompileCallField(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001293 JSObject* holder,
1294 int index,
1295 String* name) {
1296 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001297 // -- r2 : name
1298 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001299 // -----------------------------------
1300 Label miss;
1301
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001302 GenerateNameCheck(name, &miss);
1303
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 const int argc = arguments().immediate();
1305
1306 // Get the receiver of the function from the stack into r0.
1307 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1308 // Check that the receiver isn't a smi.
1309 __ tst(r0, Operand(kSmiTagMask));
1310 __ b(eq, &miss);
1311
1312 // Do the right check and compute the holder register.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001313 Register reg = CheckPrototypes(object, r0, holder, r1, r3, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001314 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
1315
Leon Clarke4515c472010-02-03 11:58:03 +00001316 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001317
1318 // Handle call cache miss.
1319 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001320 Object* obj = GenerateMissBranch();
1321 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001322
1323 // Return the generated code.
1324 return GetCode(FIELD, name);
1325}
1326
1327
Steve Block6ded16b2010-05-10 14:33:55 +01001328Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1329 JSObject* holder,
Steve Block59151502010-09-22 15:07:15 +01001330 JSGlobalPropertyCell* cell,
Steve Block6ded16b2010-05-10 14:33:55 +01001331 JSFunction* function,
Steve Block59151502010-09-22 15:07:15 +01001332 String* name) {
Steve Block6ded16b2010-05-10 14:33:55 +01001333 // ----------- S t a t e -------------
1334 // -- r2 : name
1335 // -- lr : return address
1336 // -----------------------------------
1337
Steve Block6ded16b2010-05-10 14:33:55 +01001338 // TODO(639): faster implementation.
Steve Block59151502010-09-22 15:07:15 +01001339
1340 // If object is not an array, bail out to regular call.
1341 if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001342
1343 Label miss;
1344
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001345 GenerateNameCheck(name, &miss);
1346
Steve Block6ded16b2010-05-10 14:33:55 +01001347 // Get the receiver from the stack
1348 const int argc = arguments().immediate();
1349 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1350
1351 // Check that the receiver isn't a smi.
1352 __ tst(r1, Operand(kSmiTagMask));
1353 __ b(eq, &miss);
1354
1355 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001356 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001357
Steve Block6ded16b2010-05-10 14:33:55 +01001358 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1359 argc + 1,
1360 1);
1361
1362 // Handle call cache miss.
1363 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001364 Object* obj = GenerateMissBranch();
1365 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +01001366
1367 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001368 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001369}
1370
1371
1372Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1373 JSObject* holder,
Steve Block59151502010-09-22 15:07:15 +01001374 JSGlobalPropertyCell* cell,
Steve Block6ded16b2010-05-10 14:33:55 +01001375 JSFunction* function,
Steve Block59151502010-09-22 15:07:15 +01001376 String* name) {
Steve Block6ded16b2010-05-10 14:33:55 +01001377 // ----------- S t a t e -------------
1378 // -- r2 : name
1379 // -- lr : return address
1380 // -----------------------------------
1381
Steve Block6ded16b2010-05-10 14:33:55 +01001382 // TODO(642): faster implementation.
Steve Block59151502010-09-22 15:07:15 +01001383
1384 // If object is not an array, bail out to regular call.
1385 if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001386
1387 Label miss;
1388
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001389 GenerateNameCheck(name, &miss);
1390
Steve Block6ded16b2010-05-10 14:33:55 +01001391 // Get the receiver from the stack
1392 const int argc = arguments().immediate();
1393 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1394
1395 // Check that the receiver isn't a smi.
1396 __ tst(r1, Operand(kSmiTagMask));
1397 __ b(eq, &miss);
1398
1399 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001400 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001401
Steve Block6ded16b2010-05-10 14:33:55 +01001402 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1403 argc + 1,
1404 1);
1405
1406 // Handle call cache miss.
1407 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001408 Object* obj = GenerateMissBranch();
1409 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +01001410
1411 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001412 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001413}
1414
1415
Steve Block59151502010-09-22 15:07:15 +01001416Object* CallStubCompiler::CompileStringCharCodeAtCall(
1417 Object* object,
1418 JSObject* holder,
1419 JSGlobalPropertyCell* cell,
1420 JSFunction* function,
1421 String* name) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001422 // ----------- S t a t e -------------
1423 // -- r2 : function name
1424 // -- lr : return address
1425 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1426 // -- ...
1427 // -- sp[argc * 4] : receiver
1428 // -----------------------------------
1429
1430 // If object is not a string, bail out to regular call.
Steve Block59151502010-09-22 15:07:15 +01001431 if (!object->IsString() || cell != NULL) return Heap::undefined_value();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001432
1433 const int argc = arguments().immediate();
1434
1435 Label miss;
1436 Label index_out_of_range;
1437 GenerateNameCheck(name, &miss);
1438
1439 // Check that the maps starting from the prototype haven't changed.
1440 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1441 Context::STRING_FUNCTION_INDEX,
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001442 r0,
1443 &miss);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001444 ASSERT(object != holder);
1445 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder,
1446 r1, r3, r4, name, &miss);
1447
1448 Register receiver = r1;
1449 Register index = r4;
1450 Register scratch = r3;
1451 Register result = r0;
1452 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
1453 if (argc > 0) {
1454 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
1455 } else {
1456 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1457 }
1458
1459 StringCharCodeAtGenerator char_code_at_generator(receiver,
1460 index,
1461 scratch,
1462 result,
1463 &miss, // When not a string.
1464 &miss, // When not a number.
1465 &index_out_of_range,
1466 STRING_INDEX_IS_NUMBER);
1467 char_code_at_generator.GenerateFast(masm());
1468 __ Drop(argc + 1);
1469 __ Ret();
1470
1471 ICRuntimeCallHelper call_helper;
1472 char_code_at_generator.GenerateSlow(masm(), call_helper);
1473
1474 __ bind(&index_out_of_range);
1475 __ LoadRoot(r0, Heap::kNanValueRootIndex);
1476 __ Drop(argc + 1);
1477 __ Ret();
1478
1479 __ bind(&miss);
1480 Object* obj = GenerateMissBranch();
1481 if (obj->IsFailure()) return obj;
1482
1483 // Return the generated code.
1484 return GetCode(function);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001485}
1486
1487
1488Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
1489 JSObject* holder,
Steve Block59151502010-09-22 15:07:15 +01001490 JSGlobalPropertyCell* cell,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001491 JSFunction* function,
Steve Block59151502010-09-22 15:07:15 +01001492 String* name) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001493 // ----------- S t a t e -------------
1494 // -- r2 : function name
1495 // -- lr : return address
1496 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1497 // -- ...
1498 // -- sp[argc * 4] : receiver
1499 // -----------------------------------
1500
1501 // If object is not a string, bail out to regular call.
Steve Block59151502010-09-22 15:07:15 +01001502 if (!object->IsString() || cell != NULL) return Heap::undefined_value();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001503
1504 const int argc = arguments().immediate();
1505
1506 Label miss;
1507 Label index_out_of_range;
1508
1509 GenerateNameCheck(name, &miss);
1510
1511 // Check that the maps starting from the prototype haven't changed.
1512 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1513 Context::STRING_FUNCTION_INDEX,
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001514 r0,
1515 &miss);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001516 ASSERT(object != holder);
1517 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder,
1518 r1, r3, r4, name, &miss);
1519
1520 Register receiver = r0;
1521 Register index = r4;
1522 Register scratch1 = r1;
1523 Register scratch2 = r3;
1524 Register result = r0;
1525 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
1526 if (argc > 0) {
1527 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
1528 } else {
1529 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1530 }
1531
1532 StringCharAtGenerator char_at_generator(receiver,
1533 index,
1534 scratch1,
1535 scratch2,
1536 result,
1537 &miss, // When not a string.
1538 &miss, // When not a number.
1539 &index_out_of_range,
1540 STRING_INDEX_IS_NUMBER);
1541 char_at_generator.GenerateFast(masm());
1542 __ Drop(argc + 1);
1543 __ Ret();
1544
1545 ICRuntimeCallHelper call_helper;
1546 char_at_generator.GenerateSlow(masm(), call_helper);
1547
1548 __ bind(&index_out_of_range);
1549 __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
1550 __ Drop(argc + 1);
1551 __ Ret();
1552
1553 __ bind(&miss);
1554 Object* obj = GenerateMissBranch();
1555 if (obj->IsFailure()) return obj;
1556
1557 // Return the generated code.
1558 return GetCode(function);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001559}
1560
1561
Steve Block59151502010-09-22 15:07:15 +01001562Object* CallStubCompiler::CompileStringFromCharCodeCall(
1563 Object* object,
1564 JSObject* holder,
1565 JSGlobalPropertyCell* cell,
1566 JSFunction* function,
1567 String* name) {
1568 // ----------- S t a t e -------------
1569 // -- r2 : function name
1570 // -- lr : return address
1571 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1572 // -- ...
1573 // -- sp[argc * 4] : receiver
1574 // -----------------------------------
1575
1576 const int argc = arguments().immediate();
1577
1578 // If the object is not a JSObject or we got an unexpected number of
1579 // arguments, bail out to the regular call.
1580 if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
1581
1582 Label miss;
1583 GenerateNameCheck(name, &miss);
1584
1585 if (cell == NULL) {
1586 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
1587
1588 STATIC_ASSERT(kSmiTag == 0);
1589 __ tst(r1, Operand(kSmiTagMask));
1590 __ b(eq, &miss);
1591
1592 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
1593 &miss);
1594 } else {
1595 ASSERT(cell->value() == function);
1596 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
1597 GenerateLoadFunctionFromCell(cell, function, &miss);
1598 }
1599
1600 // Load the char code argument.
1601 Register code = r1;
1602 __ ldr(code, MemOperand(sp, 0 * kPointerSize));
1603
1604 // Check the code is a smi.
1605 Label slow;
1606 STATIC_ASSERT(kSmiTag == 0);
1607 __ tst(code, Operand(kSmiTagMask));
1608 __ b(ne, &slow);
1609
1610 // Convert the smi code to uint16.
1611 __ and_(code, code, Operand(Smi::FromInt(0xffff)));
1612
1613 StringCharFromCodeGenerator char_from_code_generator(code, r0);
1614 char_from_code_generator.GenerateFast(masm());
1615 __ Drop(argc + 1);
1616 __ Ret();
1617
1618 ICRuntimeCallHelper call_helper;
1619 char_from_code_generator.GenerateSlow(masm(), call_helper);
1620
1621 // Tail call the full function. We do not have to patch the receiver
1622 // because the function makes no use of it.
1623 __ bind(&slow);
1624 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1625
1626 __ bind(&miss);
1627 // r2: function name.
1628 Object* obj = GenerateMissBranch();
1629 if (obj->IsFailure()) return obj;
1630
1631 // Return the generated code.
1632 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
1633}
1634
1635
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001636Object* CallStubCompiler::CompileMathFloorCall(Object* object,
1637 JSObject* holder,
1638 JSGlobalPropertyCell* cell,
1639 JSFunction* function,
1640 String* name) {
1641 // TODO(872): implement this.
1642 return Heap::undefined_value();
1643}
1644
1645
Ben Murdochf87a2032010-10-22 12:50:53 +01001646Object* CallStubCompiler::CompileMathAbsCall(Object* object,
1647 JSObject* holder,
1648 JSGlobalPropertyCell* cell,
1649 JSFunction* function,
1650 String* name) {
1651 // ----------- S t a t e -------------
1652 // -- r2 : function name
1653 // -- lr : return address
1654 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1655 // -- ...
1656 // -- sp[argc * 4] : receiver
1657 // -----------------------------------
1658
1659 const int argc = arguments().immediate();
1660
1661 // If the object is not a JSObject or we got an unexpected number of
1662 // arguments, bail out to the regular call.
1663 if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
1664
1665 Label miss;
1666 GenerateNameCheck(name, &miss);
1667
1668 if (cell == NULL) {
1669 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
1670
1671 STATIC_ASSERT(kSmiTag == 0);
1672 __ tst(r1, Operand(kSmiTagMask));
1673 __ b(eq, &miss);
1674
1675 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
1676 &miss);
1677 } else {
1678 ASSERT(cell->value() == function);
1679 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
1680 GenerateLoadFunctionFromCell(cell, function, &miss);
1681 }
1682
1683 // Load the (only) argument into r0.
1684 __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
1685
1686 // Check if the argument is a smi.
1687 Label not_smi;
1688 STATIC_ASSERT(kSmiTag == 0);
1689 __ BranchOnNotSmi(r0, &not_smi);
1690
1691 // Do bitwise not or do nothing depending on the sign of the
1692 // argument.
1693 __ eor(r1, r0, Operand(r0, ASR, kBitsPerInt - 1));
1694
1695 // Add 1 or do nothing depending on the sign of the argument.
1696 __ sub(r0, r1, Operand(r0, ASR, kBitsPerInt - 1), SetCC);
1697
1698 // If the result is still negative, go to the slow case.
1699 // This only happens for the most negative smi.
1700 Label slow;
1701 __ b(mi, &slow);
1702
1703 // Smi case done.
1704 __ Drop(argc + 1);
1705 __ Ret();
1706
1707 // Check if the argument is a heap number and load its exponent and
1708 // sign.
1709 __ bind(&not_smi);
1710 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, true);
1711 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset));
1712
1713 // Check the sign of the argument. If the argument is positive,
1714 // just return it.
1715 Label negative_sign;
1716 __ tst(r1, Operand(HeapNumber::kSignMask));
1717 __ b(ne, &negative_sign);
1718 __ Drop(argc + 1);
1719 __ Ret();
1720
1721 // If the argument is negative, clear the sign, and return a new
1722 // number.
1723 __ bind(&negative_sign);
1724 __ eor(r1, r1, Operand(HeapNumber::kSignMask));
1725 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
1726 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
1727 __ AllocateHeapNumber(r0, r4, r5, r6, &slow);
1728 __ str(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset));
1729 __ str(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
1730 __ Drop(argc + 1);
1731 __ Ret();
1732
1733 // Tail call the full function. We do not have to patch the receiver
1734 // because the function makes no use of it.
1735 __ bind(&slow);
1736 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1737
1738 __ bind(&miss);
1739 // r2: function name.
1740 Object* obj = GenerateMissBranch();
1741 if (obj->IsFailure()) return obj;
1742
1743 // Return the generated code.
1744 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
1745}
1746
1747
Steve Blocka7e24c12009-10-30 11:49:00 +00001748Object* CallStubCompiler::CompileCallConstant(Object* object,
1749 JSObject* holder,
1750 JSFunction* function,
1751 String* name,
1752 CheckType check) {
1753 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001754 // -- r2 : name
1755 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001756 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001757 SharedFunctionInfo* function_info = function->shared();
1758 if (function_info->HasCustomCallGenerator()) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001759 const int id = function_info->custom_call_generator_id();
Steve Block59151502010-09-22 15:07:15 +01001760 Object* result = CompileCustomCall(
1761 id, object, holder, NULL, function, name);
Steve Block6ded16b2010-05-10 14:33:55 +01001762 // undefined means bail out to regular compiler.
1763 if (!result->IsUndefined()) {
1764 return result;
1765 }
1766 }
1767
1768 Label miss_in_smi_check;
Steve Blocka7e24c12009-10-30 11:49:00 +00001769
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001770 GenerateNameCheck(name, &miss_in_smi_check);
1771
Steve Blocka7e24c12009-10-30 11:49:00 +00001772 // Get the receiver from the stack
1773 const int argc = arguments().immediate();
1774 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1775
1776 // Check that the receiver isn't a smi.
1777 if (check != NUMBER_CHECK) {
1778 __ tst(r1, Operand(kSmiTagMask));
Steve Block6ded16b2010-05-10 14:33:55 +01001779 __ b(eq, &miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001780 }
1781
1782 // Make sure that it's okay not to patch the on stack receiver
1783 // unless we're doing a receiver map check.
1784 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1785
Steve Block6ded16b2010-05-10 14:33:55 +01001786 CallOptimization optimization(function);
1787 int depth = kInvalidProtoDepth;
1788 Label miss;
1789
Steve Blocka7e24c12009-10-30 11:49:00 +00001790 switch (check) {
1791 case RECEIVER_MAP_CHECK:
Steve Block6ded16b2010-05-10 14:33:55 +01001792 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1793
1794 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1795 depth = optimization.GetPrototypeDepthOfExpectedType(
1796 JSObject::cast(object), holder);
1797 }
1798
1799 if (depth != kInvalidProtoDepth) {
1800 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1801 ReserveSpaceForFastApiCall(masm(), r0);
1802 }
1803
Steve Blocka7e24c12009-10-30 11:49:00 +00001804 // Check that the maps haven't changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001805 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
Steve Block6ded16b2010-05-10 14:33:55 +01001806 depth, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001807
1808 // Patch the receiver on the stack with the global proxy if
1809 // necessary.
1810 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001811 ASSERT(depth == kInvalidProtoDepth);
Steve Blocka7e24c12009-10-30 11:49:00 +00001812 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1813 __ str(r3, MemOperand(sp, argc * kPointerSize));
1814 }
1815 break;
1816
1817 case STRING_CHECK:
Leon Clarkee46be812010-01-19 14:06:41 +00001818 if (!function->IsBuiltin()) {
1819 // Calling non-builtins with a value as receiver requires boxing.
1820 __ jmp(&miss);
1821 } else {
1822 // Check that the object is a two-byte string or a symbol.
Andrei Popescu402d9372010-02-26 13:31:12 +00001823 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001824 __ b(hs, &miss);
1825 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001826 GenerateDirectLoadGlobalFunctionPrototype(
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001827 masm(), Context::STRING_FUNCTION_INDEX, r0, &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001828 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001829 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001830 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001831 break;
1832
1833 case NUMBER_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001834 if (!function->IsBuiltin()) {
1835 // Calling non-builtins with a value as receiver requires boxing.
1836 __ jmp(&miss);
1837 } else {
1838 Label fast;
1839 // Check that the object is a smi or a heap number.
1840 __ tst(r1, Operand(kSmiTagMask));
1841 __ b(eq, &fast);
Andrei Popescu402d9372010-02-26 13:31:12 +00001842 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001843 __ b(ne, &miss);
1844 __ bind(&fast);
1845 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001846 GenerateDirectLoadGlobalFunctionPrototype(
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001847 masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001848 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001849 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001850 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001851 break;
1852 }
1853
1854 case BOOLEAN_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001855 if (!function->IsBuiltin()) {
1856 // Calling non-builtins with a value as receiver requires boxing.
1857 __ jmp(&miss);
1858 } else {
1859 Label fast;
1860 // Check that the object is a boolean.
1861 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1862 __ cmp(r1, ip);
1863 __ b(eq, &fast);
1864 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1865 __ cmp(r1, ip);
1866 __ b(ne, &miss);
1867 __ bind(&fast);
1868 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001869 GenerateDirectLoadGlobalFunctionPrototype(
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001870 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001871 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001872 r1, r4, name, &miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001873 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001874 break;
1875 }
1876
Steve Blocka7e24c12009-10-30 11:49:00 +00001877 default:
1878 UNREACHABLE();
1879 }
1880
Steve Block6ded16b2010-05-10 14:33:55 +01001881 if (depth != kInvalidProtoDepth) {
1882 GenerateFastApiCall(masm(), optimization, argc);
1883 } else {
1884 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1885 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001886
1887 // Handle call cache miss.
1888 __ bind(&miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001889 if (depth != kInvalidProtoDepth) {
1890 FreeSpaceForFastApiCall(masm());
1891 }
1892
1893 __ bind(&miss_in_smi_check);
Ben Murdochbb769b22010-08-11 14:56:33 +01001894 Object* obj = GenerateMissBranch();
1895 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001896
1897 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001898 return GetCode(function);
Steve Blocka7e24c12009-10-30 11:49:00 +00001899}
1900
1901
Andrei Popescu402d9372010-02-26 13:31:12 +00001902Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001903 JSObject* holder,
1904 String* name) {
1905 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001906 // -- r2 : name
1907 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001908 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001909
Steve Block6ded16b2010-05-10 14:33:55 +01001910 Label miss;
Andrei Popescu402d9372010-02-26 13:31:12 +00001911
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001912 GenerateNameCheck(name, &miss);
1913
Leon Clarke4515c472010-02-03 11:58:03 +00001914 // Get the number of arguments.
1915 const int argc = arguments().immediate();
1916
1917 LookupResult lookup;
1918 LookupPostInterceptor(holder, name, &lookup);
1919
Steve Block6ded16b2010-05-10 14:33:55 +01001920 // Get the receiver from the stack.
1921 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001922
Steve Block6ded16b2010-05-10 14:33:55 +01001923 CallInterceptorCompiler compiler(this, arguments(), r2);
1924 compiler.Compile(masm(),
1925 object,
1926 holder,
1927 name,
1928 &lookup,
1929 r1,
1930 r3,
1931 r4,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001932 r0,
Steve Block6ded16b2010-05-10 14:33:55 +01001933 &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001934
1935 // Move returned value, the function to call, to r1.
1936 __ mov(r1, r0);
Leon Clarke4515c472010-02-03 11:58:03 +00001937 // Restore receiver.
Steve Block6ded16b2010-05-10 14:33:55 +01001938 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001939
1940 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001941
1942 // Handle call cache miss.
1943 __ bind(&miss);
Ben Murdochbb769b22010-08-11 14:56:33 +01001944 Object* obj = GenerateMissBranch();
1945 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00001946
1947 // Return the generated code.
1948 return GetCode(INTERCEPTOR, name);
1949}
1950
1951
1952Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1953 GlobalObject* holder,
1954 JSGlobalPropertyCell* cell,
1955 JSFunction* function,
1956 String* name) {
1957 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001958 // -- r2 : name
1959 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001960 // -----------------------------------
Steve Block59151502010-09-22 15:07:15 +01001961
1962 SharedFunctionInfo* function_info = function->shared();
1963 if (function_info->HasCustomCallGenerator()) {
1964 const int id = function_info->custom_call_generator_id();
1965 Object* result = CompileCustomCall(
1966 id, object, holder, cell, function, name);
1967 // undefined means bail out to regular compiler.
1968 if (!result->IsUndefined()) return result;
1969 }
1970
Steve Blocka7e24c12009-10-30 11:49:00 +00001971 Label miss;
1972
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001973 GenerateNameCheck(name, &miss);
1974
Steve Blocka7e24c12009-10-30 11:49:00 +00001975 // Get the number of arguments.
1976 const int argc = arguments().immediate();
1977
Steve Block59151502010-09-22 15:07:15 +01001978 GenerateGlobalReceiverCheck(object, holder, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001979
Steve Block59151502010-09-22 15:07:15 +01001980 GenerateLoadFunctionFromCell(cell, function, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001981
1982 // Patch the receiver on the stack with the global proxy if
1983 // necessary.
1984 if (object->IsGlobalObject()) {
1985 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1986 __ str(r3, MemOperand(sp, argc * kPointerSize));
1987 }
1988
1989 // Setup the context (function already in r1).
1990 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1991
1992 // Jump to the cached code (tail call).
Steve Block6ded16b2010-05-10 14:33:55 +01001993 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001994 ASSERT(function->is_compiled());
1995 Handle<Code> code(function->code());
1996 ParameterCount expected(function->shared()->formal_parameter_count());
1997 __ InvokeCode(code, expected, arguments(),
1998 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1999
2000 // Handle call cache miss.
2001 __ bind(&miss);
2002 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
Ben Murdochbb769b22010-08-11 14:56:33 +01002003 Object* obj = GenerateMissBranch();
2004 if (obj->IsFailure()) return obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00002005
2006 // Return the generated code.
2007 return GetCode(NORMAL, name);
2008}
2009
2010
2011Object* StoreStubCompiler::CompileStoreField(JSObject* object,
2012 int index,
2013 Map* transition,
2014 String* name) {
2015 // ----------- S t a t e -------------
2016 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00002017 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002018 // -- r2 : name
2019 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002020 // -----------------------------------
2021 Label miss;
2022
Steve Blocka7e24c12009-10-30 11:49:00 +00002023 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002024 object,
2025 index,
2026 transition,
Andrei Popescu402d9372010-02-26 13:31:12 +00002027 r1, r2, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00002028 &miss);
2029 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002030 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2031 __ Jump(ic, RelocInfo::CODE_TARGET);
2032
2033 // Return the generated code.
2034 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2035}
2036
2037
2038Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
2039 AccessorInfo* callback,
2040 String* name) {
2041 // ----------- S t a t e -------------
2042 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00002043 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002044 // -- r2 : name
2045 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002046 // -----------------------------------
2047 Label miss;
2048
Steve Blocka7e24c12009-10-30 11:49:00 +00002049 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00002050 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00002051 __ b(eq, &miss);
2052
2053 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00002054 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
2055 __ cmp(r3, Operand(Handle<Map>(object->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00002056 __ b(ne, &miss);
2057
2058 // Perform global security token check if needed.
2059 if (object->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002060 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002061 }
2062
2063 // Stub never generated for non-global objects that require access
2064 // checks.
2065 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2066
Andrei Popescu402d9372010-02-26 13:31:12 +00002067 __ push(r1); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002068 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
Steve Block6ded16b2010-05-10 14:33:55 +01002069 __ Push(ip, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002070
2071 // Do tail-call to the runtime system.
2072 ExternalReference store_callback_property =
2073 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01002074 __ TailCallExternalReference(store_callback_property, 4, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002075
2076 // Handle store cache miss.
2077 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002078 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2079 __ Jump(ic, RelocInfo::CODE_TARGET);
2080
2081 // Return the generated code.
2082 return GetCode(CALLBACKS, name);
2083}
2084
2085
2086Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
2087 String* name) {
2088 // ----------- S t a t e -------------
2089 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00002090 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002091 // -- r2 : name
2092 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002093 // -----------------------------------
2094 Label miss;
2095
Steve Blocka7e24c12009-10-30 11:49:00 +00002096 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00002097 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00002098 __ b(eq, &miss);
2099
2100 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00002101 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
2102 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00002103 __ b(ne, &miss);
2104
2105 // Perform global security token check if needed.
2106 if (receiver->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002107 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002108 }
2109
Andrei Popescu402d9372010-02-26 13:31:12 +00002110 // Stub is never generated for non-global objects that require access
Steve Blocka7e24c12009-10-30 11:49:00 +00002111 // checks.
2112 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2113
Steve Block6ded16b2010-05-10 14:33:55 +01002114 __ Push(r1, r2, r0); // Receiver, name, value.
Steve Blocka7e24c12009-10-30 11:49:00 +00002115
2116 // Do tail-call to the runtime system.
2117 ExternalReference store_ic_property =
2118 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01002119 __ TailCallExternalReference(store_ic_property, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002120
2121 // Handle store cache miss.
2122 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002123 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2124 __ Jump(ic, RelocInfo::CODE_TARGET);
2125
2126 // Return the generated code.
2127 return GetCode(INTERCEPTOR, name);
2128}
2129
2130
2131Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
2132 JSGlobalPropertyCell* cell,
2133 String* name) {
2134 // ----------- S t a t e -------------
2135 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00002136 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002137 // -- r2 : name
2138 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002139 // -----------------------------------
2140 Label miss;
2141
2142 // Check that the map of the global has not changed.
Steve Blocka7e24c12009-10-30 11:49:00 +00002143 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
2144 __ cmp(r3, Operand(Handle<Map>(object->map())));
2145 __ b(ne, &miss);
2146
2147 // Store the value in the cell.
2148 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
2149 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
2150
Andrei Popescu402d9372010-02-26 13:31:12 +00002151 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00002152 __ Ret();
2153
2154 // Handle store cache miss.
2155 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00002156 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00002157 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2158 __ Jump(ic, RelocInfo::CODE_TARGET);
2159
2160 // Return the generated code.
2161 return GetCode(NORMAL, name);
2162}
2163
2164
Steve Block6ded16b2010-05-10 14:33:55 +01002165Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
2166 JSObject* object,
2167 JSObject* last) {
2168 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002169 // -- r0 : receiver
Steve Block6ded16b2010-05-10 14:33:55 +01002170 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002171 // -----------------------------------
2172 Label miss;
2173
Steve Block6ded16b2010-05-10 14:33:55 +01002174 // Check that receiver is not a smi.
2175 __ tst(r0, Operand(kSmiTagMask));
2176 __ b(eq, &miss);
2177
2178 // Check the maps of the full prototype chain.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002179 CheckPrototypes(object, r0, last, r3, r1, r4, name, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01002180
2181 // If the last object in the prototype chain is a global object,
2182 // check that the global property cell is empty.
2183 if (last->IsGlobalObject()) {
2184 Object* cell = GenerateCheckPropertyCell(masm(),
2185 GlobalObject::cast(last),
2186 name,
2187 r1,
2188 &miss);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002189 if (cell->IsFailure()) {
2190 miss.Unuse();
2191 return cell;
2192 }
Steve Block6ded16b2010-05-10 14:33:55 +01002193 }
2194
2195 // Return undefined if maps of the full prototype chain are still the
2196 // same and no global property with this name contains a value.
2197 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
2198 __ Ret();
2199
2200 __ bind(&miss);
2201 GenerateLoadMiss(masm(), Code::LOAD_IC);
2202
2203 // Return the generated code.
2204 return GetCode(NONEXISTENT, Heap::empty_string());
2205}
2206
2207
Steve Blocka7e24c12009-10-30 11:49:00 +00002208Object* LoadStubCompiler::CompileLoadField(JSObject* object,
2209 JSObject* holder,
2210 int index,
2211 String* name) {
2212 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002213 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002214 // -- r2 : name
2215 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002216 // -----------------------------------
2217 Label miss;
2218
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002219 GenerateLoadField(object, holder, r0, r3, r1, r4, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002220 __ bind(&miss);
2221 GenerateLoadMiss(masm(), Code::LOAD_IC);
2222
2223 // Return the generated code.
2224 return GetCode(FIELD, name);
2225}
2226
2227
Leon Clarkee46be812010-01-19 14:06:41 +00002228Object* LoadStubCompiler::CompileLoadCallback(String* name,
2229 JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00002230 JSObject* holder,
Leon Clarkee46be812010-01-19 14:06:41 +00002231 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002232 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002233 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002234 // -- r2 : name
2235 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002236 // -----------------------------------
2237 Label miss;
2238
Leon Clarkee46be812010-01-19 14:06:41 +00002239 Failure* failure = Failure::InternalError();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002240 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1, r4,
Leon Clarkee46be812010-01-19 14:06:41 +00002241 callback, name, &miss, &failure);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002242 if (!success) {
2243 miss.Unuse();
2244 return failure;
2245 }
Leon Clarkee46be812010-01-19 14:06:41 +00002246
Steve Blocka7e24c12009-10-30 11:49:00 +00002247 __ bind(&miss);
2248 GenerateLoadMiss(masm(), Code::LOAD_IC);
2249
2250 // Return the generated code.
2251 return GetCode(CALLBACKS, name);
2252}
2253
2254
2255Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
2256 JSObject* holder,
2257 Object* value,
2258 String* name) {
2259 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002260 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002261 // -- r2 : name
2262 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002263 // -----------------------------------
2264 Label miss;
2265
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002266 GenerateLoadConstant(object, holder, r0, r3, r1, r4, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002267 __ bind(&miss);
2268 GenerateLoadMiss(masm(), Code::LOAD_IC);
2269
2270 // Return the generated code.
2271 return GetCode(CONSTANT_FUNCTION, name);
2272}
2273
2274
2275Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
2276 JSObject* holder,
2277 String* name) {
2278 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002279 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002280 // -- r2 : name
2281 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002282 // -----------------------------------
2283 Label miss;
2284
Steve Blocka7e24c12009-10-30 11:49:00 +00002285 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00002286 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00002287 GenerateLoadInterceptor(object,
2288 holder,
2289 &lookup,
2290 r0,
2291 r2,
2292 r3,
2293 r1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002294 r4,
Steve Blocka7e24c12009-10-30 11:49:00 +00002295 name,
2296 &miss);
2297 __ bind(&miss);
2298 GenerateLoadMiss(masm(), Code::LOAD_IC);
2299
2300 // Return the generated code.
2301 return GetCode(INTERCEPTOR, name);
2302}
2303
2304
2305Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
2306 GlobalObject* holder,
2307 JSGlobalPropertyCell* cell,
2308 String* name,
2309 bool is_dont_delete) {
2310 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01002311 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002312 // -- r2 : name
2313 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002314 // -----------------------------------
2315 Label miss;
2316
Steve Blocka7e24c12009-10-30 11:49:00 +00002317 // If the object is the holder then we know that it's a global
2318 // object which can only happen for contextual calls. In this case,
2319 // the receiver cannot be a smi.
2320 if (object != holder) {
Steve Block6ded16b2010-05-10 14:33:55 +01002321 __ tst(r0, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00002322 __ b(eq, &miss);
2323 }
2324
2325 // Check that the map of the global has not changed.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002326 CheckPrototypes(object, r0, holder, r3, r4, r1, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002327
2328 // Get the value from the cell.
2329 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
Steve Block6ded16b2010-05-10 14:33:55 +01002330 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00002331
2332 // Check for deleted property if property can actually be deleted.
2333 if (!is_dont_delete) {
2334 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
Steve Block6ded16b2010-05-10 14:33:55 +01002335 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00002336 __ b(eq, &miss);
2337 }
2338
Steve Block6ded16b2010-05-10 14:33:55 +01002339 __ mov(r0, r4);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002340 __ IncrementCounter(&Counters::named_load_global_stub, 1, r1, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00002341 __ Ret();
2342
2343 __ bind(&miss);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002344 __ IncrementCounter(&Counters::named_load_global_stub_miss, 1, r1, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00002345 GenerateLoadMiss(masm(), Code::LOAD_IC);
2346
2347 // Return the generated code.
2348 return GetCode(NORMAL, name);
2349}
2350
2351
2352Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
2353 JSObject* receiver,
2354 JSObject* holder,
2355 int index) {
2356 // ----------- S t a t e -------------
2357 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002358 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002359 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002360 // -----------------------------------
2361 Label miss;
2362
Steve Block6ded16b2010-05-10 14:33:55 +01002363 // Check the key is the cached one.
2364 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002365 __ b(ne, &miss);
2366
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002367 GenerateLoadField(receiver, holder, r1, r2, r3, r4, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002368 __ bind(&miss);
2369 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2370
2371 return GetCode(FIELD, name);
2372}
2373
2374
2375Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
2376 JSObject* receiver,
2377 JSObject* holder,
2378 AccessorInfo* callback) {
2379 // ----------- S t a t e -------------
2380 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002381 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002382 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002383 // -----------------------------------
2384 Label miss;
2385
Steve Block6ded16b2010-05-10 14:33:55 +01002386 // Check the key is the cached one.
2387 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002388 __ b(ne, &miss);
2389
Leon Clarkee46be812010-01-19 14:06:41 +00002390 Failure* failure = Failure::InternalError();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002391 bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3, r4,
Leon Clarkee46be812010-01-19 14:06:41 +00002392 callback, name, &miss, &failure);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002393 if (!success) {
2394 miss.Unuse();
2395 return failure;
2396 }
Leon Clarkee46be812010-01-19 14:06:41 +00002397
Steve Blocka7e24c12009-10-30 11:49:00 +00002398 __ bind(&miss);
2399 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2400
2401 return GetCode(CALLBACKS, name);
2402}
2403
2404
2405Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
2406 JSObject* receiver,
2407 JSObject* holder,
2408 Object* value) {
2409 // ----------- S t a t e -------------
2410 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002411 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002412 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002413 // -----------------------------------
2414 Label miss;
2415
Steve Block6ded16b2010-05-10 14:33:55 +01002416 // Check the key is the cached one.
2417 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002418 __ b(ne, &miss);
2419
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002420 GenerateLoadConstant(receiver, holder, r1, r2, r3, r4, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002421 __ bind(&miss);
2422 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2423
2424 // Return the generated code.
2425 return GetCode(CONSTANT_FUNCTION, name);
2426}
2427
2428
2429Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
2430 JSObject* holder,
2431 String* name) {
2432 // ----------- S t a t e -------------
2433 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002434 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002435 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002436 // -----------------------------------
2437 Label miss;
2438
Steve Block6ded16b2010-05-10 14:33:55 +01002439 // Check the key is the cached one.
2440 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002441 __ b(ne, &miss);
2442
2443 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00002444 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00002445 GenerateLoadInterceptor(receiver,
2446 holder,
2447 &lookup,
Steve Block6ded16b2010-05-10 14:33:55 +01002448 r1,
Steve Blocka7e24c12009-10-30 11:49:00 +00002449 r0,
2450 r2,
2451 r3,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002452 r4,
Steve Blocka7e24c12009-10-30 11:49:00 +00002453 name,
2454 &miss);
2455 __ bind(&miss);
2456 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2457
2458 return GetCode(INTERCEPTOR, name);
2459}
2460
2461
2462Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
2463 // ----------- S t a t e -------------
2464 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002465 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002466 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002467 // -----------------------------------
2468 Label miss;
2469
Steve Block6ded16b2010-05-10 14:33:55 +01002470 // Check the key is the cached one.
2471 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002472 __ b(ne, &miss);
2473
Steve Block6ded16b2010-05-10 14:33:55 +01002474 GenerateLoadArrayLength(masm(), r1, r2, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002475 __ bind(&miss);
2476 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2477
2478 return GetCode(CALLBACKS, name);
2479}
2480
2481
2482Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
2483 // ----------- S t a t e -------------
2484 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002485 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002486 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002487 // -----------------------------------
2488 Label miss;
2489 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
2490
Steve Block6ded16b2010-05-10 14:33:55 +01002491 // Check the key is the cached one.
2492 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002493 __ b(ne, &miss);
2494
Steve Block6ded16b2010-05-10 14:33:55 +01002495 GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00002496 __ bind(&miss);
2497 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
2498
2499 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2500
2501 return GetCode(CALLBACKS, name);
2502}
2503
2504
2505// TODO(1224671): implement the fast case.
2506Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
2507 // ----------- S t a t e -------------
2508 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01002509 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01002510 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002511 // -----------------------------------
2512 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2513
2514 return GetCode(CALLBACKS, name);
2515}
2516
2517
2518Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
2519 int index,
2520 Map* transition,
2521 String* name) {
2522 // ----------- S t a t e -------------
2523 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01002524 // -- r1 : key
2525 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00002526 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00002527 // -----------------------------------
2528 Label miss;
2529
Leon Clarkef7060e22010-06-03 12:02:55 +01002530 __ IncrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002531
2532 // Check that the name has not changed.
Leon Clarkef7060e22010-06-03 12:02:55 +01002533 __ cmp(r1, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002534 __ b(ne, &miss);
2535
Leon Clarkef7060e22010-06-03 12:02:55 +01002536 // r3 is used as scratch register. r1 and r2 keep their values if a jump to
2537 // the miss label is generated.
Steve Blocka7e24c12009-10-30 11:49:00 +00002538 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002539 object,
2540 index,
2541 transition,
Leon Clarkef7060e22010-06-03 12:02:55 +01002542 r2, r1, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00002543 &miss);
2544 __ bind(&miss);
2545
Leon Clarkef7060e22010-06-03 12:02:55 +01002546 __ DecrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002547 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
Leon Clarkef7060e22010-06-03 12:02:55 +01002548
Steve Blocka7e24c12009-10-30 11:49:00 +00002549 __ Jump(ic, RelocInfo::CODE_TARGET);
2550
2551 // Return the generated code.
2552 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2553}
2554
2555
2556Object* ConstructStubCompiler::CompileConstructStub(
2557 SharedFunctionInfo* shared) {
2558 // ----------- S t a t e -------------
2559 // -- r0 : argc
2560 // -- r1 : constructor
2561 // -- lr : return address
2562 // -- [sp] : last argument
2563 // -----------------------------------
2564 Label generic_stub_call;
2565
2566 // Use r7 for holding undefined which is used in several places below.
2567 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2568
2569#ifdef ENABLE_DEBUGGER_SUPPORT
2570 // Check to see whether there are any break points in the function code. If
2571 // there are jump to the generic constructor stub which calls the actual
2572 // code for the function thereby hitting the break points.
2573 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2574 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2575 __ cmp(r2, r7);
2576 __ b(ne, &generic_stub_call);
2577#endif
2578
2579 // Load the initial map and verify that it is in fact a map.
2580 // r1: constructor function
2581 // r7: undefined
2582 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2583 __ tst(r2, Operand(kSmiTagMask));
2584 __ b(eq, &generic_stub_call);
2585 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2586 __ b(ne, &generic_stub_call);
2587
2588#ifdef DEBUG
2589 // Cannot construct functions this way.
2590 // r0: argc
2591 // r1: constructor function
2592 // r2: initial map
2593 // r7: undefined
2594 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2595 __ Check(ne, "Function constructed by construct stub.");
2596#endif
2597
2598 // Now allocate the JSObject in new space.
2599 // r0: argc
2600 // r1: constructor function
2601 // r2: initial map
2602 // r7: undefined
2603 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
2604 __ AllocateInNewSpace(r3,
2605 r4,
2606 r5,
2607 r6,
2608 &generic_stub_call,
Kristian Monsen25f61362010-05-21 11:50:48 +01002609 SIZE_IN_WORDS);
Steve Blocka7e24c12009-10-30 11:49:00 +00002610
2611 // Allocated the JSObject, now initialize the fields. Map is set to initial
2612 // map and properties and elements are set to empty fixed array.
2613 // r0: argc
2614 // r1: constructor function
2615 // r2: initial map
2616 // r3: object size (in words)
2617 // r4: JSObject (not tagged)
2618 // r7: undefined
2619 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2620 __ mov(r5, r4);
2621 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2622 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2623 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2624 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2625 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2626 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2627
2628 // Calculate the location of the first argument. The stack contains only the
2629 // argc arguments.
2630 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2631
2632 // Fill all the in-object properties with undefined.
2633 // r0: argc
2634 // r1: first argument
2635 // r3: object size (in words)
2636 // r4: JSObject (not tagged)
2637 // r5: First in-object property of JSObject (not tagged)
2638 // r7: undefined
2639 // Fill the initialized properties with a constant value or a passed argument
2640 // depending on the this.x = ...; assignment in the function.
2641 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2642 if (shared->IsThisPropertyAssignmentArgument(i)) {
2643 Label not_passed, next;
2644 // Check if the argument assigned to the property is actually passed.
2645 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2646 __ cmp(r0, Operand(arg_number));
2647 __ b(le, &not_passed);
2648 // Argument passed - find it on the stack.
2649 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2650 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2651 __ b(&next);
2652 __ bind(&not_passed);
2653 // Set the property to undefined.
2654 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2655 __ bind(&next);
2656 } else {
2657 // Set the property to the constant value.
2658 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2659 __ mov(r2, Operand(constant));
2660 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2661 }
2662 }
2663
2664 // Fill the unused in-object property fields with undefined.
2665 for (int i = shared->this_property_assignments_count();
2666 i < shared->CalculateInObjectProperties();
2667 i++) {
2668 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2669 }
2670
2671 // r0: argc
2672 // r4: JSObject (not tagged)
2673 // Move argc to r1 and the JSObject to return to r0 and tag it.
2674 __ mov(r1, r0);
2675 __ mov(r0, r4);
2676 __ orr(r0, r0, Operand(kHeapObjectTag));
2677
2678 // r0: JSObject
2679 // r1: argc
2680 // Remove caller arguments and receiver from the stack and return.
2681 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2682 __ add(sp, sp, Operand(kPointerSize));
2683 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2684 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2685 __ Jump(lr);
2686
2687 // Jump to the generic stub in case the specialized code cannot handle the
2688 // construction.
2689 __ bind(&generic_stub_call);
2690 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2691 Handle<Code> generic_construct_stub(code);
2692 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2693
2694 // Return the generated code.
2695 return GetCode();
2696}
2697
2698
2699#undef __
2700
2701} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002702
2703#endif // V8_TARGET_ARCH_ARM