blob: 0e649ccd13cf1823c7fb218661c6faffb5f76acd [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 Block8defd9f2010-07-08 12:39:36 +0100744 Label* miss,
745 Register extra) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000746 // Check that the maps haven't changed.
747 Register result =
Steve Block6ded16b2010-05-10 14:33:55 +0100748 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch,
749 save_at_depth, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000750
751 // If we've skipped any global objects, it's not enough to verify
Steve Block6ded16b2010-05-10 14:33:55 +0100752 // that their maps haven't changed. We also need to check that the
753 // property cell for the property is still empty.
Steve Blocka7e24c12009-10-30 11:49:00 +0000754 while (object != holder) {
755 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100756 Object* cell = GenerateCheckPropertyCell(masm(),
757 GlobalObject::cast(object),
758 name,
759 scratch,
760 miss);
761 if (cell->IsFailure()) {
762 set_failure(Failure::cast(cell));
Steve Blocka7e24c12009-10-30 11:49:00 +0000763 return result;
764 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000765 }
766 object = JSObject::cast(object->GetPrototype());
767 }
768
Andrei Popescu402d9372010-02-26 13:31:12 +0000769 // Return the register containing the holder.
Steve Blocka7e24c12009-10-30 11:49:00 +0000770 return result;
771}
772
773
774void StubCompiler::GenerateLoadField(JSObject* object,
775 JSObject* holder,
776 Register receiver,
777 Register scratch1,
778 Register scratch2,
779 int index,
780 String* name,
781 Label* miss) {
782 // Check that the receiver isn't a smi.
783 __ tst(receiver, Operand(kSmiTagMask));
784 __ b(eq, miss);
785
786 // Check that the maps haven't changed.
787 Register reg =
788 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
789 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
790 __ Ret();
791}
792
793
794void StubCompiler::GenerateLoadConstant(JSObject* object,
795 JSObject* holder,
796 Register receiver,
797 Register scratch1,
798 Register scratch2,
799 Object* value,
800 String* name,
801 Label* miss) {
802 // Check that the receiver isn't a smi.
803 __ tst(receiver, Operand(kSmiTagMask));
804 __ b(eq, miss);
805
806 // Check that the maps haven't changed.
807 Register reg =
808 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
809
810 // Return the constant value.
811 __ mov(r0, Operand(Handle<Object>(value)));
812 __ Ret();
813}
814
815
Leon Clarkee46be812010-01-19 14:06:41 +0000816bool StubCompiler::GenerateLoadCallback(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +0000817 JSObject* holder,
818 Register receiver,
819 Register name_reg,
820 Register scratch1,
821 Register scratch2,
822 AccessorInfo* callback,
823 String* name,
Leon Clarkee46be812010-01-19 14:06:41 +0000824 Label* miss,
825 Failure** failure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000826 // Check that the receiver isn't a smi.
827 __ tst(receiver, Operand(kSmiTagMask));
828 __ b(eq, miss);
829
830 // Check that the maps haven't changed.
831 Register reg =
832 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
833
834 // Push the arguments on the JS stack of the caller.
Steve Block6ded16b2010-05-10 14:33:55 +0100835 __ push(receiver); // Receiver.
836 __ push(reg); // Holder.
Steve Blocka7e24c12009-10-30 11:49:00 +0000837 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
Steve Blocka7e24c12009-10-30 11:49:00 +0000838 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
Steve Block6ded16b2010-05-10 14:33:55 +0100839 __ Push(ip, reg, name_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000840
841 // Do tail-call to the runtime system.
842 ExternalReference load_callback_property =
843 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +0100844 __ TailCallExternalReference(load_callback_property, 5, 1);
Leon Clarkee46be812010-01-19 14:06:41 +0000845
846 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000847}
848
849
850void StubCompiler::GenerateLoadInterceptor(JSObject* object,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100851 JSObject* interceptor_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000852 LookupResult* lookup,
853 Register receiver,
854 Register name_reg,
855 Register scratch1,
856 Register scratch2,
857 String* name,
858 Label* miss) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100859 ASSERT(interceptor_holder->HasNamedInterceptor());
860 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
861
862 // Check that the receiver isn't a smi.
863 __ BranchOnSmi(receiver, miss);
864
865 // So far the most popular follow ups for interceptor loads are FIELD
866 // and CALLBACKS, so inline only them, other cases may be added
867 // later.
868 bool compile_followup_inline = false;
869 if (lookup->IsProperty() && lookup->IsCacheable()) {
870 if (lookup->type() == FIELD) {
871 compile_followup_inline = true;
872 } else if (lookup->type() == CALLBACKS &&
873 lookup->GetCallbackObject()->IsAccessorInfo() &&
874 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
875 compile_followup_inline = true;
876 }
877 }
878
879 if (compile_followup_inline) {
880 // Compile the interceptor call, followed by inline code to load the
881 // property from further up the prototype chain if the call fails.
882 // Check that the maps haven't changed.
883 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
884 scratch1, scratch2, name, miss);
885 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
886
887 // Save necessary data before invoking an interceptor.
888 // Requires a frame to make GC aware of pushed pointers.
889 __ EnterInternalFrame();
890
891 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
892 // CALLBACKS case needs a receiver to be passed into C++ callback.
893 __ Push(receiver, holder_reg, name_reg);
894 } else {
895 __ Push(holder_reg, name_reg);
896 }
897
898 // Invoke an interceptor. Note: map checks from receiver to
899 // interceptor's holder has been compiled before (see a caller
900 // of this method.)
901 CompileCallLoadPropertyWithInterceptor(masm(),
902 receiver,
903 holder_reg,
904 name_reg,
905 interceptor_holder);
906
907 // Check if interceptor provided a value for property. If it's
908 // the case, return immediately.
909 Label interceptor_failed;
910 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
911 __ cmp(r0, scratch1);
912 __ b(eq, &interceptor_failed);
913 __ LeaveInternalFrame();
914 __ Ret();
915
916 __ bind(&interceptor_failed);
917 __ pop(name_reg);
918 __ pop(holder_reg);
919 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
920 __ pop(receiver);
921 }
922
923 __ LeaveInternalFrame();
924
925 // Check that the maps from interceptor's holder to lookup's holder
926 // haven't changed. And load lookup's holder into |holder| register.
927 if (interceptor_holder != lookup->holder()) {
928 holder_reg = CheckPrototypes(interceptor_holder,
929 holder_reg,
930 lookup->holder(),
931 scratch1,
932 scratch2,
933 name,
934 miss);
935 }
936
937 if (lookup->type() == FIELD) {
938 // We found FIELD property in prototype chain of interceptor's holder.
939 // Retrieve a field from field's holder.
940 GenerateFastPropertyLoad(masm(), r0, holder_reg,
941 lookup->holder(), lookup->GetFieldIndex());
942 __ Ret();
943 } else {
944 // We found CALLBACKS property in prototype chain of interceptor's
945 // holder.
946 ASSERT(lookup->type() == CALLBACKS);
947 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
948 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
949 ASSERT(callback != NULL);
950 ASSERT(callback->getter() != NULL);
951
952 // Tail call to runtime.
953 // Important invariant in CALLBACKS case: the code above must be
954 // structured to never clobber |receiver| register.
955 __ Move(scratch2, Handle<AccessorInfo>(callback));
956 // holder_reg is either receiver or scratch1.
957 if (!receiver.is(holder_reg)) {
958 ASSERT(scratch1.is(holder_reg));
959 __ Push(receiver, holder_reg, scratch2);
960 __ ldr(scratch1,
961 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
962 __ Push(scratch1, name_reg);
963 } else {
964 __ push(receiver);
965 __ ldr(scratch1,
966 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
967 __ Push(holder_reg, scratch2, scratch1, name_reg);
968 }
969
970 ExternalReference ref =
971 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
972 __ TailCallExternalReference(ref, 5, 1);
973 }
974 } else { // !compile_followup_inline
975 // Call the runtime system to load the interceptor.
976 // Check that the maps haven't changed.
977 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
978 scratch1, scratch2, name, miss);
979 PushInterceptorArguments(masm(), receiver, holder_reg,
980 name_reg, interceptor_holder);
981
982 ExternalReference ref = ExternalReference(
983 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
984 __ TailCallExternalReference(ref, 5, 1);
985 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000986}
987
988
989Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
990 // ----------- S t a t e -------------
991 // -- r1: function
992 // -- lr: return address
993 // -----------------------------------
994
995 // Enter an internal frame.
996 __ EnterInternalFrame();
997
998 // Preserve the function.
999 __ push(r1);
1000
1001 // Push the function on the stack as the argument to the runtime function.
1002 __ push(r1);
1003 __ CallRuntime(Runtime::kLazyCompile, 1);
1004
1005 // Calculate the entry point.
1006 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
1007
1008 // Restore saved function.
1009 __ pop(r1);
1010
1011 // Tear down temporary frame.
1012 __ LeaveInternalFrame();
1013
1014 // Do a tail-call of the compiled function.
1015 __ Jump(r2);
1016
1017 return GetCodeWithFlags(flags, "LazyCompileStub");
1018}
1019
1020
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001021void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
1022 if (kind_ == Code::KEYED_CALL_IC) {
1023 __ cmp(r2, Operand(Handle<String>(name)));
1024 __ b(ne, miss);
1025 }
1026}
1027
1028
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001029void CallStubCompiler::GenerateMissBranch() {
1030 Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_);
1031 __ Jump(ic, RelocInfo::CODE_TARGET);
1032}
1033
1034
Andrei Popescu402d9372010-02-26 13:31:12 +00001035Object* CallStubCompiler::CompileCallField(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001036 JSObject* holder,
1037 int index,
1038 String* name) {
1039 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001040 // -- r2 : name
1041 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001042 // -----------------------------------
1043 Label miss;
1044
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001045 GenerateNameCheck(name, &miss);
1046
Steve Blocka7e24c12009-10-30 11:49:00 +00001047 const int argc = arguments().immediate();
1048
1049 // Get the receiver of the function from the stack into r0.
1050 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1051 // Check that the receiver isn't a smi.
1052 __ tst(r0, Operand(kSmiTagMask));
1053 __ b(eq, &miss);
1054
1055 // Do the right check and compute the holder register.
Andrei Popescu402d9372010-02-26 13:31:12 +00001056 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001057 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
1058
Leon Clarke4515c472010-02-03 11:58:03 +00001059 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001060
1061 // Handle call cache miss.
1062 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001063 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001064
1065 // Return the generated code.
1066 return GetCode(FIELD, name);
1067}
1068
1069
Steve Block6ded16b2010-05-10 14:33:55 +01001070Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1071 JSObject* holder,
1072 JSFunction* function,
1073 String* name,
1074 CheckType check) {
1075 // ----------- S t a t e -------------
1076 // -- r2 : name
1077 // -- lr : return address
1078 // -----------------------------------
1079
1080 // If object is not an array, bail out to regular call.
1081 if (!object->IsJSArray()) {
1082 return Heap::undefined_value();
1083 }
1084
1085 // TODO(639): faster implementation.
1086 ASSERT(check == RECEIVER_MAP_CHECK);
1087
1088 Label miss;
1089
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001090 GenerateNameCheck(name, &miss);
1091
Steve Block6ded16b2010-05-10 14:33:55 +01001092 // Get the receiver from the stack
1093 const int argc = arguments().immediate();
1094 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1095
1096 // Check that the receiver isn't a smi.
1097 __ tst(r1, Operand(kSmiTagMask));
1098 __ b(eq, &miss);
1099
1100 // Check that the maps haven't changed.
1101 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1102
1103 if (object->IsGlobalObject()) {
1104 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1105 __ str(r3, MemOperand(sp, argc * kPointerSize));
1106 }
1107
1108 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1109 argc + 1,
1110 1);
1111
1112 // Handle call cache miss.
1113 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001114 GenerateMissBranch();
Steve Block6ded16b2010-05-10 14:33:55 +01001115
1116 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001117 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001118}
1119
1120
1121Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1122 JSObject* holder,
1123 JSFunction* function,
1124 String* name,
1125 CheckType check) {
1126 // ----------- S t a t e -------------
1127 // -- r2 : name
1128 // -- lr : return address
1129 // -----------------------------------
1130
1131 // If object is not an array, bail out to regular call.
1132 if (!object->IsJSArray()) {
1133 return Heap::undefined_value();
1134 }
1135
1136 // TODO(642): faster implementation.
1137 ASSERT(check == RECEIVER_MAP_CHECK);
1138
1139 Label miss;
1140
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001141 GenerateNameCheck(name, &miss);
1142
Steve Block6ded16b2010-05-10 14:33:55 +01001143 // Get the receiver from the stack
1144 const int argc = arguments().immediate();
1145 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1146
1147 // Check that the receiver isn't a smi.
1148 __ tst(r1, Operand(kSmiTagMask));
1149 __ b(eq, &miss);
1150
1151 // Check that the maps haven't changed.
1152 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1153
1154 if (object->IsGlobalObject()) {
1155 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1156 __ str(r3, MemOperand(sp, argc * kPointerSize));
1157 }
1158
1159 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1160 argc + 1,
1161 1);
1162
1163 // Handle call cache miss.
1164 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001165 GenerateMissBranch();
Steve Block6ded16b2010-05-10 14:33:55 +01001166
1167 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001168 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001169}
1170
1171
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001172Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
1173 JSObject* holder,
1174 JSFunction* function,
1175 String* name,
1176 CheckType check) {
1177 // TODO(722): implement this.
1178 return Heap::undefined_value();
1179}
1180
1181
1182Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
1183 JSObject* holder,
1184 JSFunction* function,
1185 String* name,
1186 CheckType check) {
1187 // TODO(722): implement this.
1188 return Heap::undefined_value();
1189}
1190
1191
Steve Blocka7e24c12009-10-30 11:49:00 +00001192Object* CallStubCompiler::CompileCallConstant(Object* object,
1193 JSObject* holder,
1194 JSFunction* function,
1195 String* name,
1196 CheckType check) {
1197 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001198 // -- r2 : name
1199 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001200 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001201 SharedFunctionInfo* function_info = function->shared();
1202 if (function_info->HasCustomCallGenerator()) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001203 const int id = function_info->custom_call_generator_id();
1204 Object* result =
1205 CompileCustomCall(id, object, holder, function, name, check);
Steve Block6ded16b2010-05-10 14:33:55 +01001206 // undefined means bail out to regular compiler.
1207 if (!result->IsUndefined()) {
1208 return result;
1209 }
1210 }
1211
1212 Label miss_in_smi_check;
Steve Blocka7e24c12009-10-30 11:49:00 +00001213
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001214 GenerateNameCheck(name, &miss_in_smi_check);
1215
Steve Blocka7e24c12009-10-30 11:49:00 +00001216 // Get the receiver from the stack
1217 const int argc = arguments().immediate();
1218 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1219
1220 // Check that the receiver isn't a smi.
1221 if (check != NUMBER_CHECK) {
1222 __ tst(r1, Operand(kSmiTagMask));
Steve Block6ded16b2010-05-10 14:33:55 +01001223 __ b(eq, &miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001224 }
1225
1226 // Make sure that it's okay not to patch the on stack receiver
1227 // unless we're doing a receiver map check.
1228 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1229
Steve Block6ded16b2010-05-10 14:33:55 +01001230 CallOptimization optimization(function);
1231 int depth = kInvalidProtoDepth;
1232 Label miss;
1233
Steve Blocka7e24c12009-10-30 11:49:00 +00001234 switch (check) {
1235 case RECEIVER_MAP_CHECK:
Steve Block6ded16b2010-05-10 14:33:55 +01001236 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1237
1238 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1239 depth = optimization.GetPrototypeDepthOfExpectedType(
1240 JSObject::cast(object), holder);
1241 }
1242
1243 if (depth != kInvalidProtoDepth) {
1244 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1245 ReserveSpaceForFastApiCall(masm(), r0);
1246 }
1247
Steve Blocka7e24c12009-10-30 11:49:00 +00001248 // Check that the maps haven't changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001249 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, name,
1250 depth, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001251
1252 // Patch the receiver on the stack with the global proxy if
1253 // necessary.
1254 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001255 ASSERT(depth == kInvalidProtoDepth);
Steve Blocka7e24c12009-10-30 11:49:00 +00001256 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1257 __ str(r3, MemOperand(sp, argc * kPointerSize));
1258 }
1259 break;
1260
1261 case STRING_CHECK:
Leon Clarkee46be812010-01-19 14:06:41 +00001262 if (!function->IsBuiltin()) {
1263 // Calling non-builtins with a value as receiver requires boxing.
1264 __ jmp(&miss);
1265 } else {
1266 // Check that the object is a two-byte string or a symbol.
Andrei Popescu402d9372010-02-26 13:31:12 +00001267 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001268 __ b(hs, &miss);
1269 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001270 GenerateDirectLoadGlobalFunctionPrototype(
1271 masm(), Context::STRING_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001272 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001273 r1, name, &miss);
1274 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001275 break;
1276
1277 case NUMBER_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001278 if (!function->IsBuiltin()) {
1279 // Calling non-builtins with a value as receiver requires boxing.
1280 __ jmp(&miss);
1281 } else {
1282 Label fast;
1283 // Check that the object is a smi or a heap number.
1284 __ tst(r1, Operand(kSmiTagMask));
1285 __ b(eq, &fast);
Andrei Popescu402d9372010-02-26 13:31:12 +00001286 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001287 __ b(ne, &miss);
1288 __ bind(&fast);
1289 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001290 GenerateDirectLoadGlobalFunctionPrototype(
1291 masm(), Context::NUMBER_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001292 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001293 r1, name, &miss);
1294 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001295 break;
1296 }
1297
1298 case BOOLEAN_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001299 if (!function->IsBuiltin()) {
1300 // Calling non-builtins with a value as receiver requires boxing.
1301 __ jmp(&miss);
1302 } else {
1303 Label fast;
1304 // Check that the object is a boolean.
1305 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1306 __ cmp(r1, ip);
1307 __ b(eq, &fast);
1308 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1309 __ cmp(r1, ip);
1310 __ b(ne, &miss);
1311 __ bind(&fast);
1312 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001313 GenerateDirectLoadGlobalFunctionPrototype(
1314 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001315 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001316 r1, name, &miss);
1317 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001318 break;
1319 }
1320
Steve Blocka7e24c12009-10-30 11:49:00 +00001321 default:
1322 UNREACHABLE();
1323 }
1324
Steve Block6ded16b2010-05-10 14:33:55 +01001325 if (depth != kInvalidProtoDepth) {
1326 GenerateFastApiCall(masm(), optimization, argc);
1327 } else {
1328 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1329 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001330
1331 // Handle call cache miss.
1332 __ bind(&miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001333 if (depth != kInvalidProtoDepth) {
1334 FreeSpaceForFastApiCall(masm());
1335 }
1336
1337 __ bind(&miss_in_smi_check);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001338 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001339
1340 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001341 return GetCode(function);
Steve Blocka7e24c12009-10-30 11:49:00 +00001342}
1343
1344
Andrei Popescu402d9372010-02-26 13:31:12 +00001345Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001346 JSObject* holder,
1347 String* name) {
1348 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001349 // -- r2 : name
1350 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001351 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001352
Steve Block6ded16b2010-05-10 14:33:55 +01001353 Label miss;
Andrei Popescu402d9372010-02-26 13:31:12 +00001354
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001355 GenerateNameCheck(name, &miss);
1356
Leon Clarke4515c472010-02-03 11:58:03 +00001357 // Get the number of arguments.
1358 const int argc = arguments().immediate();
1359
1360 LookupResult lookup;
1361 LookupPostInterceptor(holder, name, &lookup);
1362
Steve Block6ded16b2010-05-10 14:33:55 +01001363 // Get the receiver from the stack.
1364 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001365
Steve Block6ded16b2010-05-10 14:33:55 +01001366 CallInterceptorCompiler compiler(this, arguments(), r2);
1367 compiler.Compile(masm(),
1368 object,
1369 holder,
1370 name,
1371 &lookup,
1372 r1,
1373 r3,
1374 r4,
1375 &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001376
1377 // Move returned value, the function to call, to r1.
1378 __ mov(r1, r0);
Leon Clarke4515c472010-02-03 11:58:03 +00001379 // Restore receiver.
Steve Block6ded16b2010-05-10 14:33:55 +01001380 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001381
1382 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001383
1384 // Handle call cache miss.
1385 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001386 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001387
1388 // Return the generated code.
1389 return GetCode(INTERCEPTOR, name);
1390}
1391
1392
1393Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1394 GlobalObject* holder,
1395 JSGlobalPropertyCell* cell,
1396 JSFunction* function,
1397 String* name) {
1398 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001399 // -- r2 : name
1400 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001401 // -----------------------------------
1402 Label miss;
1403
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001404 GenerateNameCheck(name, &miss);
1405
Steve Blocka7e24c12009-10-30 11:49:00 +00001406 // Get the number of arguments.
1407 const int argc = arguments().immediate();
1408
1409 // Get the receiver from the stack.
1410 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1411
1412 // If the object is the holder then we know that it's a global
1413 // object which can only happen for contextual calls. In this case,
1414 // the receiver cannot be a smi.
1415 if (object != holder) {
1416 __ tst(r0, Operand(kSmiTagMask));
1417 __ b(eq, &miss);
1418 }
1419
1420 // Check that the maps haven't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001421 CheckPrototypes(object, r0, holder, r3, r1, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001422
1423 // Get the value from the cell.
1424 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1425 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1426
1427 // Check that the cell contains the same function.
Leon Clarkee46be812010-01-19 14:06:41 +00001428 if (Heap::InNewSpace(function)) {
1429 // We can't embed a pointer to a function in new space so we have
1430 // to verify that the shared function info is unchanged. This has
1431 // the nice side effect that multiple closures based on the same
1432 // function can all use this call IC. Before we load through the
1433 // function, we have to verify that it still is a function.
1434 __ tst(r1, Operand(kSmiTagMask));
1435 __ b(eq, &miss);
1436 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1437 __ b(ne, &miss);
1438
1439 // Check the shared function info. Make sure it hasn't changed.
1440 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
Andrei Popescu402d9372010-02-26 13:31:12 +00001441 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1442 __ cmp(r4, r3);
Leon Clarkee46be812010-01-19 14:06:41 +00001443 __ b(ne, &miss);
1444 } else {
1445 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1446 __ b(ne, &miss);
1447 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001448
1449 // Patch the receiver on the stack with the global proxy if
1450 // necessary.
1451 if (object->IsGlobalObject()) {
1452 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1453 __ str(r3, MemOperand(sp, argc * kPointerSize));
1454 }
1455
1456 // Setup the context (function already in r1).
1457 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1458
1459 // Jump to the cached code (tail call).
Steve Block6ded16b2010-05-10 14:33:55 +01001460 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001461 ASSERT(function->is_compiled());
1462 Handle<Code> code(function->code());
1463 ParameterCount expected(function->shared()->formal_parameter_count());
1464 __ InvokeCode(code, expected, arguments(),
1465 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1466
1467 // Handle call cache miss.
1468 __ bind(&miss);
1469 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001470 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001471
1472 // Return the generated code.
1473 return GetCode(NORMAL, name);
1474}
1475
1476
1477Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1478 int index,
1479 Map* transition,
1480 String* name) {
1481 // ----------- S t a t e -------------
1482 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001483 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001484 // -- r2 : name
1485 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001486 // -----------------------------------
1487 Label miss;
1488
Steve Blocka7e24c12009-10-30 11:49:00 +00001489 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001490 object,
1491 index,
1492 transition,
Andrei Popescu402d9372010-02-26 13:31:12 +00001493 r1, r2, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001494 &miss);
1495 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001496 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1497 __ Jump(ic, RelocInfo::CODE_TARGET);
1498
1499 // Return the generated code.
1500 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1501}
1502
1503
1504Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1505 AccessorInfo* callback,
1506 String* name) {
1507 // ----------- S t a t e -------------
1508 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001509 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001510 // -- r2 : name
1511 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001512 // -----------------------------------
1513 Label miss;
1514
Steve Blocka7e24c12009-10-30 11:49:00 +00001515 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001516 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001517 __ b(eq, &miss);
1518
1519 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001520 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1521 __ cmp(r3, Operand(Handle<Map>(object->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001522 __ b(ne, &miss);
1523
1524 // Perform global security token check if needed.
1525 if (object->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001526 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001527 }
1528
1529 // Stub never generated for non-global objects that require access
1530 // checks.
1531 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1532
Andrei Popescu402d9372010-02-26 13:31:12 +00001533 __ push(r1); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001534 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
Steve Block6ded16b2010-05-10 14:33:55 +01001535 __ Push(ip, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001536
1537 // Do tail-call to the runtime system.
1538 ExternalReference store_callback_property =
1539 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001540 __ TailCallExternalReference(store_callback_property, 4, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001541
1542 // Handle store cache miss.
1543 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001544 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1545 __ Jump(ic, RelocInfo::CODE_TARGET);
1546
1547 // Return the generated code.
1548 return GetCode(CALLBACKS, name);
1549}
1550
1551
1552Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1553 String* name) {
1554 // ----------- S t a t e -------------
1555 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001556 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001557 // -- r2 : name
1558 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001559 // -----------------------------------
1560 Label miss;
1561
Steve Blocka7e24c12009-10-30 11:49:00 +00001562 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001563 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001564 __ b(eq, &miss);
1565
1566 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001567 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1568 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001569 __ b(ne, &miss);
1570
1571 // Perform global security token check if needed.
1572 if (receiver->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001573 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001574 }
1575
Andrei Popescu402d9372010-02-26 13:31:12 +00001576 // Stub is never generated for non-global objects that require access
Steve Blocka7e24c12009-10-30 11:49:00 +00001577 // checks.
1578 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1579
Steve Block6ded16b2010-05-10 14:33:55 +01001580 __ Push(r1, r2, r0); // Receiver, name, value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001581
1582 // Do tail-call to the runtime system.
1583 ExternalReference store_ic_property =
1584 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001585 __ TailCallExternalReference(store_ic_property, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001586
1587 // Handle store cache miss.
1588 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001589 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1590 __ Jump(ic, RelocInfo::CODE_TARGET);
1591
1592 // Return the generated code.
1593 return GetCode(INTERCEPTOR, name);
1594}
1595
1596
1597Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1598 JSGlobalPropertyCell* cell,
1599 String* name) {
1600 // ----------- S t a t e -------------
1601 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001602 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001603 // -- r2 : name
1604 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001605 // -----------------------------------
1606 Label miss;
1607
1608 // Check that the map of the global has not changed.
Steve Blocka7e24c12009-10-30 11:49:00 +00001609 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1610 __ cmp(r3, Operand(Handle<Map>(object->map())));
1611 __ b(ne, &miss);
1612
1613 // Store the value in the cell.
1614 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1615 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
1616
Andrei Popescu402d9372010-02-26 13:31:12 +00001617 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001618 __ Ret();
1619
1620 // Handle store cache miss.
1621 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001622 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001623 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1624 __ Jump(ic, RelocInfo::CODE_TARGET);
1625
1626 // Return the generated code.
1627 return GetCode(NORMAL, name);
1628}
1629
1630
Steve Block6ded16b2010-05-10 14:33:55 +01001631Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1632 JSObject* object,
1633 JSObject* last) {
1634 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001635 // -- r0 : receiver
Steve Block6ded16b2010-05-10 14:33:55 +01001636 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001637 // -----------------------------------
1638 Label miss;
1639
Steve Block6ded16b2010-05-10 14:33:55 +01001640 // Check that receiver is not a smi.
1641 __ tst(r0, Operand(kSmiTagMask));
1642 __ b(eq, &miss);
1643
1644 // Check the maps of the full prototype chain.
1645 CheckPrototypes(object, r0, last, r3, r1, name, &miss);
1646
1647 // If the last object in the prototype chain is a global object,
1648 // check that the global property cell is empty.
1649 if (last->IsGlobalObject()) {
1650 Object* cell = GenerateCheckPropertyCell(masm(),
1651 GlobalObject::cast(last),
1652 name,
1653 r1,
1654 &miss);
1655 if (cell->IsFailure()) return cell;
1656 }
1657
1658 // Return undefined if maps of the full prototype chain are still the
1659 // same and no global property with this name contains a value.
1660 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1661 __ Ret();
1662
1663 __ bind(&miss);
1664 GenerateLoadMiss(masm(), Code::LOAD_IC);
1665
1666 // Return the generated code.
1667 return GetCode(NONEXISTENT, Heap::empty_string());
1668}
1669
1670
Steve Blocka7e24c12009-10-30 11:49:00 +00001671Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1672 JSObject* holder,
1673 int index,
1674 String* name) {
1675 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001676 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001677 // -- r2 : name
1678 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001679 // -----------------------------------
1680 Label miss;
1681
Steve Blocka7e24c12009-10-30 11:49:00 +00001682 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
1683 __ bind(&miss);
1684 GenerateLoadMiss(masm(), Code::LOAD_IC);
1685
1686 // Return the generated code.
1687 return GetCode(FIELD, name);
1688}
1689
1690
Leon Clarkee46be812010-01-19 14:06:41 +00001691Object* LoadStubCompiler::CompileLoadCallback(String* name,
1692 JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001693 JSObject* holder,
Leon Clarkee46be812010-01-19 14:06:41 +00001694 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001695 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001696 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001697 // -- r2 : name
1698 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001699 // -----------------------------------
1700 Label miss;
1701
Leon Clarkee46be812010-01-19 14:06:41 +00001702 Failure* failure = Failure::InternalError();
1703 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
1704 callback, name, &miss, &failure);
1705 if (!success) return failure;
1706
Steve Blocka7e24c12009-10-30 11:49:00 +00001707 __ bind(&miss);
1708 GenerateLoadMiss(masm(), Code::LOAD_IC);
1709
1710 // Return the generated code.
1711 return GetCode(CALLBACKS, name);
1712}
1713
1714
1715Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1716 JSObject* holder,
1717 Object* value,
1718 String* name) {
1719 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001720 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001721 // -- r2 : name
1722 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001723 // -----------------------------------
1724 Label miss;
1725
Steve Blocka7e24c12009-10-30 11:49:00 +00001726 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
1727 __ bind(&miss);
1728 GenerateLoadMiss(masm(), Code::LOAD_IC);
1729
1730 // Return the generated code.
1731 return GetCode(CONSTANT_FUNCTION, name);
1732}
1733
1734
1735Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1736 JSObject* holder,
1737 String* name) {
1738 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001739 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001740 // -- r2 : name
1741 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001742 // -----------------------------------
1743 Label miss;
1744
Steve Blocka7e24c12009-10-30 11:49:00 +00001745 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001746 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001747 GenerateLoadInterceptor(object,
1748 holder,
1749 &lookup,
1750 r0,
1751 r2,
1752 r3,
1753 r1,
1754 name,
1755 &miss);
1756 __ bind(&miss);
1757 GenerateLoadMiss(masm(), Code::LOAD_IC);
1758
1759 // Return the generated code.
1760 return GetCode(INTERCEPTOR, name);
1761}
1762
1763
1764Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1765 GlobalObject* holder,
1766 JSGlobalPropertyCell* cell,
1767 String* name,
1768 bool is_dont_delete) {
1769 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001770 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001771 // -- r2 : name
1772 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001773 // -----------------------------------
1774 Label miss;
1775
Steve Blocka7e24c12009-10-30 11:49:00 +00001776 // If the object is the holder then we know that it's a global
1777 // object which can only happen for contextual calls. In this case,
1778 // the receiver cannot be a smi.
1779 if (object != holder) {
Steve Block6ded16b2010-05-10 14:33:55 +01001780 __ tst(r0, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001781 __ b(eq, &miss);
1782 }
1783
1784 // Check that the map of the global has not changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001785 CheckPrototypes(object, r0, holder, r3, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001786
1787 // Get the value from the cell.
1788 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
Steve Block6ded16b2010-05-10 14:33:55 +01001789 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001790
1791 // Check for deleted property if property can actually be deleted.
1792 if (!is_dont_delete) {
1793 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
Steve Block6ded16b2010-05-10 14:33:55 +01001794 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00001795 __ b(eq, &miss);
1796 }
1797
Steve Block6ded16b2010-05-10 14:33:55 +01001798 __ mov(r0, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001799 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1800 __ Ret();
1801
1802 __ bind(&miss);
1803 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1804 GenerateLoadMiss(masm(), Code::LOAD_IC);
1805
1806 // Return the generated code.
1807 return GetCode(NORMAL, name);
1808}
1809
1810
1811Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1812 JSObject* receiver,
1813 JSObject* holder,
1814 int index) {
1815 // ----------- S t a t e -------------
1816 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001817 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001818 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001819 // -----------------------------------
1820 Label miss;
1821
Steve Block6ded16b2010-05-10 14:33:55 +01001822 // Check the key is the cached one.
1823 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001824 __ b(ne, &miss);
1825
Steve Block6ded16b2010-05-10 14:33:55 +01001826 GenerateLoadField(receiver, holder, r1, r2, r3, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001827 __ bind(&miss);
1828 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1829
1830 return GetCode(FIELD, name);
1831}
1832
1833
1834Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1835 JSObject* receiver,
1836 JSObject* holder,
1837 AccessorInfo* callback) {
1838 // ----------- S t a t e -------------
1839 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001840 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001841 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001842 // -----------------------------------
1843 Label miss;
1844
Steve Block6ded16b2010-05-10 14:33:55 +01001845 // Check the key is the cached one.
1846 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001847 __ b(ne, &miss);
1848
Leon Clarkee46be812010-01-19 14:06:41 +00001849 Failure* failure = Failure::InternalError();
Steve Block6ded16b2010-05-10 14:33:55 +01001850 bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001851 callback, name, &miss, &failure);
1852 if (!success) return failure;
1853
Steve Blocka7e24c12009-10-30 11:49:00 +00001854 __ bind(&miss);
1855 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1856
1857 return GetCode(CALLBACKS, name);
1858}
1859
1860
1861Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1862 JSObject* receiver,
1863 JSObject* holder,
1864 Object* value) {
1865 // ----------- S t a t e -------------
1866 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001867 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001868 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001869 // -----------------------------------
1870 Label miss;
1871
Steve Block6ded16b2010-05-10 14:33:55 +01001872 // Check the key is the cached one.
1873 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001874 __ b(ne, &miss);
1875
Steve Block6ded16b2010-05-10 14:33:55 +01001876 GenerateLoadConstant(receiver, holder, r1, r2, r3, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001877 __ bind(&miss);
1878 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1879
1880 // Return the generated code.
1881 return GetCode(CONSTANT_FUNCTION, name);
1882}
1883
1884
1885Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1886 JSObject* holder,
1887 String* name) {
1888 // ----------- S t a t e -------------
1889 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001890 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001891 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001892 // -----------------------------------
1893 Label miss;
1894
Steve Block6ded16b2010-05-10 14:33:55 +01001895 // Check the key is the cached one.
1896 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001897 __ b(ne, &miss);
1898
1899 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001900 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001901 GenerateLoadInterceptor(receiver,
1902 holder,
1903 &lookup,
Steve Block6ded16b2010-05-10 14:33:55 +01001904 r1,
Steve Blocka7e24c12009-10-30 11:49:00 +00001905 r0,
1906 r2,
1907 r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001908 name,
1909 &miss);
1910 __ bind(&miss);
1911 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1912
1913 return GetCode(INTERCEPTOR, name);
1914}
1915
1916
1917Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1918 // ----------- S t a t e -------------
1919 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001920 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001921 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001922 // -----------------------------------
1923 Label miss;
1924
Steve Block6ded16b2010-05-10 14:33:55 +01001925 // Check the key is the cached one.
1926 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001927 __ b(ne, &miss);
1928
Steve Block6ded16b2010-05-10 14:33:55 +01001929 GenerateLoadArrayLength(masm(), r1, r2, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001930 __ bind(&miss);
1931 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1932
1933 return GetCode(CALLBACKS, name);
1934}
1935
1936
1937Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
1938 // ----------- S t a t e -------------
1939 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001940 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001941 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001942 // -----------------------------------
1943 Label miss;
1944 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1945
Steve Block6ded16b2010-05-10 14:33:55 +01001946 // Check the key is the cached one.
1947 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001948 __ b(ne, &miss);
1949
Steve Block6ded16b2010-05-10 14:33:55 +01001950 GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001951 __ bind(&miss);
1952 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1953
1954 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1955
1956 return GetCode(CALLBACKS, name);
1957}
1958
1959
1960// TODO(1224671): implement the fast case.
1961Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1962 // ----------- S t a t e -------------
1963 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001964 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001965 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001966 // -----------------------------------
1967 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1968
1969 return GetCode(CALLBACKS, name);
1970}
1971
1972
1973Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1974 int index,
1975 Map* transition,
1976 String* name) {
1977 // ----------- S t a t e -------------
1978 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01001979 // -- r1 : key
1980 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001981 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001982 // -----------------------------------
1983 Label miss;
1984
Leon Clarkef7060e22010-06-03 12:02:55 +01001985 __ IncrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001986
1987 // Check that the name has not changed.
Leon Clarkef7060e22010-06-03 12:02:55 +01001988 __ cmp(r1, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001989 __ b(ne, &miss);
1990
Leon Clarkef7060e22010-06-03 12:02:55 +01001991 // r3 is used as scratch register. r1 and r2 keep their values if a jump to
1992 // the miss label is generated.
Steve Blocka7e24c12009-10-30 11:49:00 +00001993 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001994 object,
1995 index,
1996 transition,
Leon Clarkef7060e22010-06-03 12:02:55 +01001997 r2, r1, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001998 &miss);
1999 __ bind(&miss);
2000
Leon Clarkef7060e22010-06-03 12:02:55 +01002001 __ DecrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00002002 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
Leon Clarkef7060e22010-06-03 12:02:55 +01002003
Steve Blocka7e24c12009-10-30 11:49:00 +00002004 __ Jump(ic, RelocInfo::CODE_TARGET);
2005
2006 // Return the generated code.
2007 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2008}
2009
2010
2011Object* ConstructStubCompiler::CompileConstructStub(
2012 SharedFunctionInfo* shared) {
2013 // ----------- S t a t e -------------
2014 // -- r0 : argc
2015 // -- r1 : constructor
2016 // -- lr : return address
2017 // -- [sp] : last argument
2018 // -----------------------------------
2019 Label generic_stub_call;
2020
2021 // Use r7 for holding undefined which is used in several places below.
2022 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2023
2024#ifdef ENABLE_DEBUGGER_SUPPORT
2025 // Check to see whether there are any break points in the function code. If
2026 // there are jump to the generic constructor stub which calls the actual
2027 // code for the function thereby hitting the break points.
2028 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2029 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2030 __ cmp(r2, r7);
2031 __ b(ne, &generic_stub_call);
2032#endif
2033
2034 // Load the initial map and verify that it is in fact a map.
2035 // r1: constructor function
2036 // r7: undefined
2037 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2038 __ tst(r2, Operand(kSmiTagMask));
2039 __ b(eq, &generic_stub_call);
2040 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2041 __ b(ne, &generic_stub_call);
2042
2043#ifdef DEBUG
2044 // Cannot construct functions this way.
2045 // r0: argc
2046 // r1: constructor function
2047 // r2: initial map
2048 // r7: undefined
2049 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2050 __ Check(ne, "Function constructed by construct stub.");
2051#endif
2052
2053 // Now allocate the JSObject in new space.
2054 // r0: argc
2055 // r1: constructor function
2056 // r2: initial map
2057 // r7: undefined
2058 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
2059 __ AllocateInNewSpace(r3,
2060 r4,
2061 r5,
2062 r6,
2063 &generic_stub_call,
Kristian Monsen25f61362010-05-21 11:50:48 +01002064 SIZE_IN_WORDS);
Steve Blocka7e24c12009-10-30 11:49:00 +00002065
2066 // Allocated the JSObject, now initialize the fields. Map is set to initial
2067 // map and properties and elements are set to empty fixed array.
2068 // r0: argc
2069 // r1: constructor function
2070 // r2: initial map
2071 // r3: object size (in words)
2072 // r4: JSObject (not tagged)
2073 // r7: undefined
2074 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2075 __ mov(r5, r4);
2076 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2077 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2078 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2079 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2080 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2081 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2082
2083 // Calculate the location of the first argument. The stack contains only the
2084 // argc arguments.
2085 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2086
2087 // Fill all the in-object properties with undefined.
2088 // r0: argc
2089 // r1: first argument
2090 // r3: object size (in words)
2091 // r4: JSObject (not tagged)
2092 // r5: First in-object property of JSObject (not tagged)
2093 // r7: undefined
2094 // Fill the initialized properties with a constant value or a passed argument
2095 // depending on the this.x = ...; assignment in the function.
2096 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2097 if (shared->IsThisPropertyAssignmentArgument(i)) {
2098 Label not_passed, next;
2099 // Check if the argument assigned to the property is actually passed.
2100 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2101 __ cmp(r0, Operand(arg_number));
2102 __ b(le, &not_passed);
2103 // Argument passed - find it on the stack.
2104 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2105 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2106 __ b(&next);
2107 __ bind(&not_passed);
2108 // Set the property to undefined.
2109 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2110 __ bind(&next);
2111 } else {
2112 // Set the property to the constant value.
2113 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2114 __ mov(r2, Operand(constant));
2115 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2116 }
2117 }
2118
2119 // Fill the unused in-object property fields with undefined.
2120 for (int i = shared->this_property_assignments_count();
2121 i < shared->CalculateInObjectProperties();
2122 i++) {
2123 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2124 }
2125
2126 // r0: argc
2127 // r4: JSObject (not tagged)
2128 // Move argc to r1 and the JSObject to return to r0 and tag it.
2129 __ mov(r1, r0);
2130 __ mov(r0, r4);
2131 __ orr(r0, r0, Operand(kHeapObjectTag));
2132
2133 // r0: JSObject
2134 // r1: argc
2135 // Remove caller arguments and receiver from the stack and return.
2136 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2137 __ add(sp, sp, Operand(kPointerSize));
2138 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2139 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2140 __ Jump(lr);
2141
2142 // Jump to the generic stub in case the specialized code cannot handle the
2143 // construction.
2144 __ bind(&generic_stub_call);
2145 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2146 Handle<Code> generic_construct_stub(code);
2147 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2148
2149 // Return the generated code.
2150 return GetCode();
2151}
2152
2153
2154#undef __
2155
2156} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002157
2158#endif // V8_TARGET_ARCH_ARM