blob: d82ef21ce02399c44ed960e76af583c0548f4eac [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
86void StubCache::GenerateProbe(MacroAssembler* masm,
87 Code::Flags flags,
88 Register receiver,
89 Register name,
90 Register scratch,
91 Register extra) {
92 Label miss;
93
94 // Make sure that code is valid. The shifting code relies on the
95 // entry size being 8.
96 ASSERT(sizeof(Entry) == 8);
97
98 // Make sure the flags does not name a specific type.
99 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
100
101 // Make sure that there are no register conflicts.
102 ASSERT(!scratch.is(receiver));
103 ASSERT(!scratch.is(name));
104
105 // Check that the receiver isn't a smi.
106 __ tst(receiver, Operand(kSmiTagMask));
107 __ b(eq, &miss);
108
109 // Get the map of the receiver and compute the hash.
Steve Blockd0582a62009-12-15 09:54:21 +0000110 __ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000111 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
112 __ add(scratch, scratch, Operand(ip));
113 __ eor(scratch, scratch, Operand(flags));
114 __ and_(scratch,
115 scratch,
116 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
117
118 // Probe the primary table.
119 ProbeTable(masm, flags, kPrimary, name, scratch);
120
121 // Primary miss: Compute hash for secondary probe.
122 __ sub(scratch, scratch, Operand(name));
123 __ add(scratch, scratch, Operand(flags));
124 __ and_(scratch,
125 scratch,
126 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
127
128 // Probe the secondary table.
129 ProbeTable(masm, flags, kSecondary, name, scratch);
130
131 // Cache miss: Fall-through and let caller handle the miss by
132 // entering the runtime system.
133 __ bind(&miss);
134}
135
136
137void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
138 int index,
139 Register prototype) {
140 // Load the global or builtins object from the current context.
141 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
142 // Load the global context from the global or builtins object.
143 __ ldr(prototype,
144 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
145 // Load the function from the global context.
146 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
147 // Load the initial map. The global functions all have initial maps.
148 __ ldr(prototype,
149 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
150 // Load the prototype from the initial map.
151 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
152}
153
154
155// Load a fast property out of a holder object (src). In-object properties
156// are loaded directly otherwise the property is loaded from the properties
157// fixed array.
158void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
159 Register dst, Register src,
160 JSObject* holder, int index) {
161 // Adjust for the number of properties stored in the holder.
162 index -= holder->map()->inobject_properties();
163 if (index < 0) {
164 // Get the property straight out of the holder.
165 int offset = holder->map()->instance_size() + (index * kPointerSize);
166 __ ldr(dst, FieldMemOperand(src, offset));
167 } else {
168 // Calculate the offset into the properties array.
169 int offset = index * kPointerSize + FixedArray::kHeaderSize;
170 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
171 __ ldr(dst, FieldMemOperand(dst, offset));
172 }
173}
174
175
176void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
177 Register receiver,
178 Register scratch,
179 Label* miss_label) {
180 // Check that the receiver isn't a smi.
181 __ tst(receiver, Operand(kSmiTagMask));
182 __ b(eq, miss_label);
183
184 // Check that the object is a JS array.
185 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
186 __ b(ne, miss_label);
187
188 // Load length directly from the JS array.
189 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
190 __ Ret();
191}
192
193
Andrei Popescu402d9372010-02-26 13:31:12 +0000194// Generate code to check if an object is a string. If the object is a
195// heap object, its map's instance type is left in the scratch1 register.
196// If this is not needed, scratch1 and scratch2 may be the same register.
Steve Blocka7e24c12009-10-30 11:49:00 +0000197static void GenerateStringCheck(MacroAssembler* masm,
198 Register receiver,
199 Register scratch1,
200 Register scratch2,
201 Label* smi,
202 Label* non_string_object) {
203 // Check that the receiver isn't a smi.
204 __ tst(receiver, Operand(kSmiTagMask));
205 __ b(eq, smi);
206
207 // Check that the object is a string.
208 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
209 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
210 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
211 // The cast is to resolve the overload for the argument of 0x0.
212 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
213 __ b(ne, non_string_object);
214}
215
216
217// Generate code to load the length from a string object and return the length.
218// If the receiver object is not a string or a wrapped string object the
219// execution continues at the miss label. The register containing the
220// receiver is potentially clobbered.
Andrei Popescu402d9372010-02-26 13:31:12 +0000221void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
222 Register receiver,
223 Register scratch1,
224 Register scratch2,
225 Label* miss) {
226 Label check_wrapper;
Steve Blocka7e24c12009-10-30 11:49:00 +0000227
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 // Check if the object is a string leaving the instance type in the
229 // scratch1 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000230 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
Steve Blocka7e24c12009-10-30 11:49:00 +0000231
232 // Load length directly from the string.
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000234 __ Ret();
235
236 // Check if the object is a JSValue wrapper.
237 __ bind(&check_wrapper);
238 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
239 __ b(ne, miss);
240
Andrei Popescu402d9372010-02-26 13:31:12 +0000241 // Unwrap the value and check if the wrapped value is a string.
242 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
243 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
244 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
Andrei Popescu402d9372010-02-26 13:31:12 +0000245 __ Ret();
Steve Blocka7e24c12009-10-30 11:49:00 +0000246}
247
248
249void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
250 Register receiver,
251 Register scratch1,
252 Register scratch2,
253 Label* miss_label) {
254 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
255 __ mov(r0, scratch1);
256 __ Ret();
257}
258
259
260// Generate StoreField code, value is passed in r0 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000261// When leaving generated code after success, the receiver_reg and name_reg
262// may be clobbered. Upon branch to miss_label, the receiver and name
263// registers have their original values.
Steve Blocka7e24c12009-10-30 11:49:00 +0000264void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Steve Blocka7e24c12009-10-30 11:49:00 +0000265 JSObject* object,
266 int index,
267 Map* transition,
268 Register receiver_reg,
269 Register name_reg,
270 Register scratch,
271 Label* miss_label) {
272 // r0 : value
273 Label exit;
274
275 // Check that the receiver isn't a smi.
276 __ tst(receiver_reg, Operand(kSmiTagMask));
277 __ b(eq, miss_label);
278
279 // Check that the map of the receiver hasn't changed.
280 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
281 __ cmp(scratch, Operand(Handle<Map>(object->map())));
282 __ b(ne, miss_label);
283
284 // Perform global security token check if needed.
285 if (object->IsJSGlobalProxy()) {
286 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
287 }
288
289 // Stub never generated for non-global objects that require access
290 // checks.
291 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
292
293 // Perform map transition for the receiver if necessary.
294 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
295 // The properties must be extended before we can store the value.
296 // We jump to a runtime call that extends the properties array.
Andrei Popescu402d9372010-02-26 13:31:12 +0000297 __ push(receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000298 __ mov(r2, Operand(Handle<Map>(transition)));
Steve Block6ded16b2010-05-10 14:33:55 +0100299 __ Push(r2, r0);
300 __ TailCallExternalReference(
Andrei Popescu402d9372010-02-26 13:31:12 +0000301 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)),
302 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000303 return;
304 }
305
306 if (transition != NULL) {
307 // Update the map of the object; no write barrier updating is
308 // needed because the map is never in new space.
309 __ mov(ip, Operand(Handle<Map>(transition)));
310 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
311 }
312
313 // Adjust for the number of properties stored in the object. Even in the
314 // face of a transition we can use the old map here because the size of the
315 // object and the number of in-object properties is not going to change.
316 index -= object->map()->inobject_properties();
317
318 if (index < 0) {
319 // Set the property straight into the object.
320 int offset = object->map()->instance_size() + (index * kPointerSize);
321 __ str(r0, FieldMemOperand(receiver_reg, offset));
322
323 // Skip updating write barrier if storing a smi.
324 __ tst(r0, Operand(kSmiTagMask));
325 __ b(eq, &exit);
326
327 // Update the write barrier for the array address.
328 // Pass the value being stored in the now unused name_reg.
329 __ mov(name_reg, Operand(offset));
330 __ RecordWrite(receiver_reg, name_reg, scratch);
331 } else {
332 // Write to the properties array.
333 int offset = index * kPointerSize + FixedArray::kHeaderSize;
334 // Get the properties array
335 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
336 __ str(r0, FieldMemOperand(scratch, offset));
337
338 // Skip updating write barrier if storing a smi.
339 __ tst(r0, Operand(kSmiTagMask));
340 __ b(eq, &exit);
341
342 // Update the write barrier for the array address.
343 // Ok to clobber receiver_reg and name_reg, since we return.
344 __ mov(name_reg, Operand(offset));
345 __ RecordWrite(scratch, name_reg, receiver_reg);
346 }
347
348 // Return the value (register r0).
349 __ bind(&exit);
350 __ Ret();
351}
352
353
354void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
355 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
356 Code* code = NULL;
357 if (kind == Code::LOAD_IC) {
358 code = Builtins::builtin(Builtins::LoadIC_Miss);
359 } else {
360 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
361 }
362
363 Handle<Code> ic(code);
364 __ Jump(ic, RelocInfo::CODE_TARGET);
365}
366
367
Leon Clarke4515c472010-02-03 11:58:03 +0000368static void GenerateCallFunction(MacroAssembler* masm,
369 Object* object,
370 const ParameterCount& arguments,
371 Label* miss) {
372 // ----------- S t a t e -------------
373 // -- r0: receiver
374 // -- r1: function to call
375 // -----------------------------------
376
377 // Check that the function really is a function.
378 __ BranchOnSmi(r1, miss);
Andrei Popescu402d9372010-02-26 13:31:12 +0000379 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
Leon Clarke4515c472010-02-03 11:58:03 +0000380 __ b(ne, miss);
381
382 // Patch the receiver on the stack with the global proxy if
383 // necessary.
384 if (object->IsGlobalObject()) {
385 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
386 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
387 }
388
389 // Invoke the function.
390 __ InvokeFunction(r1, arguments, JUMP_FUNCTION);
391}
392
393
Leon Clarke4515c472010-02-03 11:58:03 +0000394static void PushInterceptorArguments(MacroAssembler* masm,
395 Register receiver,
396 Register holder,
397 Register name,
398 JSObject* holder_obj) {
Leon Clarke4515c472010-02-03 11:58:03 +0000399 __ push(name);
400 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
401 ASSERT(!Heap::InNewSpace(interceptor));
Steve Block6ded16b2010-05-10 14:33:55 +0100402 Register scratch = name;
Leon Clarke4515c472010-02-03 11:58:03 +0000403 __ mov(scratch, Operand(Handle<Object>(interceptor)));
404 __ push(scratch);
Steve Block6ded16b2010-05-10 14:33:55 +0100405 __ push(receiver);
406 __ push(holder);
Leon Clarke4515c472010-02-03 11:58:03 +0000407 __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
408 __ push(scratch);
409}
410
411
412static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
413 Register receiver,
414 Register holder,
415 Register name,
416 JSObject* holder_obj) {
417 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
418
419 ExternalReference ref =
420 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
421 __ mov(r0, Operand(5));
422 __ mov(r1, Operand(ref));
423
424 CEntryStub stub(1);
425 __ CallStub(&stub);
426}
427
428
429class LoadInterceptorCompiler BASE_EMBEDDED {
430 public:
431 explicit LoadInterceptorCompiler(Register name) : name_(name) {}
432
433 void CompileCacheable(MacroAssembler* masm,
434 StubCompiler* stub_compiler,
435 Register receiver,
436 Register holder,
437 Register scratch1,
438 Register scratch2,
Leon Clarkef7060e22010-06-03 12:02:55 +0100439 JSObject* interceptor_holder,
Leon Clarke4515c472010-02-03 11:58:03 +0000440 LookupResult* lookup,
441 String* name,
442 Label* miss_label) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000443 AccessorInfo* callback = NULL;
Leon Clarke4515c472010-02-03 11:58:03 +0000444 bool optimize = false;
445 // So far the most popular follow ups for interceptor loads are FIELD
446 // and CALLBACKS, so inline only them, other cases may be added
447 // later.
448 if (lookup->type() == FIELD) {
449 optimize = true;
450 } else if (lookup->type() == CALLBACKS) {
451 Object* callback_object = lookup->GetCallbackObject();
452 if (callback_object->IsAccessorInfo()) {
453 callback = AccessorInfo::cast(callback_object);
454 optimize = callback->getter() != NULL;
455 }
456 }
457
458 if (!optimize) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100459 CompileRegular(masm, receiver, holder, scratch2, interceptor_holder,
460 miss_label);
Leon Clarke4515c472010-02-03 11:58:03 +0000461 return;
462 }
463
464 // Note: starting a frame here makes GC aware of pointers pushed below.
465 __ EnterInternalFrame();
466
Andrei Popescu402d9372010-02-26 13:31:12 +0000467 __ push(receiver);
Steve Block6ded16b2010-05-10 14:33:55 +0100468 __ Push(holder, name_);
Leon Clarke4515c472010-02-03 11:58:03 +0000469
Leon Clarkef7060e22010-06-03 12:02:55 +0100470 // Invoke an interceptor. Note: map checks from receiver to
471 // interceptor's holder has been compiled before (see a caller
472 // of this method.)
Leon Clarke4515c472010-02-03 11:58:03 +0000473 CompileCallLoadPropertyWithInterceptor(masm,
474 receiver,
475 holder,
476 name_,
Leon Clarkef7060e22010-06-03 12:02:55 +0100477 interceptor_holder);
Leon Clarke4515c472010-02-03 11:58:03 +0000478
Leon Clarkef7060e22010-06-03 12:02:55 +0100479 // Check if interceptor provided a value for property. If it's
480 // the case, return immediately.
Leon Clarke4515c472010-02-03 11:58:03 +0000481 Label interceptor_failed;
Leon Clarke4515c472010-02-03 11:58:03 +0000482 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
483 __ cmp(r0, scratch1);
484 __ b(eq, &interceptor_failed);
485 __ LeaveInternalFrame();
486 __ Ret();
487
488 __ bind(&interceptor_failed);
489 __ pop(name_);
490 __ pop(holder);
Andrei Popescu402d9372010-02-26 13:31:12 +0000491 __ pop(receiver);
Leon Clarke4515c472010-02-03 11:58:03 +0000492
493 __ LeaveInternalFrame();
494
495 if (lookup->type() == FIELD) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100496 // We found FIELD property in prototype chain of interceptor's holder.
497 // Check that the maps from interceptor's holder to field's holder
498 // haven't changed...
499 holder = stub_compiler->CheckPrototypes(interceptor_holder,
Leon Clarke4515c472010-02-03 11:58:03 +0000500 holder,
501 lookup->holder(),
502 scratch1,
503 scratch2,
504 name,
505 miss_label);
Leon Clarkef7060e22010-06-03 12:02:55 +0100506 // ... and retrieve a field from field's holder.
Leon Clarke4515c472010-02-03 11:58:03 +0000507 stub_compiler->GenerateFastPropertyLoad(masm,
508 r0,
509 holder,
510 lookup->holder(),
511 lookup->GetFieldIndex());
512 __ Ret();
513 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +0100514 // We found CALLBACKS property in prototype chain of interceptor's
515 // holder.
Leon Clarke4515c472010-02-03 11:58:03 +0000516 ASSERT(lookup->type() == CALLBACKS);
517 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
518 ASSERT(callback != NULL);
519 ASSERT(callback->getter() != NULL);
520
Leon Clarkef7060e22010-06-03 12:02:55 +0100521 // Prepare for tail call: push receiver to stack.
Leon Clarke4515c472010-02-03 11:58:03 +0000522 Label cleanup;
Leon Clarkef7060e22010-06-03 12:02:55 +0100523 __ push(receiver);
Leon Clarke4515c472010-02-03 11:58:03 +0000524
Leon Clarkef7060e22010-06-03 12:02:55 +0100525 // Check that the maps from interceptor's holder to callback's holder
526 // haven't changed.
527 holder = stub_compiler->CheckPrototypes(interceptor_holder, holder,
Leon Clarke4515c472010-02-03 11:58:03 +0000528 lookup->holder(), scratch1,
529 scratch2,
530 name,
531 &cleanup);
532
Leon Clarkef7060e22010-06-03 12:02:55 +0100533 // Continue tail call preparation: push remaining parameters.
Leon Clarke4515c472010-02-03 11:58:03 +0000534 __ push(holder);
535 __ Move(holder, Handle<AccessorInfo>(callback));
536 __ push(holder);
537 __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset));
Steve Block6ded16b2010-05-10 14:33:55 +0100538 __ Push(scratch1, name_);
Leon Clarke4515c472010-02-03 11:58:03 +0000539
Leon Clarkef7060e22010-06-03 12:02:55 +0100540 // Tail call to runtime.
Leon Clarke4515c472010-02-03 11:58:03 +0000541 ExternalReference ref =
542 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +0100543 __ TailCallExternalReference(ref, 5, 1);
Leon Clarke4515c472010-02-03 11:58:03 +0000544
Leon Clarkef7060e22010-06-03 12:02:55 +0100545 // Clean up code: we pushed receiver and need to remove it.
Leon Clarke4515c472010-02-03 11:58:03 +0000546 __ bind(&cleanup);
Leon Clarke4515c472010-02-03 11:58:03 +0000547 __ pop(scratch2);
Leon Clarke4515c472010-02-03 11:58:03 +0000548 }
549 }
550
551
552 void CompileRegular(MacroAssembler* masm,
553 Register receiver,
554 Register holder,
555 Register scratch,
Leon Clarkef7060e22010-06-03 12:02:55 +0100556 JSObject* interceptor_holder,
Leon Clarke4515c472010-02-03 11:58:03 +0000557 Label* miss_label) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100558 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
Leon Clarke4515c472010-02-03 11:58:03 +0000559
560 ExternalReference ref = ExternalReference(
561 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
Steve Block6ded16b2010-05-10 14:33:55 +0100562 __ TailCallExternalReference(ref, 5, 1);
Leon Clarke4515c472010-02-03 11:58:03 +0000563 }
564
565 private:
566 Register name_;
567};
568
569
Andrei Popescu402d9372010-02-26 13:31:12 +0000570static void CompileLoadInterceptor(LoadInterceptorCompiler* compiler,
571 StubCompiler* stub_compiler,
572 MacroAssembler* masm,
573 JSObject* object,
574 JSObject* holder,
575 String* name,
576 LookupResult* lookup,
577 Register receiver,
578 Register scratch1,
579 Register scratch2,
580 Label* miss) {
581 ASSERT(holder->HasNamedInterceptor());
582 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
Leon Clarke4515c472010-02-03 11:58:03 +0000583
Andrei Popescu402d9372010-02-26 13:31:12 +0000584 // Check that the receiver isn't a smi.
585 __ BranchOnSmi(receiver, miss);
Leon Clarke4515c472010-02-03 11:58:03 +0000586
Andrei Popescu402d9372010-02-26 13:31:12 +0000587 // Check that the maps haven't changed.
588 Register reg =
589 stub_compiler->CheckPrototypes(object, receiver, holder,
590 scratch1, scratch2, name, miss);
Leon Clarke4515c472010-02-03 11:58:03 +0000591
Andrei Popescu402d9372010-02-26 13:31:12 +0000592 if (lookup->IsProperty() && lookup->IsCacheable()) {
593 compiler->CompileCacheable(masm,
594 stub_compiler,
595 receiver,
596 reg,
597 scratch1,
598 scratch2,
599 holder,
600 lookup,
601 name,
602 miss);
603 } else {
604 compiler->CompileRegular(masm,
Leon Clarke4515c472010-02-03 11:58:03 +0000605 receiver,
Andrei Popescu402d9372010-02-26 13:31:12 +0000606 reg,
607 scratch2,
Leon Clarke4515c472010-02-03 11:58:03 +0000608 holder,
Andrei Popescu402d9372010-02-26 13:31:12 +0000609 miss);
Leon Clarke4515c472010-02-03 11:58:03 +0000610 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000611}
Leon Clarke4515c472010-02-03 11:58:03 +0000612
613
Steve Block6ded16b2010-05-10 14:33:55 +0100614// Reserves space for the extra arguments to FastHandleApiCall in the
615// caller's frame.
616//
617// These arguments are set by CheckPrototypes and GenerateFastApiCall.
618static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
619 Register scratch) {
620 __ mov(scratch, Operand(Smi::FromInt(0)));
621 __ push(scratch);
622 __ push(scratch);
623 __ push(scratch);
624 __ push(scratch);
625}
626
627
628// Undoes the effects of ReserveSpaceForFastApiCall.
629static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
630 __ Drop(4);
631}
632
633
634// Generates call to FastHandleApiCall builtin.
635static void GenerateFastApiCall(MacroAssembler* masm,
636 const CallOptimization& optimization,
637 int argc) {
638 // Get the function and setup the context.
639 JSFunction* function = optimization.constant_function();
640 __ mov(r7, Operand(Handle<JSFunction>(function)));
641 __ ldr(cp, FieldMemOperand(r7, JSFunction::kContextOffset));
642
643 // Pass the additional arguments FastHandleApiCall expects.
644 bool info_loaded = false;
645 Object* callback = optimization.api_call_info()->callback();
646 if (Heap::InNewSpace(callback)) {
647 info_loaded = true;
648 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
649 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
650 } else {
651 __ Move(r6, Handle<Object>(callback));
652 }
653 Object* call_data = optimization.api_call_info()->data();
654 if (Heap::InNewSpace(call_data)) {
655 if (!info_loaded) {
656 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
657 }
658 __ ldr(r5, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
659 } else {
660 __ Move(r5, Handle<Object>(call_data));
661 }
662
663 __ add(sp, sp, Operand(1 * kPointerSize));
664 __ stm(ia, sp, r5.bit() | r6.bit() | r7.bit());
665 __ sub(sp, sp, Operand(1 * kPointerSize));
666
667 // Set the number of arguments.
668 __ mov(r0, Operand(argc + 4));
669
670 // Jump to the fast api call builtin (tail call).
671 Handle<Code> code = Handle<Code>(
672 Builtins::builtin(Builtins::FastHandleApiCall));
673 ParameterCount expected(0);
674 __ InvokeCode(code, expected, expected,
675 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
676}
677
678
679class CallInterceptorCompiler BASE_EMBEDDED {
680 public:
681 CallInterceptorCompiler(StubCompiler* stub_compiler,
682 const ParameterCount& arguments,
683 Register name)
684 : stub_compiler_(stub_compiler),
685 arguments_(arguments),
686 name_(name) {}
687
688 void Compile(MacroAssembler* masm,
689 JSObject* object,
690 JSObject* holder,
691 String* name,
692 LookupResult* lookup,
693 Register receiver,
694 Register scratch1,
695 Register scratch2,
696 Label* miss) {
697 ASSERT(holder->HasNamedInterceptor());
698 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
699
700 // Check that the receiver isn't a smi.
701 __ BranchOnSmi(receiver, miss);
702
703 CallOptimization optimization(lookup);
704
705 if (optimization.is_constant_call()) {
706 CompileCacheable(masm,
707 object,
708 receiver,
709 scratch1,
710 scratch2,
711 holder,
712 lookup,
713 name,
714 optimization,
715 miss);
716 } else {
717 CompileRegular(masm,
718 object,
719 receiver,
720 scratch1,
721 scratch2,
722 name,
723 holder,
724 miss);
725 }
726 }
727
728 private:
729 void CompileCacheable(MacroAssembler* masm,
730 JSObject* object,
731 Register receiver,
732 Register scratch1,
733 Register scratch2,
Leon Clarkef7060e22010-06-03 12:02:55 +0100734 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100735 LookupResult* lookup,
736 String* name,
737 const CallOptimization& optimization,
738 Label* miss_label) {
739 ASSERT(optimization.is_constant_call());
740 ASSERT(!lookup->holder()->IsGlobalObject());
741
742 int depth1 = kInvalidProtoDepth;
743 int depth2 = kInvalidProtoDepth;
744 bool can_do_fast_api_call = false;
745 if (optimization.is_simple_api_call() &&
746 !lookup->holder()->IsGlobalObject()) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100747 depth1 =
748 optimization.GetPrototypeDepthOfExpectedType(object,
749 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100750 if (depth1 == kInvalidProtoDepth) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100751 depth2 =
752 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
753 lookup->holder());
Steve Block6ded16b2010-05-10 14:33:55 +0100754 }
755 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
756 (depth2 != kInvalidProtoDepth);
757 }
758
759 __ IncrementCounter(&Counters::call_const_interceptor, 1,
760 scratch1, scratch2);
761
762 if (can_do_fast_api_call) {
763 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1,
764 scratch1, scratch2);
765 ReserveSpaceForFastApiCall(masm, scratch1);
766 }
767
Leon Clarkef7060e22010-06-03 12:02:55 +0100768 // Check that the maps from receiver to interceptor's holder
769 // haven't changed and thus we can invoke interceptor.
Steve Block6ded16b2010-05-10 14:33:55 +0100770 Label miss_cleanup;
771 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
772 Register holder =
Leon Clarkef7060e22010-06-03 12:02:55 +0100773 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
774 scratch1, scratch2, name,
775 depth1, miss);
Steve Block6ded16b2010-05-10 14:33:55 +0100776
Leon Clarkef7060e22010-06-03 12:02:55 +0100777 // Invoke an interceptor and if it provides a value,
778 // branch to |regular_invoke|.
Steve Block6ded16b2010-05-10 14:33:55 +0100779 Label regular_invoke;
Leon Clarkef7060e22010-06-03 12:02:55 +0100780 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
Steve Block6ded16b2010-05-10 14:33:55 +0100781 &regular_invoke);
782
Leon Clarkef7060e22010-06-03 12:02:55 +0100783 // Interceptor returned nothing for this property. Try to use cached
784 // constant function.
Steve Block6ded16b2010-05-10 14:33:55 +0100785
Leon Clarkef7060e22010-06-03 12:02:55 +0100786 // Check that the maps from interceptor's holder to constant function's
787 // holder haven't changed and thus we can use cached constant function.
788 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
Steve Block6ded16b2010-05-10 14:33:55 +0100789 lookup->holder(), scratch1,
790 scratch2, name, depth2, miss);
791
Leon Clarkef7060e22010-06-03 12:02:55 +0100792 // Invoke function.
Steve Block6ded16b2010-05-10 14:33:55 +0100793 if (can_do_fast_api_call) {
794 GenerateFastApiCall(masm, optimization, arguments_.immediate());
795 } else {
796 __ InvokeFunction(optimization.constant_function(), arguments_,
797 JUMP_FUNCTION);
798 }
799
Leon Clarkef7060e22010-06-03 12:02:55 +0100800 // Deferred code for fast API call case---clean preallocated space.
Steve Block6ded16b2010-05-10 14:33:55 +0100801 if (can_do_fast_api_call) {
802 __ bind(&miss_cleanup);
803 FreeSpaceForFastApiCall(masm);
804 __ b(miss_label);
805 }
806
Leon Clarkef7060e22010-06-03 12:02:55 +0100807 // Invoke a regular function.
Steve Block6ded16b2010-05-10 14:33:55 +0100808 __ bind(&regular_invoke);
809 if (can_do_fast_api_call) {
810 FreeSpaceForFastApiCall(masm);
811 }
812 }
813
814 void CompileRegular(MacroAssembler* masm,
815 JSObject* object,
816 Register receiver,
817 Register scratch1,
818 Register scratch2,
819 String* name,
Leon Clarkef7060e22010-06-03 12:02:55 +0100820 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100821 Label* miss_label) {
822 Register holder =
Leon Clarkef7060e22010-06-03 12:02:55 +0100823 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100824 scratch1, scratch2, name,
825 miss_label);
826
827 // Call a runtime function to load the interceptor property.
828 __ EnterInternalFrame();
829 // Save the name_ register across the call.
830 __ push(name_);
831
832 PushInterceptorArguments(masm,
833 receiver,
834 holder,
835 name_,
Leon Clarkef7060e22010-06-03 12:02:55 +0100836 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100837
838 __ CallExternalReference(
839 ExternalReference(
840 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
841 5);
842
843 // Restore the name_ register.
844 __ pop(name_);
845 __ LeaveInternalFrame();
846 }
847
848 void LoadWithInterceptor(MacroAssembler* masm,
849 Register receiver,
850 Register holder,
851 JSObject* holder_obj,
852 Register scratch,
853 Label* interceptor_succeeded) {
854 __ EnterInternalFrame();
855 __ Push(holder, name_);
856
857 CompileCallLoadPropertyWithInterceptor(masm,
858 receiver,
859 holder,
860 name_,
861 holder_obj);
862
863 __ pop(name_); // Restore the name.
864 __ pop(receiver); // Restore the holder.
865 __ LeaveInternalFrame();
866
867 // If interceptor returns no-result sentinel, call the constant function.
868 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
869 __ cmp(r0, scratch);
870 __ b(ne, interceptor_succeeded);
871 }
872
873 StubCompiler* stub_compiler_;
874 const ParameterCount& arguments_;
875 Register name_;
876};
877
878
879// Generate code to check that a global property cell is empty. Create
880// the property cell at compilation time if no cell exists for the
881// property.
882static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
883 GlobalObject* global,
884 String* name,
885 Register scratch,
886 Label* miss) {
887 Object* probe = global->EnsurePropertyCell(name);
888 if (probe->IsFailure()) return probe;
889 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
890 ASSERT(cell->value()->IsTheHole());
891 __ mov(scratch, Operand(Handle<Object>(cell)));
892 __ ldr(scratch,
893 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
894 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
895 __ cmp(scratch, ip);
896 __ b(ne, miss);
897 return cell;
898}
899
900
Steve Blocka7e24c12009-10-30 11:49:00 +0000901#undef __
902#define __ ACCESS_MASM(masm())
903
904
905Register StubCompiler::CheckPrototypes(JSObject* object,
906 Register object_reg,
907 JSObject* holder,
908 Register holder_reg,
909 Register scratch,
910 String* name,
Andrei Popescu402d9372010-02-26 13:31:12 +0000911 int save_at_depth,
Steve Blocka7e24c12009-10-30 11:49:00 +0000912 Label* miss) {
913 // Check that the maps haven't changed.
914 Register result =
Steve Block6ded16b2010-05-10 14:33:55 +0100915 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch,
916 save_at_depth, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000917
918 // If we've skipped any global objects, it's not enough to verify
Steve Block6ded16b2010-05-10 14:33:55 +0100919 // that their maps haven't changed. We also need to check that the
920 // property cell for the property is still empty.
Steve Blocka7e24c12009-10-30 11:49:00 +0000921 while (object != holder) {
922 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100923 Object* cell = GenerateCheckPropertyCell(masm(),
924 GlobalObject::cast(object),
925 name,
926 scratch,
927 miss);
928 if (cell->IsFailure()) {
929 set_failure(Failure::cast(cell));
Steve Blocka7e24c12009-10-30 11:49:00 +0000930 return result;
931 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000932 }
933 object = JSObject::cast(object->GetPrototype());
934 }
935
Andrei Popescu402d9372010-02-26 13:31:12 +0000936 // Return the register containing the holder.
Steve Blocka7e24c12009-10-30 11:49:00 +0000937 return result;
938}
939
940
941void StubCompiler::GenerateLoadField(JSObject* object,
942 JSObject* holder,
943 Register receiver,
944 Register scratch1,
945 Register scratch2,
946 int index,
947 String* name,
948 Label* miss) {
949 // Check that the receiver isn't a smi.
950 __ tst(receiver, Operand(kSmiTagMask));
951 __ b(eq, miss);
952
953 // Check that the maps haven't changed.
954 Register reg =
955 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
956 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
957 __ Ret();
958}
959
960
961void StubCompiler::GenerateLoadConstant(JSObject* object,
962 JSObject* holder,
963 Register receiver,
964 Register scratch1,
965 Register scratch2,
966 Object* value,
967 String* name,
968 Label* miss) {
969 // Check that the receiver isn't a smi.
970 __ tst(receiver, Operand(kSmiTagMask));
971 __ b(eq, miss);
972
973 // Check that the maps haven't changed.
974 Register reg =
975 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
976
977 // Return the constant value.
978 __ mov(r0, Operand(Handle<Object>(value)));
979 __ Ret();
980}
981
982
Leon Clarkee46be812010-01-19 14:06:41 +0000983bool StubCompiler::GenerateLoadCallback(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +0000984 JSObject* holder,
985 Register receiver,
986 Register name_reg,
987 Register scratch1,
988 Register scratch2,
989 AccessorInfo* callback,
990 String* name,
Leon Clarkee46be812010-01-19 14:06:41 +0000991 Label* miss,
992 Failure** failure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000993 // Check that the receiver isn't a smi.
994 __ tst(receiver, Operand(kSmiTagMask));
995 __ b(eq, miss);
996
997 // Check that the maps haven't changed.
998 Register reg =
999 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
1000
1001 // Push the arguments on the JS stack of the caller.
Steve Block6ded16b2010-05-10 14:33:55 +01001002 __ push(receiver); // Receiver.
1003 __ push(reg); // Holder.
Steve Blocka7e24c12009-10-30 11:49:00 +00001004 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
Steve Blocka7e24c12009-10-30 11:49:00 +00001005 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
Steve Block6ded16b2010-05-10 14:33:55 +01001006 __ Push(ip, reg, name_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +00001007
1008 // Do tail-call to the runtime system.
1009 ExternalReference load_callback_property =
1010 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001011 __ TailCallExternalReference(load_callback_property, 5, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00001012
1013 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001014}
1015
1016
1017void StubCompiler::GenerateLoadInterceptor(JSObject* object,
1018 JSObject* holder,
1019 LookupResult* lookup,
1020 Register receiver,
1021 Register name_reg,
1022 Register scratch1,
1023 Register scratch2,
1024 String* name,
1025 Label* miss) {
Leon Clarke4515c472010-02-03 11:58:03 +00001026 LoadInterceptorCompiler compiler(name_reg);
1027 CompileLoadInterceptor(&compiler,
1028 this,
1029 masm(),
1030 object,
1031 holder,
1032 name,
1033 lookup,
1034 receiver,
1035 scratch1,
1036 scratch2,
1037 miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001038}
1039
1040
1041Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
1042 // ----------- S t a t e -------------
1043 // -- r1: function
1044 // -- lr: return address
1045 // -----------------------------------
1046
1047 // Enter an internal frame.
1048 __ EnterInternalFrame();
1049
1050 // Preserve the function.
1051 __ push(r1);
1052
1053 // Push the function on the stack as the argument to the runtime function.
1054 __ push(r1);
1055 __ CallRuntime(Runtime::kLazyCompile, 1);
1056
1057 // Calculate the entry point.
1058 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
1059
1060 // Restore saved function.
1061 __ pop(r1);
1062
1063 // Tear down temporary frame.
1064 __ LeaveInternalFrame();
1065
1066 // Do a tail-call of the compiled function.
1067 __ Jump(r2);
1068
1069 return GetCodeWithFlags(flags, "LazyCompileStub");
1070}
1071
1072
Andrei Popescu402d9372010-02-26 13:31:12 +00001073Object* CallStubCompiler::CompileCallField(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001074 JSObject* holder,
1075 int index,
1076 String* name) {
1077 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001078 // -- r2 : name
1079 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 // -----------------------------------
1081 Label miss;
1082
1083 const int argc = arguments().immediate();
1084
1085 // Get the receiver of the function from the stack into r0.
1086 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1087 // Check that the receiver isn't a smi.
1088 __ tst(r0, Operand(kSmiTagMask));
1089 __ b(eq, &miss);
1090
1091 // Do the right check and compute the holder register.
Andrei Popescu402d9372010-02-26 13:31:12 +00001092 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001093 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
1094
Leon Clarke4515c472010-02-03 11:58:03 +00001095 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001096
1097 // Handle call cache miss.
1098 __ bind(&miss);
1099 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1100 __ Jump(ic, RelocInfo::CODE_TARGET);
1101
1102 // Return the generated code.
1103 return GetCode(FIELD, name);
1104}
1105
1106
Steve Block6ded16b2010-05-10 14:33:55 +01001107Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1108 JSObject* holder,
1109 JSFunction* function,
1110 String* name,
1111 CheckType check) {
1112 // ----------- S t a t e -------------
1113 // -- r2 : name
1114 // -- lr : return address
1115 // -----------------------------------
1116
1117 // If object is not an array, bail out to regular call.
1118 if (!object->IsJSArray()) {
1119 return Heap::undefined_value();
1120 }
1121
1122 // TODO(639): faster implementation.
1123 ASSERT(check == RECEIVER_MAP_CHECK);
1124
1125 Label miss;
1126
1127 // Get the receiver from the stack
1128 const int argc = arguments().immediate();
1129 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1130
1131 // Check that the receiver isn't a smi.
1132 __ tst(r1, Operand(kSmiTagMask));
1133 __ b(eq, &miss);
1134
1135 // Check that the maps haven't changed.
1136 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1137
1138 if (object->IsGlobalObject()) {
1139 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1140 __ str(r3, MemOperand(sp, argc * kPointerSize));
1141 }
1142
1143 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1144 argc + 1,
1145 1);
1146
1147 // Handle call cache miss.
1148 __ bind(&miss);
1149 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1150 __ Jump(ic, RelocInfo::CODE_TARGET);
1151
1152 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001153 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001154}
1155
1156
1157Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1158 JSObject* holder,
1159 JSFunction* function,
1160 String* name,
1161 CheckType check) {
1162 // ----------- S t a t e -------------
1163 // -- r2 : name
1164 // -- lr : return address
1165 // -----------------------------------
1166
1167 // If object is not an array, bail out to regular call.
1168 if (!object->IsJSArray()) {
1169 return Heap::undefined_value();
1170 }
1171
1172 // TODO(642): faster implementation.
1173 ASSERT(check == RECEIVER_MAP_CHECK);
1174
1175 Label miss;
1176
1177 // Get the receiver from the stack
1178 const int argc = arguments().immediate();
1179 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1180
1181 // Check that the receiver isn't a smi.
1182 __ tst(r1, Operand(kSmiTagMask));
1183 __ b(eq, &miss);
1184
1185 // Check that the maps haven't changed.
1186 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1187
1188 if (object->IsGlobalObject()) {
1189 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1190 __ str(r3, MemOperand(sp, argc * kPointerSize));
1191 }
1192
1193 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1194 argc + 1,
1195 1);
1196
1197 // Handle call cache miss.
1198 __ bind(&miss);
1199 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1200 __ Jump(ic, RelocInfo::CODE_TARGET);
1201
1202 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001203 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001204}
1205
1206
Steve Blocka7e24c12009-10-30 11:49:00 +00001207Object* CallStubCompiler::CompileCallConstant(Object* object,
1208 JSObject* holder,
1209 JSFunction* function,
1210 String* name,
1211 CheckType check) {
1212 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001213 // -- r2 : name
1214 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001215 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001216 SharedFunctionInfo* function_info = function->shared();
1217 if (function_info->HasCustomCallGenerator()) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001218 const int id = function_info->custom_call_generator_id();
1219 Object* result =
1220 CompileCustomCall(id, object, holder, function, name, check);
Steve Block6ded16b2010-05-10 14:33:55 +01001221 // undefined means bail out to regular compiler.
1222 if (!result->IsUndefined()) {
1223 return result;
1224 }
1225 }
1226
1227 Label miss_in_smi_check;
Steve Blocka7e24c12009-10-30 11:49:00 +00001228
1229 // Get the receiver from the stack
1230 const int argc = arguments().immediate();
1231 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1232
1233 // Check that the receiver isn't a smi.
1234 if (check != NUMBER_CHECK) {
1235 __ tst(r1, Operand(kSmiTagMask));
Steve Block6ded16b2010-05-10 14:33:55 +01001236 __ b(eq, &miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001237 }
1238
1239 // Make sure that it's okay not to patch the on stack receiver
1240 // unless we're doing a receiver map check.
1241 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1242
Steve Block6ded16b2010-05-10 14:33:55 +01001243 CallOptimization optimization(function);
1244 int depth = kInvalidProtoDepth;
1245 Label miss;
1246
Steve Blocka7e24c12009-10-30 11:49:00 +00001247 switch (check) {
1248 case RECEIVER_MAP_CHECK:
Steve Block6ded16b2010-05-10 14:33:55 +01001249 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1250
1251 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1252 depth = optimization.GetPrototypeDepthOfExpectedType(
1253 JSObject::cast(object), holder);
1254 }
1255
1256 if (depth != kInvalidProtoDepth) {
1257 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1258 ReserveSpaceForFastApiCall(masm(), r0);
1259 }
1260
Steve Blocka7e24c12009-10-30 11:49:00 +00001261 // Check that the maps haven't changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001262 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, name,
1263 depth, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001264
1265 // Patch the receiver on the stack with the global proxy if
1266 // necessary.
1267 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001268 ASSERT(depth == kInvalidProtoDepth);
Steve Blocka7e24c12009-10-30 11:49:00 +00001269 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1270 __ str(r3, MemOperand(sp, argc * kPointerSize));
1271 }
1272 break;
1273
1274 case STRING_CHECK:
Leon Clarkee46be812010-01-19 14:06:41 +00001275 if (!function->IsBuiltin()) {
1276 // Calling non-builtins with a value as receiver requires boxing.
1277 __ jmp(&miss);
1278 } else {
1279 // Check that the object is a two-byte string or a symbol.
Andrei Popescu402d9372010-02-26 13:31:12 +00001280 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001281 __ b(hs, &miss);
1282 // Check that the maps starting from the prototype haven't changed.
1283 GenerateLoadGlobalFunctionPrototype(masm(),
1284 Context::STRING_FUNCTION_INDEX,
Andrei Popescu402d9372010-02-26 13:31:12 +00001285 r0);
1286 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001287 r1, name, &miss);
1288 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001289 break;
1290
1291 case NUMBER_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001292 if (!function->IsBuiltin()) {
1293 // Calling non-builtins with a value as receiver requires boxing.
1294 __ jmp(&miss);
1295 } else {
1296 Label fast;
1297 // Check that the object is a smi or a heap number.
1298 __ tst(r1, Operand(kSmiTagMask));
1299 __ b(eq, &fast);
Andrei Popescu402d9372010-02-26 13:31:12 +00001300 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001301 __ b(ne, &miss);
1302 __ bind(&fast);
1303 // Check that the maps starting from the prototype haven't changed.
1304 GenerateLoadGlobalFunctionPrototype(masm(),
1305 Context::NUMBER_FUNCTION_INDEX,
Andrei Popescu402d9372010-02-26 13:31:12 +00001306 r0);
1307 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001308 r1, name, &miss);
1309 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001310 break;
1311 }
1312
1313 case BOOLEAN_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001314 if (!function->IsBuiltin()) {
1315 // Calling non-builtins with a value as receiver requires boxing.
1316 __ jmp(&miss);
1317 } else {
1318 Label fast;
1319 // Check that the object is a boolean.
1320 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1321 __ cmp(r1, ip);
1322 __ b(eq, &fast);
1323 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1324 __ cmp(r1, ip);
1325 __ b(ne, &miss);
1326 __ bind(&fast);
1327 // Check that the maps starting from the prototype haven't changed.
1328 GenerateLoadGlobalFunctionPrototype(masm(),
1329 Context::BOOLEAN_FUNCTION_INDEX,
Andrei Popescu402d9372010-02-26 13:31:12 +00001330 r0);
1331 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001332 r1, name, &miss);
1333 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001334 break;
1335 }
1336
Steve Blocka7e24c12009-10-30 11:49:00 +00001337 default:
1338 UNREACHABLE();
1339 }
1340
Steve Block6ded16b2010-05-10 14:33:55 +01001341 if (depth != kInvalidProtoDepth) {
1342 GenerateFastApiCall(masm(), optimization, argc);
1343 } else {
1344 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1345 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001346
1347 // Handle call cache miss.
1348 __ bind(&miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001349 if (depth != kInvalidProtoDepth) {
1350 FreeSpaceForFastApiCall(masm());
1351 }
1352
1353 __ bind(&miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001354 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1355 __ Jump(ic, RelocInfo::CODE_TARGET);
1356
1357 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001358 return GetCode(function);
Steve Blocka7e24c12009-10-30 11:49:00 +00001359}
1360
1361
Andrei Popescu402d9372010-02-26 13:31:12 +00001362Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001363 JSObject* holder,
1364 String* name) {
1365 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001366 // -- r2 : name
1367 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001368 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001369
Steve Block6ded16b2010-05-10 14:33:55 +01001370 Label miss;
Andrei Popescu402d9372010-02-26 13:31:12 +00001371
Leon Clarke4515c472010-02-03 11:58:03 +00001372 // Get the number of arguments.
1373 const int argc = arguments().immediate();
1374
1375 LookupResult lookup;
1376 LookupPostInterceptor(holder, name, &lookup);
1377
Steve Block6ded16b2010-05-10 14:33:55 +01001378 // Get the receiver from the stack.
1379 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001380
Steve Block6ded16b2010-05-10 14:33:55 +01001381 CallInterceptorCompiler compiler(this, arguments(), r2);
1382 compiler.Compile(masm(),
1383 object,
1384 holder,
1385 name,
1386 &lookup,
1387 r1,
1388 r3,
1389 r4,
1390 &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001391
1392 // Move returned value, the function to call, to r1.
1393 __ mov(r1, r0);
Leon Clarke4515c472010-02-03 11:58:03 +00001394 // Restore receiver.
Steve Block6ded16b2010-05-10 14:33:55 +01001395 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001396
1397 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001398
1399 // Handle call cache miss.
1400 __ bind(&miss);
1401 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1402 __ Jump(ic, RelocInfo::CODE_TARGET);
1403
1404 // Return the generated code.
1405 return GetCode(INTERCEPTOR, name);
1406}
1407
1408
1409Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1410 GlobalObject* holder,
1411 JSGlobalPropertyCell* cell,
1412 JSFunction* function,
1413 String* name) {
1414 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001415 // -- r2 : name
1416 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001417 // -----------------------------------
1418 Label miss;
1419
1420 // Get the number of arguments.
1421 const int argc = arguments().immediate();
1422
1423 // Get the receiver from the stack.
1424 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1425
1426 // If the object is the holder then we know that it's a global
1427 // object which can only happen for contextual calls. In this case,
1428 // the receiver cannot be a smi.
1429 if (object != holder) {
1430 __ tst(r0, Operand(kSmiTagMask));
1431 __ b(eq, &miss);
1432 }
1433
1434 // Check that the maps haven't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001435 CheckPrototypes(object, r0, holder, r3, r1, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001436
1437 // Get the value from the cell.
1438 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1439 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1440
1441 // Check that the cell contains the same function.
Leon Clarkee46be812010-01-19 14:06:41 +00001442 if (Heap::InNewSpace(function)) {
1443 // We can't embed a pointer to a function in new space so we have
1444 // to verify that the shared function info is unchanged. This has
1445 // the nice side effect that multiple closures based on the same
1446 // function can all use this call IC. Before we load through the
1447 // function, we have to verify that it still is a function.
1448 __ tst(r1, Operand(kSmiTagMask));
1449 __ b(eq, &miss);
1450 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1451 __ b(ne, &miss);
1452
1453 // Check the shared function info. Make sure it hasn't changed.
1454 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
Andrei Popescu402d9372010-02-26 13:31:12 +00001455 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1456 __ cmp(r4, r3);
Leon Clarkee46be812010-01-19 14:06:41 +00001457 __ b(ne, &miss);
1458 } else {
1459 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1460 __ b(ne, &miss);
1461 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001462
1463 // Patch the receiver on the stack with the global proxy if
1464 // necessary.
1465 if (object->IsGlobalObject()) {
1466 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1467 __ str(r3, MemOperand(sp, argc * kPointerSize));
1468 }
1469
1470 // Setup the context (function already in r1).
1471 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1472
1473 // Jump to the cached code (tail call).
Steve Block6ded16b2010-05-10 14:33:55 +01001474 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001475 ASSERT(function->is_compiled());
1476 Handle<Code> code(function->code());
1477 ParameterCount expected(function->shared()->formal_parameter_count());
1478 __ InvokeCode(code, expected, arguments(),
1479 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1480
1481 // Handle call cache miss.
1482 __ bind(&miss);
1483 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
1484 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1485 __ Jump(ic, RelocInfo::CODE_TARGET);
1486
1487 // Return the generated code.
1488 return GetCode(NORMAL, name);
1489}
1490
1491
1492Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1493 int index,
1494 Map* transition,
1495 String* name) {
1496 // ----------- S t a t e -------------
1497 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001498 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001499 // -- r2 : name
1500 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001501 // -----------------------------------
1502 Label miss;
1503
Steve Blocka7e24c12009-10-30 11:49:00 +00001504 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001505 object,
1506 index,
1507 transition,
Andrei Popescu402d9372010-02-26 13:31:12 +00001508 r1, r2, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001509 &miss);
1510 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001511 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1512 __ Jump(ic, RelocInfo::CODE_TARGET);
1513
1514 // Return the generated code.
1515 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1516}
1517
1518
1519Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1520 AccessorInfo* callback,
1521 String* name) {
1522 // ----------- S t a t e -------------
1523 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001524 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001525 // -- r2 : name
1526 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001527 // -----------------------------------
1528 Label miss;
1529
Steve Blocka7e24c12009-10-30 11:49:00 +00001530 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001531 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001532 __ b(eq, &miss);
1533
1534 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001535 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1536 __ cmp(r3, Operand(Handle<Map>(object->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001537 __ b(ne, &miss);
1538
1539 // Perform global security token check if needed.
1540 if (object->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001541 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001542 }
1543
1544 // Stub never generated for non-global objects that require access
1545 // checks.
1546 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1547
Andrei Popescu402d9372010-02-26 13:31:12 +00001548 __ push(r1); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001549 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
Steve Block6ded16b2010-05-10 14:33:55 +01001550 __ Push(ip, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001551
1552 // Do tail-call to the runtime system.
1553 ExternalReference store_callback_property =
1554 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001555 __ TailCallExternalReference(store_callback_property, 4, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001556
1557 // Handle store cache miss.
1558 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001559 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1560 __ Jump(ic, RelocInfo::CODE_TARGET);
1561
1562 // Return the generated code.
1563 return GetCode(CALLBACKS, name);
1564}
1565
1566
1567Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1568 String* name) {
1569 // ----------- S t a t e -------------
1570 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001571 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001572 // -- r2 : name
1573 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001574 // -----------------------------------
1575 Label miss;
1576
Steve Blocka7e24c12009-10-30 11:49:00 +00001577 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001578 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001579 __ b(eq, &miss);
1580
1581 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001582 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1583 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001584 __ b(ne, &miss);
1585
1586 // Perform global security token check if needed.
1587 if (receiver->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001588 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001589 }
1590
Andrei Popescu402d9372010-02-26 13:31:12 +00001591 // Stub is never generated for non-global objects that require access
Steve Blocka7e24c12009-10-30 11:49:00 +00001592 // checks.
1593 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1594
Steve Block6ded16b2010-05-10 14:33:55 +01001595 __ Push(r1, r2, r0); // Receiver, name, value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001596
1597 // Do tail-call to the runtime system.
1598 ExternalReference store_ic_property =
1599 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001600 __ TailCallExternalReference(store_ic_property, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001601
1602 // Handle store cache miss.
1603 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001604 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1605 __ Jump(ic, RelocInfo::CODE_TARGET);
1606
1607 // Return the generated code.
1608 return GetCode(INTERCEPTOR, name);
1609}
1610
1611
1612Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1613 JSGlobalPropertyCell* cell,
1614 String* name) {
1615 // ----------- S t a t e -------------
1616 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001617 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001618 // -- r2 : name
1619 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001620 // -----------------------------------
1621 Label miss;
1622
1623 // Check that the map of the global has not changed.
Steve Blocka7e24c12009-10-30 11:49:00 +00001624 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1625 __ cmp(r3, Operand(Handle<Map>(object->map())));
1626 __ b(ne, &miss);
1627
1628 // Store the value in the cell.
1629 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1630 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
1631
Andrei Popescu402d9372010-02-26 13:31:12 +00001632 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001633 __ Ret();
1634
1635 // Handle store cache miss.
1636 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001637 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001638 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1639 __ Jump(ic, RelocInfo::CODE_TARGET);
1640
1641 // Return the generated code.
1642 return GetCode(NORMAL, name);
1643}
1644
1645
Steve Block6ded16b2010-05-10 14:33:55 +01001646Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1647 JSObject* object,
1648 JSObject* last) {
1649 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001650 // -- r0 : receiver
Steve Block6ded16b2010-05-10 14:33:55 +01001651 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001652 // -----------------------------------
1653 Label miss;
1654
Steve Block6ded16b2010-05-10 14:33:55 +01001655 // Check that receiver is not a smi.
1656 __ tst(r0, Operand(kSmiTagMask));
1657 __ b(eq, &miss);
1658
1659 // Check the maps of the full prototype chain.
1660 CheckPrototypes(object, r0, last, r3, r1, name, &miss);
1661
1662 // If the last object in the prototype chain is a global object,
1663 // check that the global property cell is empty.
1664 if (last->IsGlobalObject()) {
1665 Object* cell = GenerateCheckPropertyCell(masm(),
1666 GlobalObject::cast(last),
1667 name,
1668 r1,
1669 &miss);
1670 if (cell->IsFailure()) return cell;
1671 }
1672
1673 // Return undefined if maps of the full prototype chain are still the
1674 // same and no global property with this name contains a value.
1675 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1676 __ Ret();
1677
1678 __ bind(&miss);
1679 GenerateLoadMiss(masm(), Code::LOAD_IC);
1680
1681 // Return the generated code.
1682 return GetCode(NONEXISTENT, Heap::empty_string());
1683}
1684
1685
Steve Blocka7e24c12009-10-30 11:49:00 +00001686Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1687 JSObject* holder,
1688 int index,
1689 String* name) {
1690 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001691 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001692 // -- r2 : name
1693 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001694 // -----------------------------------
1695 Label miss;
1696
Steve Blocka7e24c12009-10-30 11:49:00 +00001697 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
1698 __ bind(&miss);
1699 GenerateLoadMiss(masm(), Code::LOAD_IC);
1700
1701 // Return the generated code.
1702 return GetCode(FIELD, name);
1703}
1704
1705
Leon Clarkee46be812010-01-19 14:06:41 +00001706Object* LoadStubCompiler::CompileLoadCallback(String* name,
1707 JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001708 JSObject* holder,
Leon Clarkee46be812010-01-19 14:06:41 +00001709 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001710 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001711 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001712 // -- r2 : name
1713 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001714 // -----------------------------------
1715 Label miss;
1716
Leon Clarkee46be812010-01-19 14:06:41 +00001717 Failure* failure = Failure::InternalError();
1718 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
1719 callback, name, &miss, &failure);
1720 if (!success) return failure;
1721
Steve Blocka7e24c12009-10-30 11:49:00 +00001722 __ bind(&miss);
1723 GenerateLoadMiss(masm(), Code::LOAD_IC);
1724
1725 // Return the generated code.
1726 return GetCode(CALLBACKS, name);
1727}
1728
1729
1730Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1731 JSObject* holder,
1732 Object* value,
1733 String* name) {
1734 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001735 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001736 // -- r2 : name
1737 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001738 // -----------------------------------
1739 Label miss;
1740
Steve Blocka7e24c12009-10-30 11:49:00 +00001741 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
1742 __ bind(&miss);
1743 GenerateLoadMiss(masm(), Code::LOAD_IC);
1744
1745 // Return the generated code.
1746 return GetCode(CONSTANT_FUNCTION, name);
1747}
1748
1749
1750Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1751 JSObject* holder,
1752 String* name) {
1753 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001754 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001755 // -- r2 : name
1756 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001757 // -----------------------------------
1758 Label miss;
1759
Steve Blocka7e24c12009-10-30 11:49:00 +00001760 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001761 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001762 GenerateLoadInterceptor(object,
1763 holder,
1764 &lookup,
1765 r0,
1766 r2,
1767 r3,
1768 r1,
1769 name,
1770 &miss);
1771 __ bind(&miss);
1772 GenerateLoadMiss(masm(), Code::LOAD_IC);
1773
1774 // Return the generated code.
1775 return GetCode(INTERCEPTOR, name);
1776}
1777
1778
1779Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1780 GlobalObject* holder,
1781 JSGlobalPropertyCell* cell,
1782 String* name,
1783 bool is_dont_delete) {
1784 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001785 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001786 // -- r2 : name
1787 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001788 // -----------------------------------
1789 Label miss;
1790
Steve Blocka7e24c12009-10-30 11:49:00 +00001791 // If the object is the holder then we know that it's a global
1792 // object which can only happen for contextual calls. In this case,
1793 // the receiver cannot be a smi.
1794 if (object != holder) {
Steve Block6ded16b2010-05-10 14:33:55 +01001795 __ tst(r0, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001796 __ b(eq, &miss);
1797 }
1798
1799 // Check that the map of the global has not changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001800 CheckPrototypes(object, r0, holder, r3, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001801
1802 // Get the value from the cell.
1803 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
Steve Block6ded16b2010-05-10 14:33:55 +01001804 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001805
1806 // Check for deleted property if property can actually be deleted.
1807 if (!is_dont_delete) {
1808 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
Steve Block6ded16b2010-05-10 14:33:55 +01001809 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00001810 __ b(eq, &miss);
1811 }
1812
Steve Block6ded16b2010-05-10 14:33:55 +01001813 __ mov(r0, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001814 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1815 __ Ret();
1816
1817 __ bind(&miss);
1818 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1819 GenerateLoadMiss(masm(), Code::LOAD_IC);
1820
1821 // Return the generated code.
1822 return GetCode(NORMAL, name);
1823}
1824
1825
1826Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1827 JSObject* receiver,
1828 JSObject* holder,
1829 int index) {
1830 // ----------- S t a t e -------------
1831 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001832 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001833 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001834 // -----------------------------------
1835 Label miss;
1836
Steve Block6ded16b2010-05-10 14:33:55 +01001837 // Check the key is the cached one.
1838 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001839 __ b(ne, &miss);
1840
Steve Block6ded16b2010-05-10 14:33:55 +01001841 GenerateLoadField(receiver, holder, r1, r2, r3, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001842 __ bind(&miss);
1843 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1844
1845 return GetCode(FIELD, name);
1846}
1847
1848
1849Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1850 JSObject* receiver,
1851 JSObject* holder,
1852 AccessorInfo* callback) {
1853 // ----------- S t a t e -------------
1854 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001855 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001856 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001857 // -----------------------------------
1858 Label miss;
1859
Steve Block6ded16b2010-05-10 14:33:55 +01001860 // Check the key is the cached one.
1861 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001862 __ b(ne, &miss);
1863
Leon Clarkee46be812010-01-19 14:06:41 +00001864 Failure* failure = Failure::InternalError();
Steve Block6ded16b2010-05-10 14:33:55 +01001865 bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001866 callback, name, &miss, &failure);
1867 if (!success) return failure;
1868
Steve Blocka7e24c12009-10-30 11:49:00 +00001869 __ bind(&miss);
1870 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1871
1872 return GetCode(CALLBACKS, name);
1873}
1874
1875
1876Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1877 JSObject* receiver,
1878 JSObject* holder,
1879 Object* value) {
1880 // ----------- S t a t e -------------
1881 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001882 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001883 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001884 // -----------------------------------
1885 Label miss;
1886
Steve Block6ded16b2010-05-10 14:33:55 +01001887 // Check the key is the cached one.
1888 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001889 __ b(ne, &miss);
1890
Steve Block6ded16b2010-05-10 14:33:55 +01001891 GenerateLoadConstant(receiver, holder, r1, r2, r3, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001892 __ bind(&miss);
1893 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1894
1895 // Return the generated code.
1896 return GetCode(CONSTANT_FUNCTION, name);
1897}
1898
1899
1900Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1901 JSObject* holder,
1902 String* name) {
1903 // ----------- S t a t e -------------
1904 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001905 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001906 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001907 // -----------------------------------
1908 Label miss;
1909
Steve Block6ded16b2010-05-10 14:33:55 +01001910 // Check the key is the cached one.
1911 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001912 __ b(ne, &miss);
1913
1914 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001915 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001916 GenerateLoadInterceptor(receiver,
1917 holder,
1918 &lookup,
Steve Block6ded16b2010-05-10 14:33:55 +01001919 r1,
Steve Blocka7e24c12009-10-30 11:49:00 +00001920 r0,
1921 r2,
1922 r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001923 name,
1924 &miss);
1925 __ bind(&miss);
1926 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1927
1928 return GetCode(INTERCEPTOR, name);
1929}
1930
1931
1932Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1933 // ----------- S t a t e -------------
1934 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001935 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001936 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001937 // -----------------------------------
1938 Label miss;
1939
Steve Block6ded16b2010-05-10 14:33:55 +01001940 // Check the key is the cached one.
1941 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001942 __ b(ne, &miss);
1943
Steve Block6ded16b2010-05-10 14:33:55 +01001944 GenerateLoadArrayLength(masm(), r1, r2, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001945 __ bind(&miss);
1946 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1947
1948 return GetCode(CALLBACKS, name);
1949}
1950
1951
1952Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
1953 // ----------- S t a t e -------------
1954 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001955 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001956 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001957 // -----------------------------------
1958 Label miss;
1959 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1960
Steve Block6ded16b2010-05-10 14:33:55 +01001961 // Check the key is the cached one.
1962 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001963 __ b(ne, &miss);
1964
Steve Block6ded16b2010-05-10 14:33:55 +01001965 GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001966 __ bind(&miss);
1967 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1968
1969 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1970
1971 return GetCode(CALLBACKS, name);
1972}
1973
1974
1975// TODO(1224671): implement the fast case.
1976Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1977 // ----------- S t a t e -------------
1978 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001979 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001980 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001981 // -----------------------------------
1982 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1983
1984 return GetCode(CALLBACKS, name);
1985}
1986
1987
1988Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1989 int index,
1990 Map* transition,
1991 String* name) {
1992 // ----------- S t a t e -------------
1993 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01001994 // -- r1 : key
1995 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001996 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001997 // -----------------------------------
1998 Label miss;
1999
Leon Clarkef7060e22010-06-03 12:02:55 +01002000 __ IncrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002001
2002 // Check that the name has not changed.
Leon Clarkef7060e22010-06-03 12:02:55 +01002003 __ cmp(r1, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002004 __ b(ne, &miss);
2005
Leon Clarkef7060e22010-06-03 12:02:55 +01002006 // r3 is used as scratch register. r1 and r2 keep their values if a jump to
2007 // the miss label is generated.
Steve Blocka7e24c12009-10-30 11:49:00 +00002008 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002009 object,
2010 index,
2011 transition,
Leon Clarkef7060e22010-06-03 12:02:55 +01002012 r2, r1, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00002013 &miss);
2014 __ bind(&miss);
2015
Leon Clarkef7060e22010-06-03 12:02:55 +01002016 __ DecrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002017 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
Leon Clarkef7060e22010-06-03 12:02:55 +01002018
Steve Blocka7e24c12009-10-30 11:49:00 +00002019 __ Jump(ic, RelocInfo::CODE_TARGET);
2020
2021 // Return the generated code.
2022 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2023}
2024
2025
2026Object* ConstructStubCompiler::CompileConstructStub(
2027 SharedFunctionInfo* shared) {
2028 // ----------- S t a t e -------------
2029 // -- r0 : argc
2030 // -- r1 : constructor
2031 // -- lr : return address
2032 // -- [sp] : last argument
2033 // -----------------------------------
2034 Label generic_stub_call;
2035
2036 // Use r7 for holding undefined which is used in several places below.
2037 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2038
2039#ifdef ENABLE_DEBUGGER_SUPPORT
2040 // Check to see whether there are any break points in the function code. If
2041 // there are jump to the generic constructor stub which calls the actual
2042 // code for the function thereby hitting the break points.
2043 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2044 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2045 __ cmp(r2, r7);
2046 __ b(ne, &generic_stub_call);
2047#endif
2048
2049 // Load the initial map and verify that it is in fact a map.
2050 // r1: constructor function
2051 // r7: undefined
2052 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2053 __ tst(r2, Operand(kSmiTagMask));
2054 __ b(eq, &generic_stub_call);
2055 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2056 __ b(ne, &generic_stub_call);
2057
2058#ifdef DEBUG
2059 // Cannot construct functions this way.
2060 // r0: argc
2061 // r1: constructor function
2062 // r2: initial map
2063 // r7: undefined
2064 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2065 __ Check(ne, "Function constructed by construct stub.");
2066#endif
2067
2068 // Now allocate the JSObject in new space.
2069 // r0: argc
2070 // r1: constructor function
2071 // r2: initial map
2072 // r7: undefined
2073 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
2074 __ AllocateInNewSpace(r3,
2075 r4,
2076 r5,
2077 r6,
2078 &generic_stub_call,
Kristian Monsen25f61362010-05-21 11:50:48 +01002079 SIZE_IN_WORDS);
Steve Blocka7e24c12009-10-30 11:49:00 +00002080
2081 // Allocated the JSObject, now initialize the fields. Map is set to initial
2082 // map and properties and elements are set to empty fixed array.
2083 // r0: argc
2084 // r1: constructor function
2085 // r2: initial map
2086 // r3: object size (in words)
2087 // r4: JSObject (not tagged)
2088 // r7: undefined
2089 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2090 __ mov(r5, r4);
2091 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2092 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2093 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2094 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2095 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2096 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2097
2098 // Calculate the location of the first argument. The stack contains only the
2099 // argc arguments.
2100 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2101
2102 // Fill all the in-object properties with undefined.
2103 // r0: argc
2104 // r1: first argument
2105 // r3: object size (in words)
2106 // r4: JSObject (not tagged)
2107 // r5: First in-object property of JSObject (not tagged)
2108 // r7: undefined
2109 // Fill the initialized properties with a constant value or a passed argument
2110 // depending on the this.x = ...; assignment in the function.
2111 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2112 if (shared->IsThisPropertyAssignmentArgument(i)) {
2113 Label not_passed, next;
2114 // Check if the argument assigned to the property is actually passed.
2115 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2116 __ cmp(r0, Operand(arg_number));
2117 __ b(le, &not_passed);
2118 // Argument passed - find it on the stack.
2119 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2120 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2121 __ b(&next);
2122 __ bind(&not_passed);
2123 // Set the property to undefined.
2124 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2125 __ bind(&next);
2126 } else {
2127 // Set the property to the constant value.
2128 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2129 __ mov(r2, Operand(constant));
2130 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2131 }
2132 }
2133
2134 // Fill the unused in-object property fields with undefined.
2135 for (int i = shared->this_property_assignments_count();
2136 i < shared->CalculateInObjectProperties();
2137 i++) {
2138 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2139 }
2140
2141 // r0: argc
2142 // r4: JSObject (not tagged)
2143 // Move argc to r1 and the JSObject to return to r0 and tag it.
2144 __ mov(r1, r0);
2145 __ mov(r0, r4);
2146 __ orr(r0, r0, Operand(kHeapObjectTag));
2147
2148 // r0: JSObject
2149 // r1: argc
2150 // Remove caller arguments and receiver from the stack and return.
2151 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2152 __ add(sp, sp, Operand(kPointerSize));
2153 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2154 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2155 __ Jump(lr);
2156
2157 // Jump to the generic stub in case the specialized code cannot handle the
2158 // construction.
2159 __ bind(&generic_stub_call);
2160 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2161 Handle<Code> generic_construct_stub(code);
2162 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2163
2164 // Return the generated code.
2165 return GetCode();
2166}
2167
2168
2169#undef __
2170
2171} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002172
2173#endif // V8_TARGET_ARCH_ARM