blob: 3e5ba1126f60e14acd521c91ba6f4b0583f45062 [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
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100155void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
156 MacroAssembler* masm, int index, Register prototype) {
157 // Get the global function with the given index.
158 JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
159 // Load its initial map. The global functions all have initial maps.
160 __ Move(prototype, Handle<Map>(function->initial_map()));
161 // Load the prototype from the initial map.
162 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
163}
164
165
Steve Blocka7e24c12009-10-30 11:49:00 +0000166// Load a fast property out of a holder object (src). In-object properties
167// are loaded directly otherwise the property is loaded from the properties
168// fixed array.
169void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
170 Register dst, Register src,
171 JSObject* holder, int index) {
172 // Adjust for the number of properties stored in the holder.
173 index -= holder->map()->inobject_properties();
174 if (index < 0) {
175 // Get the property straight out of the holder.
176 int offset = holder->map()->instance_size() + (index * kPointerSize);
177 __ ldr(dst, FieldMemOperand(src, offset));
178 } else {
179 // Calculate the offset into the properties array.
180 int offset = index * kPointerSize + FixedArray::kHeaderSize;
181 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
182 __ ldr(dst, FieldMemOperand(dst, offset));
183 }
184}
185
186
187void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
188 Register receiver,
189 Register scratch,
190 Label* miss_label) {
191 // Check that the receiver isn't a smi.
192 __ tst(receiver, Operand(kSmiTagMask));
193 __ b(eq, miss_label);
194
195 // Check that the object is a JS array.
196 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
197 __ b(ne, miss_label);
198
199 // Load length directly from the JS array.
200 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
201 __ Ret();
202}
203
204
Andrei Popescu402d9372010-02-26 13:31:12 +0000205// Generate code to check if an object is a string. If the object is a
206// heap object, its map's instance type is left in the scratch1 register.
207// If this is not needed, scratch1 and scratch2 may be the same register.
Steve Blocka7e24c12009-10-30 11:49:00 +0000208static void GenerateStringCheck(MacroAssembler* masm,
209 Register receiver,
210 Register scratch1,
211 Register scratch2,
212 Label* smi,
213 Label* non_string_object) {
214 // Check that the receiver isn't a smi.
215 __ tst(receiver, Operand(kSmiTagMask));
216 __ b(eq, smi);
217
218 // Check that the object is a string.
219 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
220 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
221 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
222 // The cast is to resolve the overload for the argument of 0x0.
223 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
224 __ b(ne, non_string_object);
225}
226
227
228// Generate code to load the length from a string object and return the length.
229// If the receiver object is not a string or a wrapped string object the
230// execution continues at the miss label. The register containing the
231// receiver is potentially clobbered.
Andrei Popescu402d9372010-02-26 13:31:12 +0000232void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
233 Register receiver,
234 Register scratch1,
235 Register scratch2,
236 Label* miss) {
237 Label check_wrapper;
Steve Blocka7e24c12009-10-30 11:49:00 +0000238
Steve Blocka7e24c12009-10-30 11:49:00 +0000239 // Check if the object is a string leaving the instance type in the
240 // scratch1 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000241 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
Steve Blocka7e24c12009-10-30 11:49:00 +0000242
243 // Load length directly from the string.
Steve Blocka7e24c12009-10-30 11:49:00 +0000244 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000245 __ Ret();
246
247 // Check if the object is a JSValue wrapper.
248 __ bind(&check_wrapper);
249 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
250 __ b(ne, miss);
251
Andrei Popescu402d9372010-02-26 13:31:12 +0000252 // Unwrap the value and check if the wrapped value is a string.
253 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
254 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
255 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
Andrei Popescu402d9372010-02-26 13:31:12 +0000256 __ Ret();
Steve Blocka7e24c12009-10-30 11:49:00 +0000257}
258
259
260void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
261 Register receiver,
262 Register scratch1,
263 Register scratch2,
264 Label* miss_label) {
265 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
266 __ mov(r0, scratch1);
267 __ Ret();
268}
269
270
271// Generate StoreField code, value is passed in r0 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000272// When leaving generated code after success, the receiver_reg and name_reg
273// may be clobbered. Upon branch to miss_label, the receiver and name
274// registers have their original values.
Steve Blocka7e24c12009-10-30 11:49:00 +0000275void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Steve Blocka7e24c12009-10-30 11:49:00 +0000276 JSObject* object,
277 int index,
278 Map* transition,
279 Register receiver_reg,
280 Register name_reg,
281 Register scratch,
282 Label* miss_label) {
283 // r0 : value
284 Label exit;
285
286 // Check that the receiver isn't a smi.
287 __ tst(receiver_reg, Operand(kSmiTagMask));
288 __ b(eq, miss_label);
289
290 // Check that the map of the receiver hasn't changed.
291 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
292 __ cmp(scratch, Operand(Handle<Map>(object->map())));
293 __ b(ne, miss_label);
294
295 // Perform global security token check if needed.
296 if (object->IsJSGlobalProxy()) {
297 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
298 }
299
300 // Stub never generated for non-global objects that require access
301 // checks.
302 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
303
304 // Perform map transition for the receiver if necessary.
305 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
306 // The properties must be extended before we can store the value.
307 // We jump to a runtime call that extends the properties array.
Andrei Popescu402d9372010-02-26 13:31:12 +0000308 __ push(receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000309 __ mov(r2, Operand(Handle<Map>(transition)));
Steve Block6ded16b2010-05-10 14:33:55 +0100310 __ Push(r2, r0);
311 __ TailCallExternalReference(
Andrei Popescu402d9372010-02-26 13:31:12 +0000312 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)),
313 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000314 return;
315 }
316
317 if (transition != NULL) {
318 // Update the map of the object; no write barrier updating is
319 // needed because the map is never in new space.
320 __ mov(ip, Operand(Handle<Map>(transition)));
321 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
322 }
323
324 // Adjust for the number of properties stored in the object. Even in the
325 // face of a transition we can use the old map here because the size of the
326 // object and the number of in-object properties is not going to change.
327 index -= object->map()->inobject_properties();
328
329 if (index < 0) {
330 // Set the property straight into the object.
331 int offset = object->map()->instance_size() + (index * kPointerSize);
332 __ str(r0, FieldMemOperand(receiver_reg, offset));
333
334 // Skip updating write barrier if storing a smi.
335 __ tst(r0, Operand(kSmiTagMask));
336 __ b(eq, &exit);
337
338 // Update the write barrier for the array address.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100339 // Pass the now unused name_reg as a scratch register.
340 __ RecordWrite(receiver_reg, Operand(offset), name_reg, scratch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000341 } else {
342 // Write to the properties array.
343 int offset = index * kPointerSize + FixedArray::kHeaderSize;
344 // Get the properties array
345 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
346 __ str(r0, FieldMemOperand(scratch, offset));
347
348 // Skip updating write barrier if storing a smi.
349 __ tst(r0, Operand(kSmiTagMask));
350 __ b(eq, &exit);
351
352 // Update the write barrier for the array address.
353 // Ok to clobber receiver_reg and name_reg, since we return.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100354 __ RecordWrite(scratch, Operand(offset), name_reg, receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000355 }
356
357 // Return the value (register r0).
358 __ bind(&exit);
359 __ Ret();
360}
361
362
363void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
364 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
365 Code* code = NULL;
366 if (kind == Code::LOAD_IC) {
367 code = Builtins::builtin(Builtins::LoadIC_Miss);
368 } else {
369 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
370 }
371
372 Handle<Code> ic(code);
373 __ Jump(ic, RelocInfo::CODE_TARGET);
374}
375
376
Leon Clarke4515c472010-02-03 11:58:03 +0000377static void GenerateCallFunction(MacroAssembler* masm,
378 Object* object,
379 const ParameterCount& arguments,
380 Label* miss) {
381 // ----------- S t a t e -------------
382 // -- r0: receiver
383 // -- r1: function to call
384 // -----------------------------------
385
386 // Check that the function really is a function.
387 __ BranchOnSmi(r1, miss);
Andrei Popescu402d9372010-02-26 13:31:12 +0000388 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
Leon Clarke4515c472010-02-03 11:58:03 +0000389 __ b(ne, miss);
390
391 // Patch the receiver on the stack with the global proxy if
392 // necessary.
393 if (object->IsGlobalObject()) {
394 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
395 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
396 }
397
398 // Invoke the function.
399 __ InvokeFunction(r1, arguments, JUMP_FUNCTION);
400}
401
402
Leon Clarke4515c472010-02-03 11:58:03 +0000403static void PushInterceptorArguments(MacroAssembler* masm,
404 Register receiver,
405 Register holder,
406 Register name,
407 JSObject* holder_obj) {
Leon Clarke4515c472010-02-03 11:58:03 +0000408 __ push(name);
409 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
410 ASSERT(!Heap::InNewSpace(interceptor));
Steve Block6ded16b2010-05-10 14:33:55 +0100411 Register scratch = name;
Leon Clarke4515c472010-02-03 11:58:03 +0000412 __ mov(scratch, Operand(Handle<Object>(interceptor)));
413 __ push(scratch);
Steve Block6ded16b2010-05-10 14:33:55 +0100414 __ push(receiver);
415 __ push(holder);
Leon Clarke4515c472010-02-03 11:58:03 +0000416 __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
417 __ push(scratch);
418}
419
420
421static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
422 Register receiver,
423 Register holder,
424 Register name,
425 JSObject* holder_obj) {
426 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
427
428 ExternalReference ref =
429 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
430 __ mov(r0, Operand(5));
431 __ mov(r1, Operand(ref));
432
433 CEntryStub stub(1);
434 __ CallStub(&stub);
435}
436
437
Steve Block6ded16b2010-05-10 14:33:55 +0100438// Reserves space for the extra arguments to FastHandleApiCall in the
439// caller's frame.
440//
441// These arguments are set by CheckPrototypes and GenerateFastApiCall.
442static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
443 Register scratch) {
444 __ mov(scratch, Operand(Smi::FromInt(0)));
445 __ push(scratch);
446 __ push(scratch);
447 __ push(scratch);
448 __ push(scratch);
449}
450
451
452// Undoes the effects of ReserveSpaceForFastApiCall.
453static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
454 __ Drop(4);
455}
456
457
458// Generates call to FastHandleApiCall builtin.
459static void GenerateFastApiCall(MacroAssembler* masm,
460 const CallOptimization& optimization,
461 int argc) {
462 // Get the function and setup the context.
463 JSFunction* function = optimization.constant_function();
464 __ mov(r7, Operand(Handle<JSFunction>(function)));
465 __ ldr(cp, FieldMemOperand(r7, JSFunction::kContextOffset));
466
467 // Pass the additional arguments FastHandleApiCall expects.
468 bool info_loaded = false;
469 Object* callback = optimization.api_call_info()->callback();
470 if (Heap::InNewSpace(callback)) {
471 info_loaded = true;
472 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
473 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
474 } else {
475 __ Move(r6, Handle<Object>(callback));
476 }
477 Object* call_data = optimization.api_call_info()->data();
478 if (Heap::InNewSpace(call_data)) {
479 if (!info_loaded) {
480 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
481 }
482 __ ldr(r5, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
483 } else {
484 __ Move(r5, Handle<Object>(call_data));
485 }
486
487 __ add(sp, sp, Operand(1 * kPointerSize));
488 __ stm(ia, sp, r5.bit() | r6.bit() | r7.bit());
489 __ sub(sp, sp, Operand(1 * kPointerSize));
490
491 // Set the number of arguments.
492 __ mov(r0, Operand(argc + 4));
493
494 // Jump to the fast api call builtin (tail call).
495 Handle<Code> code = Handle<Code>(
496 Builtins::builtin(Builtins::FastHandleApiCall));
497 ParameterCount expected(0);
498 __ InvokeCode(code, expected, expected,
499 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
500}
501
502
503class CallInterceptorCompiler BASE_EMBEDDED {
504 public:
505 CallInterceptorCompiler(StubCompiler* stub_compiler,
506 const ParameterCount& arguments,
507 Register name)
508 : stub_compiler_(stub_compiler),
509 arguments_(arguments),
510 name_(name) {}
511
512 void Compile(MacroAssembler* masm,
513 JSObject* object,
514 JSObject* holder,
515 String* name,
516 LookupResult* lookup,
517 Register receiver,
518 Register scratch1,
519 Register scratch2,
520 Label* miss) {
521 ASSERT(holder->HasNamedInterceptor());
522 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
523
524 // Check that the receiver isn't a smi.
525 __ BranchOnSmi(receiver, miss);
526
527 CallOptimization optimization(lookup);
528
529 if (optimization.is_constant_call()) {
530 CompileCacheable(masm,
531 object,
532 receiver,
533 scratch1,
534 scratch2,
535 holder,
536 lookup,
537 name,
538 optimization,
539 miss);
540 } else {
541 CompileRegular(masm,
542 object,
543 receiver,
544 scratch1,
545 scratch2,
546 name,
547 holder,
548 miss);
549 }
550 }
551
552 private:
553 void CompileCacheable(MacroAssembler* masm,
554 JSObject* object,
555 Register receiver,
556 Register scratch1,
557 Register scratch2,
Leon Clarkef7060e22010-06-03 12:02:55 +0100558 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100559 LookupResult* lookup,
560 String* name,
561 const CallOptimization& optimization,
562 Label* miss_label) {
563 ASSERT(optimization.is_constant_call());
564 ASSERT(!lookup->holder()->IsGlobalObject());
565
566 int depth1 = kInvalidProtoDepth;
567 int depth2 = kInvalidProtoDepth;
568 bool can_do_fast_api_call = false;
569 if (optimization.is_simple_api_call() &&
570 !lookup->holder()->IsGlobalObject()) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100571 depth1 =
572 optimization.GetPrototypeDepthOfExpectedType(object,
573 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100574 if (depth1 == kInvalidProtoDepth) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100575 depth2 =
576 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
577 lookup->holder());
Steve Block6ded16b2010-05-10 14:33:55 +0100578 }
579 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
580 (depth2 != kInvalidProtoDepth);
581 }
582
583 __ IncrementCounter(&Counters::call_const_interceptor, 1,
584 scratch1, scratch2);
585
586 if (can_do_fast_api_call) {
587 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1,
588 scratch1, scratch2);
589 ReserveSpaceForFastApiCall(masm, scratch1);
590 }
591
Leon Clarkef7060e22010-06-03 12:02:55 +0100592 // Check that the maps from receiver to interceptor's holder
593 // haven't changed and thus we can invoke interceptor.
Steve Block6ded16b2010-05-10 14:33:55 +0100594 Label miss_cleanup;
595 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
596 Register holder =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100597 stub_compiler_->CheckPrototypes(object, receiver,
598 interceptor_holder, scratch1,
599 scratch2, name, depth1, miss);
Steve Block6ded16b2010-05-10 14:33:55 +0100600
Leon Clarkef7060e22010-06-03 12:02:55 +0100601 // Invoke an interceptor and if it provides a value,
602 // branch to |regular_invoke|.
Steve Block6ded16b2010-05-10 14:33:55 +0100603 Label regular_invoke;
Leon Clarkef7060e22010-06-03 12:02:55 +0100604 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
Steve Block6ded16b2010-05-10 14:33:55 +0100605 &regular_invoke);
606
Leon Clarkef7060e22010-06-03 12:02:55 +0100607 // Interceptor returned nothing for this property. Try to use cached
608 // constant function.
Steve Block6ded16b2010-05-10 14:33:55 +0100609
Leon Clarkef7060e22010-06-03 12:02:55 +0100610 // Check that the maps from interceptor's holder to constant function's
611 // holder haven't changed and thus we can use cached constant function.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100612 if (interceptor_holder != lookup->holder()) {
613 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
614 lookup->holder(), scratch1,
615 scratch2, name, depth2, miss);
616 } else {
617 // CheckPrototypes has a side effect of fetching a 'holder'
618 // for API (object which is instanceof for the signature). It's
619 // safe to omit it here, as if present, it should be fetched
620 // by the previous CheckPrototypes.
621 ASSERT(depth2 == kInvalidProtoDepth);
622 }
Steve Block6ded16b2010-05-10 14:33:55 +0100623
Leon Clarkef7060e22010-06-03 12:02:55 +0100624 // Invoke function.
Steve Block6ded16b2010-05-10 14:33:55 +0100625 if (can_do_fast_api_call) {
626 GenerateFastApiCall(masm, optimization, arguments_.immediate());
627 } else {
628 __ InvokeFunction(optimization.constant_function(), arguments_,
629 JUMP_FUNCTION);
630 }
631
Leon Clarkef7060e22010-06-03 12:02:55 +0100632 // Deferred code for fast API call case---clean preallocated space.
Steve Block6ded16b2010-05-10 14:33:55 +0100633 if (can_do_fast_api_call) {
634 __ bind(&miss_cleanup);
635 FreeSpaceForFastApiCall(masm);
636 __ b(miss_label);
637 }
638
Leon Clarkef7060e22010-06-03 12:02:55 +0100639 // Invoke a regular function.
Steve Block6ded16b2010-05-10 14:33:55 +0100640 __ bind(&regular_invoke);
641 if (can_do_fast_api_call) {
642 FreeSpaceForFastApiCall(masm);
643 }
644 }
645
646 void CompileRegular(MacroAssembler* masm,
647 JSObject* object,
648 Register receiver,
649 Register scratch1,
650 Register scratch2,
651 String* name,
Leon Clarkef7060e22010-06-03 12:02:55 +0100652 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100653 Label* miss_label) {
654 Register holder =
Leon Clarkef7060e22010-06-03 12:02:55 +0100655 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100656 scratch1, scratch2, name,
657 miss_label);
658
659 // Call a runtime function to load the interceptor property.
660 __ EnterInternalFrame();
661 // Save the name_ register across the call.
662 __ push(name_);
663
664 PushInterceptorArguments(masm,
665 receiver,
666 holder,
667 name_,
Leon Clarkef7060e22010-06-03 12:02:55 +0100668 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100669
670 __ CallExternalReference(
671 ExternalReference(
672 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
673 5);
674
675 // Restore the name_ register.
676 __ pop(name_);
677 __ LeaveInternalFrame();
678 }
679
680 void LoadWithInterceptor(MacroAssembler* masm,
681 Register receiver,
682 Register holder,
683 JSObject* holder_obj,
684 Register scratch,
685 Label* interceptor_succeeded) {
686 __ EnterInternalFrame();
687 __ Push(holder, name_);
688
689 CompileCallLoadPropertyWithInterceptor(masm,
690 receiver,
691 holder,
692 name_,
693 holder_obj);
694
695 __ pop(name_); // Restore the name.
696 __ pop(receiver); // Restore the holder.
697 __ LeaveInternalFrame();
698
699 // If interceptor returns no-result sentinel, call the constant function.
700 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
701 __ cmp(r0, scratch);
702 __ b(ne, interceptor_succeeded);
703 }
704
705 StubCompiler* stub_compiler_;
706 const ParameterCount& arguments_;
707 Register name_;
708};
709
710
711// Generate code to check that a global property cell is empty. Create
712// the property cell at compilation time if no cell exists for the
713// property.
714static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
715 GlobalObject* global,
716 String* name,
717 Register scratch,
718 Label* miss) {
719 Object* probe = global->EnsurePropertyCell(name);
720 if (probe->IsFailure()) return probe;
721 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
722 ASSERT(cell->value()->IsTheHole());
723 __ mov(scratch, Operand(Handle<Object>(cell)));
724 __ ldr(scratch,
725 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
726 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
727 __ cmp(scratch, ip);
728 __ b(ne, miss);
729 return cell;
730}
731
732
Steve Blocka7e24c12009-10-30 11:49:00 +0000733#undef __
734#define __ ACCESS_MASM(masm())
735
736
737Register StubCompiler::CheckPrototypes(JSObject* object,
738 Register object_reg,
739 JSObject* holder,
740 Register holder_reg,
741 Register scratch,
742 String* name,
Andrei Popescu402d9372010-02-26 13:31:12 +0000743 int save_at_depth,
Steve Blocka7e24c12009-10-30 11:49:00 +0000744 Label* miss) {
745 // Check that the maps haven't changed.
746 Register result =
Steve Block6ded16b2010-05-10 14:33:55 +0100747 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch,
748 save_at_depth, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000749
750 // If we've skipped any global objects, it's not enough to verify
Steve Block6ded16b2010-05-10 14:33:55 +0100751 // that their maps haven't changed. We also need to check that the
752 // property cell for the property is still empty.
Steve Blocka7e24c12009-10-30 11:49:00 +0000753 while (object != holder) {
754 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100755 Object* cell = GenerateCheckPropertyCell(masm(),
756 GlobalObject::cast(object),
757 name,
758 scratch,
759 miss);
760 if (cell->IsFailure()) {
761 set_failure(Failure::cast(cell));
Steve Blocka7e24c12009-10-30 11:49:00 +0000762 return result;
763 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000764 }
765 object = JSObject::cast(object->GetPrototype());
766 }
767
Andrei Popescu402d9372010-02-26 13:31:12 +0000768 // Return the register containing the holder.
Steve Blocka7e24c12009-10-30 11:49:00 +0000769 return result;
770}
771
772
773void StubCompiler::GenerateLoadField(JSObject* object,
774 JSObject* holder,
775 Register receiver,
776 Register scratch1,
777 Register scratch2,
778 int index,
779 String* name,
780 Label* miss) {
781 // Check that the receiver isn't a smi.
782 __ tst(receiver, Operand(kSmiTagMask));
783 __ b(eq, miss);
784
785 // Check that the maps haven't changed.
786 Register reg =
787 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
788 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
789 __ Ret();
790}
791
792
793void StubCompiler::GenerateLoadConstant(JSObject* object,
794 JSObject* holder,
795 Register receiver,
796 Register scratch1,
797 Register scratch2,
798 Object* value,
799 String* name,
800 Label* miss) {
801 // Check that the receiver isn't a smi.
802 __ tst(receiver, Operand(kSmiTagMask));
803 __ b(eq, miss);
804
805 // Check that the maps haven't changed.
806 Register reg =
807 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
808
809 // Return the constant value.
810 __ mov(r0, Operand(Handle<Object>(value)));
811 __ Ret();
812}
813
814
Leon Clarkee46be812010-01-19 14:06:41 +0000815bool StubCompiler::GenerateLoadCallback(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +0000816 JSObject* holder,
817 Register receiver,
818 Register name_reg,
819 Register scratch1,
820 Register scratch2,
821 AccessorInfo* callback,
822 String* name,
Leon Clarkee46be812010-01-19 14:06:41 +0000823 Label* miss,
824 Failure** failure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000825 // Check that the receiver isn't a smi.
826 __ tst(receiver, Operand(kSmiTagMask));
827 __ b(eq, miss);
828
829 // Check that the maps haven't changed.
830 Register reg =
831 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
832
833 // Push the arguments on the JS stack of the caller.
Steve Block6ded16b2010-05-10 14:33:55 +0100834 __ push(receiver); // Receiver.
835 __ push(reg); // Holder.
Steve Blocka7e24c12009-10-30 11:49:00 +0000836 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
Steve Blocka7e24c12009-10-30 11:49:00 +0000837 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
Steve Block6ded16b2010-05-10 14:33:55 +0100838 __ Push(ip, reg, name_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000839
840 // Do tail-call to the runtime system.
841 ExternalReference load_callback_property =
842 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +0100843 __ TailCallExternalReference(load_callback_property, 5, 1);
Leon Clarkee46be812010-01-19 14:06:41 +0000844
845 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000846}
847
848
849void StubCompiler::GenerateLoadInterceptor(JSObject* object,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100850 JSObject* interceptor_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000851 LookupResult* lookup,
852 Register receiver,
853 Register name_reg,
854 Register scratch1,
855 Register scratch2,
856 String* name,
857 Label* miss) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100858 ASSERT(interceptor_holder->HasNamedInterceptor());
859 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
860
861 // Check that the receiver isn't a smi.
862 __ BranchOnSmi(receiver, miss);
863
864 // So far the most popular follow ups for interceptor loads are FIELD
865 // and CALLBACKS, so inline only them, other cases may be added
866 // later.
867 bool compile_followup_inline = false;
868 if (lookup->IsProperty() && lookup->IsCacheable()) {
869 if (lookup->type() == FIELD) {
870 compile_followup_inline = true;
871 } else if (lookup->type() == CALLBACKS &&
872 lookup->GetCallbackObject()->IsAccessorInfo() &&
873 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
874 compile_followup_inline = true;
875 }
876 }
877
878 if (compile_followup_inline) {
879 // Compile the interceptor call, followed by inline code to load the
880 // property from further up the prototype chain if the call fails.
881 // Check that the maps haven't changed.
882 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
883 scratch1, scratch2, name, miss);
884 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
885
886 // Save necessary data before invoking an interceptor.
887 // Requires a frame to make GC aware of pushed pointers.
888 __ EnterInternalFrame();
889
890 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
891 // CALLBACKS case needs a receiver to be passed into C++ callback.
892 __ Push(receiver, holder_reg, name_reg);
893 } else {
894 __ Push(holder_reg, name_reg);
895 }
896
897 // Invoke an interceptor. Note: map checks from receiver to
898 // interceptor's holder has been compiled before (see a caller
899 // of this method.)
900 CompileCallLoadPropertyWithInterceptor(masm(),
901 receiver,
902 holder_reg,
903 name_reg,
904 interceptor_holder);
905
906 // Check if interceptor provided a value for property. If it's
907 // the case, return immediately.
908 Label interceptor_failed;
909 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
910 __ cmp(r0, scratch1);
911 __ b(eq, &interceptor_failed);
912 __ LeaveInternalFrame();
913 __ Ret();
914
915 __ bind(&interceptor_failed);
916 __ pop(name_reg);
917 __ pop(holder_reg);
918 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
919 __ pop(receiver);
920 }
921
922 __ LeaveInternalFrame();
923
924 // Check that the maps from interceptor's holder to lookup's holder
925 // haven't changed. And load lookup's holder into |holder| register.
926 if (interceptor_holder != lookup->holder()) {
927 holder_reg = CheckPrototypes(interceptor_holder,
928 holder_reg,
929 lookup->holder(),
930 scratch1,
931 scratch2,
932 name,
933 miss);
934 }
935
936 if (lookup->type() == FIELD) {
937 // We found FIELD property in prototype chain of interceptor's holder.
938 // Retrieve a field from field's holder.
939 GenerateFastPropertyLoad(masm(), r0, holder_reg,
940 lookup->holder(), lookup->GetFieldIndex());
941 __ Ret();
942 } else {
943 // We found CALLBACKS property in prototype chain of interceptor's
944 // holder.
945 ASSERT(lookup->type() == CALLBACKS);
946 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
947 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
948 ASSERT(callback != NULL);
949 ASSERT(callback->getter() != NULL);
950
951 // Tail call to runtime.
952 // Important invariant in CALLBACKS case: the code above must be
953 // structured to never clobber |receiver| register.
954 __ Move(scratch2, Handle<AccessorInfo>(callback));
955 // holder_reg is either receiver or scratch1.
956 if (!receiver.is(holder_reg)) {
957 ASSERT(scratch1.is(holder_reg));
958 __ Push(receiver, holder_reg, scratch2);
959 __ ldr(scratch1,
960 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
961 __ Push(scratch1, name_reg);
962 } else {
963 __ push(receiver);
964 __ ldr(scratch1,
965 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
966 __ Push(holder_reg, scratch2, scratch1, name_reg);
967 }
968
969 ExternalReference ref =
970 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
971 __ TailCallExternalReference(ref, 5, 1);
972 }
973 } else { // !compile_followup_inline
974 // Call the runtime system to load the interceptor.
975 // Check that the maps haven't changed.
976 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
977 scratch1, scratch2, name, miss);
978 PushInterceptorArguments(masm(), receiver, holder_reg,
979 name_reg, interceptor_holder);
980
981 ExternalReference ref = ExternalReference(
982 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
983 __ TailCallExternalReference(ref, 5, 1);
984 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000985}
986
987
988Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
989 // ----------- S t a t e -------------
990 // -- r1: function
991 // -- lr: return address
992 // -----------------------------------
993
994 // Enter an internal frame.
995 __ EnterInternalFrame();
996
997 // Preserve the function.
998 __ push(r1);
999
1000 // Push the function on the stack as the argument to the runtime function.
1001 __ push(r1);
1002 __ CallRuntime(Runtime::kLazyCompile, 1);
1003
1004 // Calculate the entry point.
1005 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
1006
1007 // Restore saved function.
1008 __ pop(r1);
1009
1010 // Tear down temporary frame.
1011 __ LeaveInternalFrame();
1012
1013 // Do a tail-call of the compiled function.
1014 __ Jump(r2);
1015
1016 return GetCodeWithFlags(flags, "LazyCompileStub");
1017}
1018
1019
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001020void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
1021 if (kind_ == Code::KEYED_CALL_IC) {
1022 __ cmp(r2, Operand(Handle<String>(name)));
1023 __ b(ne, miss);
1024 }
1025}
1026
1027
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001028void CallStubCompiler::GenerateMissBranch() {
1029 Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_);
1030 __ Jump(ic, RelocInfo::CODE_TARGET);
1031}
1032
1033
Andrei Popescu402d9372010-02-26 13:31:12 +00001034Object* CallStubCompiler::CompileCallField(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001035 JSObject* holder,
1036 int index,
1037 String* name) {
1038 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001039 // -- r2 : name
1040 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001041 // -----------------------------------
1042 Label miss;
1043
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001044 GenerateNameCheck(name, &miss);
1045
Steve Blocka7e24c12009-10-30 11:49:00 +00001046 const int argc = arguments().immediate();
1047
1048 // Get the receiver of the function from the stack into r0.
1049 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1050 // Check that the receiver isn't a smi.
1051 __ tst(r0, Operand(kSmiTagMask));
1052 __ b(eq, &miss);
1053
1054 // Do the right check and compute the holder register.
Andrei Popescu402d9372010-02-26 13:31:12 +00001055 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001056 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
1057
Leon Clarke4515c472010-02-03 11:58:03 +00001058 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001059
1060 // Handle call cache miss.
1061 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001062 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001063
1064 // Return the generated code.
1065 return GetCode(FIELD, name);
1066}
1067
1068
Steve Block6ded16b2010-05-10 14:33:55 +01001069Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1070 JSObject* holder,
1071 JSFunction* function,
1072 String* name,
1073 CheckType check) {
1074 // ----------- S t a t e -------------
1075 // -- r2 : name
1076 // -- lr : return address
1077 // -----------------------------------
1078
1079 // If object is not an array, bail out to regular call.
1080 if (!object->IsJSArray()) {
1081 return Heap::undefined_value();
1082 }
1083
1084 // TODO(639): faster implementation.
1085 ASSERT(check == RECEIVER_MAP_CHECK);
1086
1087 Label miss;
1088
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001089 GenerateNameCheck(name, &miss);
1090
Steve Block6ded16b2010-05-10 14:33:55 +01001091 // Get the receiver from the stack
1092 const int argc = arguments().immediate();
1093 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1094
1095 // Check that the receiver isn't a smi.
1096 __ tst(r1, Operand(kSmiTagMask));
1097 __ b(eq, &miss);
1098
1099 // Check that the maps haven't changed.
1100 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1101
1102 if (object->IsGlobalObject()) {
1103 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1104 __ str(r3, MemOperand(sp, argc * kPointerSize));
1105 }
1106
1107 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1108 argc + 1,
1109 1);
1110
1111 // Handle call cache miss.
1112 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001113 GenerateMissBranch();
Steve Block6ded16b2010-05-10 14:33:55 +01001114
1115 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001116 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001117}
1118
1119
1120Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1121 JSObject* holder,
1122 JSFunction* function,
1123 String* name,
1124 CheckType check) {
1125 // ----------- S t a t e -------------
1126 // -- r2 : name
1127 // -- lr : return address
1128 // -----------------------------------
1129
1130 // If object is not an array, bail out to regular call.
1131 if (!object->IsJSArray()) {
1132 return Heap::undefined_value();
1133 }
1134
1135 // TODO(642): faster implementation.
1136 ASSERT(check == RECEIVER_MAP_CHECK);
1137
1138 Label miss;
1139
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001140 GenerateNameCheck(name, &miss);
1141
Steve Block6ded16b2010-05-10 14:33:55 +01001142 // Get the receiver from the stack
1143 const int argc = arguments().immediate();
1144 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1145
1146 // Check that the receiver isn't a smi.
1147 __ tst(r1, Operand(kSmiTagMask));
1148 __ b(eq, &miss);
1149
1150 // Check that the maps haven't changed.
1151 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1152
1153 if (object->IsGlobalObject()) {
1154 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1155 __ str(r3, MemOperand(sp, argc * kPointerSize));
1156 }
1157
1158 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1159 argc + 1,
1160 1);
1161
1162 // Handle call cache miss.
1163 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001164 GenerateMissBranch();
Steve Block6ded16b2010-05-10 14:33:55 +01001165
1166 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001167 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001168}
1169
1170
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001171Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
1172 JSObject* holder,
1173 JSFunction* function,
1174 String* name,
1175 CheckType check) {
1176 // TODO(722): implement this.
1177 return Heap::undefined_value();
1178}
1179
1180
1181Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
1182 JSObject* holder,
1183 JSFunction* function,
1184 String* name,
1185 CheckType check) {
1186 // TODO(722): implement this.
1187 return Heap::undefined_value();
1188}
1189
1190
Steve Blocka7e24c12009-10-30 11:49:00 +00001191Object* CallStubCompiler::CompileCallConstant(Object* object,
1192 JSObject* holder,
1193 JSFunction* function,
1194 String* name,
1195 CheckType check) {
1196 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001197 // -- r2 : name
1198 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001199 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001200 SharedFunctionInfo* function_info = function->shared();
1201 if (function_info->HasCustomCallGenerator()) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001202 const int id = function_info->custom_call_generator_id();
1203 Object* result =
1204 CompileCustomCall(id, object, holder, function, name, check);
Steve Block6ded16b2010-05-10 14:33:55 +01001205 // undefined means bail out to regular compiler.
1206 if (!result->IsUndefined()) {
1207 return result;
1208 }
1209 }
1210
1211 Label miss_in_smi_check;
Steve Blocka7e24c12009-10-30 11:49:00 +00001212
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001213 GenerateNameCheck(name, &miss_in_smi_check);
1214
Steve Blocka7e24c12009-10-30 11:49:00 +00001215 // Get the receiver from the stack
1216 const int argc = arguments().immediate();
1217 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1218
1219 // Check that the receiver isn't a smi.
1220 if (check != NUMBER_CHECK) {
1221 __ tst(r1, Operand(kSmiTagMask));
Steve Block6ded16b2010-05-10 14:33:55 +01001222 __ b(eq, &miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001223 }
1224
1225 // Make sure that it's okay not to patch the on stack receiver
1226 // unless we're doing a receiver map check.
1227 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1228
Steve Block6ded16b2010-05-10 14:33:55 +01001229 CallOptimization optimization(function);
1230 int depth = kInvalidProtoDepth;
1231 Label miss;
1232
Steve Blocka7e24c12009-10-30 11:49:00 +00001233 switch (check) {
1234 case RECEIVER_MAP_CHECK:
Steve Block6ded16b2010-05-10 14:33:55 +01001235 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1236
1237 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1238 depth = optimization.GetPrototypeDepthOfExpectedType(
1239 JSObject::cast(object), holder);
1240 }
1241
1242 if (depth != kInvalidProtoDepth) {
1243 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1244 ReserveSpaceForFastApiCall(masm(), r0);
1245 }
1246
Steve Blocka7e24c12009-10-30 11:49:00 +00001247 // Check that the maps haven't changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001248 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, name,
1249 depth, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001250
1251 // Patch the receiver on the stack with the global proxy if
1252 // necessary.
1253 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001254 ASSERT(depth == kInvalidProtoDepth);
Steve Blocka7e24c12009-10-30 11:49:00 +00001255 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1256 __ str(r3, MemOperand(sp, argc * kPointerSize));
1257 }
1258 break;
1259
1260 case STRING_CHECK:
Leon Clarkee46be812010-01-19 14:06:41 +00001261 if (!function->IsBuiltin()) {
1262 // Calling non-builtins with a value as receiver requires boxing.
1263 __ jmp(&miss);
1264 } else {
1265 // Check that the object is a two-byte string or a symbol.
Andrei Popescu402d9372010-02-26 13:31:12 +00001266 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001267 __ b(hs, &miss);
1268 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001269 GenerateDirectLoadGlobalFunctionPrototype(
1270 masm(), Context::STRING_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001271 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001272 r1, name, &miss);
1273 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001274 break;
1275
1276 case NUMBER_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001277 if (!function->IsBuiltin()) {
1278 // Calling non-builtins with a value as receiver requires boxing.
1279 __ jmp(&miss);
1280 } else {
1281 Label fast;
1282 // Check that the object is a smi or a heap number.
1283 __ tst(r1, Operand(kSmiTagMask));
1284 __ b(eq, &fast);
Andrei Popescu402d9372010-02-26 13:31:12 +00001285 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001286 __ b(ne, &miss);
1287 __ bind(&fast);
1288 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001289 GenerateDirectLoadGlobalFunctionPrototype(
1290 masm(), Context::NUMBER_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001291 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001292 r1, name, &miss);
1293 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001294 break;
1295 }
1296
1297 case BOOLEAN_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001298 if (!function->IsBuiltin()) {
1299 // Calling non-builtins with a value as receiver requires boxing.
1300 __ jmp(&miss);
1301 } else {
1302 Label fast;
1303 // Check that the object is a boolean.
1304 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1305 __ cmp(r1, ip);
1306 __ b(eq, &fast);
1307 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1308 __ cmp(r1, ip);
1309 __ b(ne, &miss);
1310 __ bind(&fast);
1311 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001312 GenerateDirectLoadGlobalFunctionPrototype(
1313 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001314 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001315 r1, name, &miss);
1316 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001317 break;
1318 }
1319
Steve Blocka7e24c12009-10-30 11:49:00 +00001320 default:
1321 UNREACHABLE();
1322 }
1323
Steve Block6ded16b2010-05-10 14:33:55 +01001324 if (depth != kInvalidProtoDepth) {
1325 GenerateFastApiCall(masm(), optimization, argc);
1326 } else {
1327 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1328 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001329
1330 // Handle call cache miss.
1331 __ bind(&miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001332 if (depth != kInvalidProtoDepth) {
1333 FreeSpaceForFastApiCall(masm());
1334 }
1335
1336 __ bind(&miss_in_smi_check);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001337 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001338
1339 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001340 return GetCode(function);
Steve Blocka7e24c12009-10-30 11:49:00 +00001341}
1342
1343
Andrei Popescu402d9372010-02-26 13:31:12 +00001344Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001345 JSObject* holder,
1346 String* name) {
1347 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001348 // -- r2 : name
1349 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001350 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001351
Steve Block6ded16b2010-05-10 14:33:55 +01001352 Label miss;
Andrei Popescu402d9372010-02-26 13:31:12 +00001353
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001354 GenerateNameCheck(name, &miss);
1355
Leon Clarke4515c472010-02-03 11:58:03 +00001356 // Get the number of arguments.
1357 const int argc = arguments().immediate();
1358
1359 LookupResult lookup;
1360 LookupPostInterceptor(holder, name, &lookup);
1361
Steve Block6ded16b2010-05-10 14:33:55 +01001362 // Get the receiver from the stack.
1363 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001364
Steve Block6ded16b2010-05-10 14:33:55 +01001365 CallInterceptorCompiler compiler(this, arguments(), r2);
1366 compiler.Compile(masm(),
1367 object,
1368 holder,
1369 name,
1370 &lookup,
1371 r1,
1372 r3,
1373 r4,
1374 &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001375
1376 // Move returned value, the function to call, to r1.
1377 __ mov(r1, r0);
Leon Clarke4515c472010-02-03 11:58:03 +00001378 // Restore receiver.
Steve Block6ded16b2010-05-10 14:33:55 +01001379 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001380
1381 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001382
1383 // Handle call cache miss.
1384 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001385 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001386
1387 // Return the generated code.
1388 return GetCode(INTERCEPTOR, name);
1389}
1390
1391
1392Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1393 GlobalObject* holder,
1394 JSGlobalPropertyCell* cell,
1395 JSFunction* function,
1396 String* name) {
1397 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001398 // -- r2 : name
1399 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001400 // -----------------------------------
1401 Label miss;
1402
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001403 GenerateNameCheck(name, &miss);
1404
Steve Blocka7e24c12009-10-30 11:49:00 +00001405 // Get the number of arguments.
1406 const int argc = arguments().immediate();
1407
1408 // Get the receiver from the stack.
1409 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1410
1411 // If the object is the holder then we know that it's a global
1412 // object which can only happen for contextual calls. In this case,
1413 // the receiver cannot be a smi.
1414 if (object != holder) {
1415 __ tst(r0, Operand(kSmiTagMask));
1416 __ b(eq, &miss);
1417 }
1418
1419 // Check that the maps haven't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001420 CheckPrototypes(object, r0, holder, r3, r1, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001421
1422 // Get the value from the cell.
1423 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1424 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1425
1426 // Check that the cell contains the same function.
Leon Clarkee46be812010-01-19 14:06:41 +00001427 if (Heap::InNewSpace(function)) {
1428 // We can't embed a pointer to a function in new space so we have
1429 // to verify that the shared function info is unchanged. This has
1430 // the nice side effect that multiple closures based on the same
1431 // function can all use this call IC. Before we load through the
1432 // function, we have to verify that it still is a function.
1433 __ tst(r1, Operand(kSmiTagMask));
1434 __ b(eq, &miss);
1435 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1436 __ b(ne, &miss);
1437
1438 // Check the shared function info. Make sure it hasn't changed.
1439 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
Andrei Popescu402d9372010-02-26 13:31:12 +00001440 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1441 __ cmp(r4, r3);
Leon Clarkee46be812010-01-19 14:06:41 +00001442 __ b(ne, &miss);
1443 } else {
1444 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1445 __ b(ne, &miss);
1446 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001447
1448 // Patch the receiver on the stack with the global proxy if
1449 // necessary.
1450 if (object->IsGlobalObject()) {
1451 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1452 __ str(r3, MemOperand(sp, argc * kPointerSize));
1453 }
1454
1455 // Setup the context (function already in r1).
1456 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1457
1458 // Jump to the cached code (tail call).
Steve Block6ded16b2010-05-10 14:33:55 +01001459 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001460 ASSERT(function->is_compiled());
1461 Handle<Code> code(function->code());
1462 ParameterCount expected(function->shared()->formal_parameter_count());
1463 __ InvokeCode(code, expected, arguments(),
1464 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1465
1466 // Handle call cache miss.
1467 __ bind(&miss);
1468 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001469 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001470
1471 // Return the generated code.
1472 return GetCode(NORMAL, name);
1473}
1474
1475
1476Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1477 int index,
1478 Map* transition,
1479 String* name) {
1480 // ----------- S t a t e -------------
1481 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001482 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001483 // -- r2 : name
1484 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001485 // -----------------------------------
1486 Label miss;
1487
Steve Blocka7e24c12009-10-30 11:49:00 +00001488 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001489 object,
1490 index,
1491 transition,
Andrei Popescu402d9372010-02-26 13:31:12 +00001492 r1, r2, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001493 &miss);
1494 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001495 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1496 __ Jump(ic, RelocInfo::CODE_TARGET);
1497
1498 // Return the generated code.
1499 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1500}
1501
1502
1503Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1504 AccessorInfo* callback,
1505 String* name) {
1506 // ----------- S t a t e -------------
1507 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001508 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001509 // -- r2 : name
1510 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001511 // -----------------------------------
1512 Label miss;
1513
Steve Blocka7e24c12009-10-30 11:49:00 +00001514 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001515 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001516 __ b(eq, &miss);
1517
1518 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001519 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1520 __ cmp(r3, Operand(Handle<Map>(object->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001521 __ b(ne, &miss);
1522
1523 // Perform global security token check if needed.
1524 if (object->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001525 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001526 }
1527
1528 // Stub never generated for non-global objects that require access
1529 // checks.
1530 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1531
Andrei Popescu402d9372010-02-26 13:31:12 +00001532 __ push(r1); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001533 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
Steve Block6ded16b2010-05-10 14:33:55 +01001534 __ Push(ip, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001535
1536 // Do tail-call to the runtime system.
1537 ExternalReference store_callback_property =
1538 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001539 __ TailCallExternalReference(store_callback_property, 4, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001540
1541 // Handle store cache miss.
1542 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001543 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1544 __ Jump(ic, RelocInfo::CODE_TARGET);
1545
1546 // Return the generated code.
1547 return GetCode(CALLBACKS, name);
1548}
1549
1550
1551Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1552 String* name) {
1553 // ----------- S t a t e -------------
1554 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001555 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001556 // -- r2 : name
1557 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001558 // -----------------------------------
1559 Label miss;
1560
Steve Blocka7e24c12009-10-30 11:49:00 +00001561 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001562 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001563 __ b(eq, &miss);
1564
1565 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001566 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1567 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001568 __ b(ne, &miss);
1569
1570 // Perform global security token check if needed.
1571 if (receiver->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001572 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001573 }
1574
Andrei Popescu402d9372010-02-26 13:31:12 +00001575 // Stub is never generated for non-global objects that require access
Steve Blocka7e24c12009-10-30 11:49:00 +00001576 // checks.
1577 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1578
Steve Block6ded16b2010-05-10 14:33:55 +01001579 __ Push(r1, r2, r0); // Receiver, name, value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001580
1581 // Do tail-call to the runtime system.
1582 ExternalReference store_ic_property =
1583 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001584 __ TailCallExternalReference(store_ic_property, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001585
1586 // Handle store cache miss.
1587 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001588 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1589 __ Jump(ic, RelocInfo::CODE_TARGET);
1590
1591 // Return the generated code.
1592 return GetCode(INTERCEPTOR, name);
1593}
1594
1595
1596Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1597 JSGlobalPropertyCell* cell,
1598 String* name) {
1599 // ----------- S t a t e -------------
1600 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001601 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001602 // -- r2 : name
1603 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001604 // -----------------------------------
1605 Label miss;
1606
1607 // Check that the map of the global has not changed.
Steve Blocka7e24c12009-10-30 11:49:00 +00001608 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1609 __ cmp(r3, Operand(Handle<Map>(object->map())));
1610 __ b(ne, &miss);
1611
1612 // Store the value in the cell.
1613 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1614 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
1615
Andrei Popescu402d9372010-02-26 13:31:12 +00001616 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001617 __ Ret();
1618
1619 // Handle store cache miss.
1620 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001621 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001622 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1623 __ Jump(ic, RelocInfo::CODE_TARGET);
1624
1625 // Return the generated code.
1626 return GetCode(NORMAL, name);
1627}
1628
1629
Steve Block6ded16b2010-05-10 14:33:55 +01001630Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1631 JSObject* object,
1632 JSObject* last) {
1633 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001634 // -- r0 : receiver
Steve Block6ded16b2010-05-10 14:33:55 +01001635 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001636 // -----------------------------------
1637 Label miss;
1638
Steve Block6ded16b2010-05-10 14:33:55 +01001639 // Check that receiver is not a smi.
1640 __ tst(r0, Operand(kSmiTagMask));
1641 __ b(eq, &miss);
1642
1643 // Check the maps of the full prototype chain.
1644 CheckPrototypes(object, r0, last, r3, r1, name, &miss);
1645
1646 // If the last object in the prototype chain is a global object,
1647 // check that the global property cell is empty.
1648 if (last->IsGlobalObject()) {
1649 Object* cell = GenerateCheckPropertyCell(masm(),
1650 GlobalObject::cast(last),
1651 name,
1652 r1,
1653 &miss);
1654 if (cell->IsFailure()) return cell;
1655 }
1656
1657 // Return undefined if maps of the full prototype chain are still the
1658 // same and no global property with this name contains a value.
1659 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1660 __ Ret();
1661
1662 __ bind(&miss);
1663 GenerateLoadMiss(masm(), Code::LOAD_IC);
1664
1665 // Return the generated code.
1666 return GetCode(NONEXISTENT, Heap::empty_string());
1667}
1668
1669
Steve Blocka7e24c12009-10-30 11:49:00 +00001670Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1671 JSObject* holder,
1672 int index,
1673 String* name) {
1674 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001675 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001676 // -- r2 : name
1677 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001678 // -----------------------------------
1679 Label miss;
1680
Steve Blocka7e24c12009-10-30 11:49:00 +00001681 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
1682 __ bind(&miss);
1683 GenerateLoadMiss(masm(), Code::LOAD_IC);
1684
1685 // Return the generated code.
1686 return GetCode(FIELD, name);
1687}
1688
1689
Leon Clarkee46be812010-01-19 14:06:41 +00001690Object* LoadStubCompiler::CompileLoadCallback(String* name,
1691 JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001692 JSObject* holder,
Leon Clarkee46be812010-01-19 14:06:41 +00001693 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001694 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001695 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001696 // -- r2 : name
1697 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001698 // -----------------------------------
1699 Label miss;
1700
Leon Clarkee46be812010-01-19 14:06:41 +00001701 Failure* failure = Failure::InternalError();
1702 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
1703 callback, name, &miss, &failure);
1704 if (!success) return failure;
1705
Steve Blocka7e24c12009-10-30 11:49:00 +00001706 __ bind(&miss);
1707 GenerateLoadMiss(masm(), Code::LOAD_IC);
1708
1709 // Return the generated code.
1710 return GetCode(CALLBACKS, name);
1711}
1712
1713
1714Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1715 JSObject* holder,
1716 Object* value,
1717 String* name) {
1718 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001719 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001720 // -- r2 : name
1721 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001722 // -----------------------------------
1723 Label miss;
1724
Steve Blocka7e24c12009-10-30 11:49:00 +00001725 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
1726 __ bind(&miss);
1727 GenerateLoadMiss(masm(), Code::LOAD_IC);
1728
1729 // Return the generated code.
1730 return GetCode(CONSTANT_FUNCTION, name);
1731}
1732
1733
1734Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1735 JSObject* holder,
1736 String* name) {
1737 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001738 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001739 // -- r2 : name
1740 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001741 // -----------------------------------
1742 Label miss;
1743
Steve Blocka7e24c12009-10-30 11:49:00 +00001744 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001745 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001746 GenerateLoadInterceptor(object,
1747 holder,
1748 &lookup,
1749 r0,
1750 r2,
1751 r3,
1752 r1,
1753 name,
1754 &miss);
1755 __ bind(&miss);
1756 GenerateLoadMiss(masm(), Code::LOAD_IC);
1757
1758 // Return the generated code.
1759 return GetCode(INTERCEPTOR, name);
1760}
1761
1762
1763Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1764 GlobalObject* holder,
1765 JSGlobalPropertyCell* cell,
1766 String* name,
1767 bool is_dont_delete) {
1768 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001769 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001770 // -- r2 : name
1771 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001772 // -----------------------------------
1773 Label miss;
1774
Steve Blocka7e24c12009-10-30 11:49:00 +00001775 // If the object is the holder then we know that it's a global
1776 // object which can only happen for contextual calls. In this case,
1777 // the receiver cannot be a smi.
1778 if (object != holder) {
Steve Block6ded16b2010-05-10 14:33:55 +01001779 __ tst(r0, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001780 __ b(eq, &miss);
1781 }
1782
1783 // Check that the map of the global has not changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001784 CheckPrototypes(object, r0, holder, r3, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001785
1786 // Get the value from the cell.
1787 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
Steve Block6ded16b2010-05-10 14:33:55 +01001788 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001789
1790 // Check for deleted property if property can actually be deleted.
1791 if (!is_dont_delete) {
1792 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
Steve Block6ded16b2010-05-10 14:33:55 +01001793 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00001794 __ b(eq, &miss);
1795 }
1796
Steve Block6ded16b2010-05-10 14:33:55 +01001797 __ mov(r0, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001798 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1799 __ Ret();
1800
1801 __ bind(&miss);
1802 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1803 GenerateLoadMiss(masm(), Code::LOAD_IC);
1804
1805 // Return the generated code.
1806 return GetCode(NORMAL, name);
1807}
1808
1809
1810Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1811 JSObject* receiver,
1812 JSObject* holder,
1813 int index) {
1814 // ----------- S t a t e -------------
1815 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001816 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001817 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001818 // -----------------------------------
1819 Label miss;
1820
Steve Block6ded16b2010-05-10 14:33:55 +01001821 // Check the key is the cached one.
1822 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001823 __ b(ne, &miss);
1824
Steve Block6ded16b2010-05-10 14:33:55 +01001825 GenerateLoadField(receiver, holder, r1, r2, r3, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001826 __ bind(&miss);
1827 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1828
1829 return GetCode(FIELD, name);
1830}
1831
1832
1833Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1834 JSObject* receiver,
1835 JSObject* holder,
1836 AccessorInfo* callback) {
1837 // ----------- S t a t e -------------
1838 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001839 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001840 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001841 // -----------------------------------
1842 Label miss;
1843
Steve Block6ded16b2010-05-10 14:33:55 +01001844 // Check the key is the cached one.
1845 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001846 __ b(ne, &miss);
1847
Leon Clarkee46be812010-01-19 14:06:41 +00001848 Failure* failure = Failure::InternalError();
Steve Block6ded16b2010-05-10 14:33:55 +01001849 bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001850 callback, name, &miss, &failure);
1851 if (!success) return failure;
1852
Steve Blocka7e24c12009-10-30 11:49:00 +00001853 __ bind(&miss);
1854 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1855
1856 return GetCode(CALLBACKS, name);
1857}
1858
1859
1860Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1861 JSObject* receiver,
1862 JSObject* holder,
1863 Object* value) {
1864 // ----------- S t a t e -------------
1865 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001866 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001867 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001868 // -----------------------------------
1869 Label miss;
1870
Steve Block6ded16b2010-05-10 14:33:55 +01001871 // Check the key is the cached one.
1872 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001873 __ b(ne, &miss);
1874
Steve Block6ded16b2010-05-10 14:33:55 +01001875 GenerateLoadConstant(receiver, holder, r1, r2, r3, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001876 __ bind(&miss);
1877 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1878
1879 // Return the generated code.
1880 return GetCode(CONSTANT_FUNCTION, name);
1881}
1882
1883
1884Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1885 JSObject* holder,
1886 String* name) {
1887 // ----------- S t a t e -------------
1888 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001889 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001890 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001891 // -----------------------------------
1892 Label miss;
1893
Steve Block6ded16b2010-05-10 14:33:55 +01001894 // Check the key is the cached one.
1895 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001896 __ b(ne, &miss);
1897
1898 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001899 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001900 GenerateLoadInterceptor(receiver,
1901 holder,
1902 &lookup,
Steve Block6ded16b2010-05-10 14:33:55 +01001903 r1,
Steve Blocka7e24c12009-10-30 11:49:00 +00001904 r0,
1905 r2,
1906 r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001907 name,
1908 &miss);
1909 __ bind(&miss);
1910 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1911
1912 return GetCode(INTERCEPTOR, name);
1913}
1914
1915
1916Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1917 // ----------- S t a t e -------------
1918 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001919 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001920 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001921 // -----------------------------------
1922 Label miss;
1923
Steve Block6ded16b2010-05-10 14:33:55 +01001924 // Check the key is the cached one.
1925 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001926 __ b(ne, &miss);
1927
Steve Block6ded16b2010-05-10 14:33:55 +01001928 GenerateLoadArrayLength(masm(), r1, r2, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001929 __ bind(&miss);
1930 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1931
1932 return GetCode(CALLBACKS, name);
1933}
1934
1935
1936Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
1937 // ----------- S t a t e -------------
1938 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001939 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001940 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001941 // -----------------------------------
1942 Label miss;
1943 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1944
Steve Block6ded16b2010-05-10 14:33:55 +01001945 // Check the key is the cached one.
1946 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001947 __ b(ne, &miss);
1948
Steve Block6ded16b2010-05-10 14:33:55 +01001949 GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001950 __ bind(&miss);
1951 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1952
1953 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1954
1955 return GetCode(CALLBACKS, name);
1956}
1957
1958
1959// TODO(1224671): implement the fast case.
1960Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1961 // ----------- S t a t e -------------
1962 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001963 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001964 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001965 // -----------------------------------
1966 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1967
1968 return GetCode(CALLBACKS, name);
1969}
1970
1971
1972Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1973 int index,
1974 Map* transition,
1975 String* name) {
1976 // ----------- S t a t e -------------
1977 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01001978 // -- r1 : key
1979 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001980 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001981 // -----------------------------------
1982 Label miss;
1983
Leon Clarkef7060e22010-06-03 12:02:55 +01001984 __ IncrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001985
1986 // Check that the name has not changed.
Leon Clarkef7060e22010-06-03 12:02:55 +01001987 __ cmp(r1, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001988 __ b(ne, &miss);
1989
Leon Clarkef7060e22010-06-03 12:02:55 +01001990 // r3 is used as scratch register. r1 and r2 keep their values if a jump to
1991 // the miss label is generated.
Steve Blocka7e24c12009-10-30 11:49:00 +00001992 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001993 object,
1994 index,
1995 transition,
Leon Clarkef7060e22010-06-03 12:02:55 +01001996 r2, r1, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001997 &miss);
1998 __ bind(&miss);
1999
Leon Clarkef7060e22010-06-03 12:02:55 +01002000 __ DecrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002001 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
Leon Clarkef7060e22010-06-03 12:02:55 +01002002
Steve Blocka7e24c12009-10-30 11:49:00 +00002003 __ Jump(ic, RelocInfo::CODE_TARGET);
2004
2005 // Return the generated code.
2006 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2007}
2008
2009
2010Object* ConstructStubCompiler::CompileConstructStub(
2011 SharedFunctionInfo* shared) {
2012 // ----------- S t a t e -------------
2013 // -- r0 : argc
2014 // -- r1 : constructor
2015 // -- lr : return address
2016 // -- [sp] : last argument
2017 // -----------------------------------
2018 Label generic_stub_call;
2019
2020 // Use r7 for holding undefined which is used in several places below.
2021 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2022
2023#ifdef ENABLE_DEBUGGER_SUPPORT
2024 // Check to see whether there are any break points in the function code. If
2025 // there are jump to the generic constructor stub which calls the actual
2026 // code for the function thereby hitting the break points.
2027 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2028 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2029 __ cmp(r2, r7);
2030 __ b(ne, &generic_stub_call);
2031#endif
2032
2033 // Load the initial map and verify that it is in fact a map.
2034 // r1: constructor function
2035 // r7: undefined
2036 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2037 __ tst(r2, Operand(kSmiTagMask));
2038 __ b(eq, &generic_stub_call);
2039 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2040 __ b(ne, &generic_stub_call);
2041
2042#ifdef DEBUG
2043 // Cannot construct functions this way.
2044 // r0: argc
2045 // r1: constructor function
2046 // r2: initial map
2047 // r7: undefined
2048 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2049 __ Check(ne, "Function constructed by construct stub.");
2050#endif
2051
2052 // Now allocate the JSObject in new space.
2053 // r0: argc
2054 // r1: constructor function
2055 // r2: initial map
2056 // r7: undefined
2057 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
2058 __ AllocateInNewSpace(r3,
2059 r4,
2060 r5,
2061 r6,
2062 &generic_stub_call,
Kristian Monsen25f61362010-05-21 11:50:48 +01002063 SIZE_IN_WORDS);
Steve Blocka7e24c12009-10-30 11:49:00 +00002064
2065 // Allocated the JSObject, now initialize the fields. Map is set to initial
2066 // map and properties and elements are set to empty fixed array.
2067 // r0: argc
2068 // r1: constructor function
2069 // r2: initial map
2070 // r3: object size (in words)
2071 // r4: JSObject (not tagged)
2072 // r7: undefined
2073 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2074 __ mov(r5, r4);
2075 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2076 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2077 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2078 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2079 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2080 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2081
2082 // Calculate the location of the first argument. The stack contains only the
2083 // argc arguments.
2084 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2085
2086 // Fill all the in-object properties with undefined.
2087 // r0: argc
2088 // r1: first argument
2089 // r3: object size (in words)
2090 // r4: JSObject (not tagged)
2091 // r5: First in-object property of JSObject (not tagged)
2092 // r7: undefined
2093 // Fill the initialized properties with a constant value or a passed argument
2094 // depending on the this.x = ...; assignment in the function.
2095 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2096 if (shared->IsThisPropertyAssignmentArgument(i)) {
2097 Label not_passed, next;
2098 // Check if the argument assigned to the property is actually passed.
2099 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2100 __ cmp(r0, Operand(arg_number));
2101 __ b(le, &not_passed);
2102 // Argument passed - find it on the stack.
2103 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2104 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2105 __ b(&next);
2106 __ bind(&not_passed);
2107 // Set the property to undefined.
2108 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2109 __ bind(&next);
2110 } else {
2111 // Set the property to the constant value.
2112 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2113 __ mov(r2, Operand(constant));
2114 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2115 }
2116 }
2117
2118 // Fill the unused in-object property fields with undefined.
2119 for (int i = shared->this_property_assignments_count();
2120 i < shared->CalculateInObjectProperties();
2121 i++) {
2122 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2123 }
2124
2125 // r0: argc
2126 // r4: JSObject (not tagged)
2127 // Move argc to r1 and the JSObject to return to r0 and tag it.
2128 __ mov(r1, r0);
2129 __ mov(r0, r4);
2130 __ orr(r0, r0, Operand(kHeapObjectTag));
2131
2132 // r0: JSObject
2133 // r1: argc
2134 // Remove caller arguments and receiver from the stack and return.
2135 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2136 __ add(sp, sp, Operand(kPointerSize));
2137 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2138 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2139 __ Jump(lr);
2140
2141 // Jump to the generic stub in case the specialized code cannot handle the
2142 // construction.
2143 __ bind(&generic_stub_call);
2144 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2145 Handle<Code> generic_construct_stub(code);
2146 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2147
2148 // Return the generated code.
2149 return GetCode();
2150}
2151
2152
2153#undef __
2154
2155} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002156
2157#endif // V8_TARGET_ARCH_ARM