blob: 3992d6c5d097c2115528aebcf072a9d2c9c348e1 [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.
339 // Pass the value being stored in the now unused name_reg.
340 __ mov(name_reg, Operand(offset));
341 __ RecordWrite(receiver_reg, name_reg, scratch);
342 } else {
343 // Write to the properties array.
344 int offset = index * kPointerSize + FixedArray::kHeaderSize;
345 // Get the properties array
346 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
347 __ str(r0, FieldMemOperand(scratch, offset));
348
349 // Skip updating write barrier if storing a smi.
350 __ tst(r0, Operand(kSmiTagMask));
351 __ b(eq, &exit);
352
353 // Update the write barrier for the array address.
354 // Ok to clobber receiver_reg and name_reg, since we return.
355 __ mov(name_reg, Operand(offset));
356 __ RecordWrite(scratch, name_reg, receiver_reg);
357 }
358
359 // Return the value (register r0).
360 __ bind(&exit);
361 __ Ret();
362}
363
364
365void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
366 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
367 Code* code = NULL;
368 if (kind == Code::LOAD_IC) {
369 code = Builtins::builtin(Builtins::LoadIC_Miss);
370 } else {
371 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
372 }
373
374 Handle<Code> ic(code);
375 __ Jump(ic, RelocInfo::CODE_TARGET);
376}
377
378
Leon Clarke4515c472010-02-03 11:58:03 +0000379static void GenerateCallFunction(MacroAssembler* masm,
380 Object* object,
381 const ParameterCount& arguments,
382 Label* miss) {
383 // ----------- S t a t e -------------
384 // -- r0: receiver
385 // -- r1: function to call
386 // -----------------------------------
387
388 // Check that the function really is a function.
389 __ BranchOnSmi(r1, miss);
Andrei Popescu402d9372010-02-26 13:31:12 +0000390 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
Leon Clarke4515c472010-02-03 11:58:03 +0000391 __ b(ne, miss);
392
393 // Patch the receiver on the stack with the global proxy if
394 // necessary.
395 if (object->IsGlobalObject()) {
396 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
397 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
398 }
399
400 // Invoke the function.
401 __ InvokeFunction(r1, arguments, JUMP_FUNCTION);
402}
403
404
Leon Clarke4515c472010-02-03 11:58:03 +0000405static void PushInterceptorArguments(MacroAssembler* masm,
406 Register receiver,
407 Register holder,
408 Register name,
409 JSObject* holder_obj) {
Leon Clarke4515c472010-02-03 11:58:03 +0000410 __ push(name);
411 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
412 ASSERT(!Heap::InNewSpace(interceptor));
Steve Block6ded16b2010-05-10 14:33:55 +0100413 Register scratch = name;
Leon Clarke4515c472010-02-03 11:58:03 +0000414 __ mov(scratch, Operand(Handle<Object>(interceptor)));
415 __ push(scratch);
Steve Block6ded16b2010-05-10 14:33:55 +0100416 __ push(receiver);
417 __ push(holder);
Leon Clarke4515c472010-02-03 11:58:03 +0000418 __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
419 __ push(scratch);
420}
421
422
423static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
424 Register receiver,
425 Register holder,
426 Register name,
427 JSObject* holder_obj) {
428 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
429
430 ExternalReference ref =
431 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
432 __ mov(r0, Operand(5));
433 __ mov(r1, Operand(ref));
434
435 CEntryStub stub(1);
436 __ CallStub(&stub);
437}
438
439
Steve Block6ded16b2010-05-10 14:33:55 +0100440// Reserves space for the extra arguments to FastHandleApiCall in the
441// caller's frame.
442//
443// These arguments are set by CheckPrototypes and GenerateFastApiCall.
444static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
445 Register scratch) {
446 __ mov(scratch, Operand(Smi::FromInt(0)));
447 __ push(scratch);
448 __ push(scratch);
449 __ push(scratch);
450 __ push(scratch);
451}
452
453
454// Undoes the effects of ReserveSpaceForFastApiCall.
455static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
456 __ Drop(4);
457}
458
459
460// Generates call to FastHandleApiCall builtin.
461static void GenerateFastApiCall(MacroAssembler* masm,
462 const CallOptimization& optimization,
463 int argc) {
464 // Get the function and setup the context.
465 JSFunction* function = optimization.constant_function();
466 __ mov(r7, Operand(Handle<JSFunction>(function)));
467 __ ldr(cp, FieldMemOperand(r7, JSFunction::kContextOffset));
468
469 // Pass the additional arguments FastHandleApiCall expects.
470 bool info_loaded = false;
471 Object* callback = optimization.api_call_info()->callback();
472 if (Heap::InNewSpace(callback)) {
473 info_loaded = true;
474 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
475 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
476 } else {
477 __ Move(r6, Handle<Object>(callback));
478 }
479 Object* call_data = optimization.api_call_info()->data();
480 if (Heap::InNewSpace(call_data)) {
481 if (!info_loaded) {
482 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
483 }
484 __ ldr(r5, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
485 } else {
486 __ Move(r5, Handle<Object>(call_data));
487 }
488
489 __ add(sp, sp, Operand(1 * kPointerSize));
490 __ stm(ia, sp, r5.bit() | r6.bit() | r7.bit());
491 __ sub(sp, sp, Operand(1 * kPointerSize));
492
493 // Set the number of arguments.
494 __ mov(r0, Operand(argc + 4));
495
496 // Jump to the fast api call builtin (tail call).
497 Handle<Code> code = Handle<Code>(
498 Builtins::builtin(Builtins::FastHandleApiCall));
499 ParameterCount expected(0);
500 __ InvokeCode(code, expected, expected,
501 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
502}
503
504
505class CallInterceptorCompiler BASE_EMBEDDED {
506 public:
507 CallInterceptorCompiler(StubCompiler* stub_compiler,
508 const ParameterCount& arguments,
509 Register name)
510 : stub_compiler_(stub_compiler),
511 arguments_(arguments),
512 name_(name) {}
513
514 void Compile(MacroAssembler* masm,
515 JSObject* object,
516 JSObject* holder,
517 String* name,
518 LookupResult* lookup,
519 Register receiver,
520 Register scratch1,
521 Register scratch2,
522 Label* miss) {
523 ASSERT(holder->HasNamedInterceptor());
524 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
525
526 // Check that the receiver isn't a smi.
527 __ BranchOnSmi(receiver, miss);
528
529 CallOptimization optimization(lookup);
530
531 if (optimization.is_constant_call()) {
532 CompileCacheable(masm,
533 object,
534 receiver,
535 scratch1,
536 scratch2,
537 holder,
538 lookup,
539 name,
540 optimization,
541 miss);
542 } else {
543 CompileRegular(masm,
544 object,
545 receiver,
546 scratch1,
547 scratch2,
548 name,
549 holder,
550 miss);
551 }
552 }
553
554 private:
555 void CompileCacheable(MacroAssembler* masm,
556 JSObject* object,
557 Register receiver,
558 Register scratch1,
559 Register scratch2,
Leon Clarkef7060e22010-06-03 12:02:55 +0100560 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100561 LookupResult* lookup,
562 String* name,
563 const CallOptimization& optimization,
564 Label* miss_label) {
565 ASSERT(optimization.is_constant_call());
566 ASSERT(!lookup->holder()->IsGlobalObject());
567
568 int depth1 = kInvalidProtoDepth;
569 int depth2 = kInvalidProtoDepth;
570 bool can_do_fast_api_call = false;
571 if (optimization.is_simple_api_call() &&
572 !lookup->holder()->IsGlobalObject()) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100573 depth1 =
574 optimization.GetPrototypeDepthOfExpectedType(object,
575 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100576 if (depth1 == kInvalidProtoDepth) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100577 depth2 =
578 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
579 lookup->holder());
Steve Block6ded16b2010-05-10 14:33:55 +0100580 }
581 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
582 (depth2 != kInvalidProtoDepth);
583 }
584
585 __ IncrementCounter(&Counters::call_const_interceptor, 1,
586 scratch1, scratch2);
587
588 if (can_do_fast_api_call) {
589 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1,
590 scratch1, scratch2);
591 ReserveSpaceForFastApiCall(masm, scratch1);
592 }
593
Leon Clarkef7060e22010-06-03 12:02:55 +0100594 // Check that the maps from receiver to interceptor's holder
595 // haven't changed and thus we can invoke interceptor.
Steve Block6ded16b2010-05-10 14:33:55 +0100596 Label miss_cleanup;
597 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
598 Register holder =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100599 stub_compiler_->CheckPrototypes(object, receiver,
600 interceptor_holder, scratch1,
601 scratch2, name, depth1, miss);
Steve Block6ded16b2010-05-10 14:33:55 +0100602
Leon Clarkef7060e22010-06-03 12:02:55 +0100603 // Invoke an interceptor and if it provides a value,
604 // branch to |regular_invoke|.
Steve Block6ded16b2010-05-10 14:33:55 +0100605 Label regular_invoke;
Leon Clarkef7060e22010-06-03 12:02:55 +0100606 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
Steve Block6ded16b2010-05-10 14:33:55 +0100607 &regular_invoke);
608
Leon Clarkef7060e22010-06-03 12:02:55 +0100609 // Interceptor returned nothing for this property. Try to use cached
610 // constant function.
Steve Block6ded16b2010-05-10 14:33:55 +0100611
Leon Clarkef7060e22010-06-03 12:02:55 +0100612 // Check that the maps from interceptor's holder to constant function's
613 // holder haven't changed and thus we can use cached constant function.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100614 if (interceptor_holder != lookup->holder()) {
615 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
616 lookup->holder(), scratch1,
617 scratch2, name, depth2, miss);
618 } else {
619 // CheckPrototypes has a side effect of fetching a 'holder'
620 // for API (object which is instanceof for the signature). It's
621 // safe to omit it here, as if present, it should be fetched
622 // by the previous CheckPrototypes.
623 ASSERT(depth2 == kInvalidProtoDepth);
624 }
Steve Block6ded16b2010-05-10 14:33:55 +0100625
Leon Clarkef7060e22010-06-03 12:02:55 +0100626 // Invoke function.
Steve Block6ded16b2010-05-10 14:33:55 +0100627 if (can_do_fast_api_call) {
628 GenerateFastApiCall(masm, optimization, arguments_.immediate());
629 } else {
630 __ InvokeFunction(optimization.constant_function(), arguments_,
631 JUMP_FUNCTION);
632 }
633
Leon Clarkef7060e22010-06-03 12:02:55 +0100634 // Deferred code for fast API call case---clean preallocated space.
Steve Block6ded16b2010-05-10 14:33:55 +0100635 if (can_do_fast_api_call) {
636 __ bind(&miss_cleanup);
637 FreeSpaceForFastApiCall(masm);
638 __ b(miss_label);
639 }
640
Leon Clarkef7060e22010-06-03 12:02:55 +0100641 // Invoke a regular function.
Steve Block6ded16b2010-05-10 14:33:55 +0100642 __ bind(&regular_invoke);
643 if (can_do_fast_api_call) {
644 FreeSpaceForFastApiCall(masm);
645 }
646 }
647
648 void CompileRegular(MacroAssembler* masm,
649 JSObject* object,
650 Register receiver,
651 Register scratch1,
652 Register scratch2,
653 String* name,
Leon Clarkef7060e22010-06-03 12:02:55 +0100654 JSObject* interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100655 Label* miss_label) {
656 Register holder =
Leon Clarkef7060e22010-06-03 12:02:55 +0100657 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
Steve Block6ded16b2010-05-10 14:33:55 +0100658 scratch1, scratch2, name,
659 miss_label);
660
661 // Call a runtime function to load the interceptor property.
662 __ EnterInternalFrame();
663 // Save the name_ register across the call.
664 __ push(name_);
665
666 PushInterceptorArguments(masm,
667 receiver,
668 holder,
669 name_,
Leon Clarkef7060e22010-06-03 12:02:55 +0100670 interceptor_holder);
Steve Block6ded16b2010-05-10 14:33:55 +0100671
672 __ CallExternalReference(
673 ExternalReference(
674 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
675 5);
676
677 // Restore the name_ register.
678 __ pop(name_);
679 __ LeaveInternalFrame();
680 }
681
682 void LoadWithInterceptor(MacroAssembler* masm,
683 Register receiver,
684 Register holder,
685 JSObject* holder_obj,
686 Register scratch,
687 Label* interceptor_succeeded) {
688 __ EnterInternalFrame();
689 __ Push(holder, name_);
690
691 CompileCallLoadPropertyWithInterceptor(masm,
692 receiver,
693 holder,
694 name_,
695 holder_obj);
696
697 __ pop(name_); // Restore the name.
698 __ pop(receiver); // Restore the holder.
699 __ LeaveInternalFrame();
700
701 // If interceptor returns no-result sentinel, call the constant function.
702 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
703 __ cmp(r0, scratch);
704 __ b(ne, interceptor_succeeded);
705 }
706
707 StubCompiler* stub_compiler_;
708 const ParameterCount& arguments_;
709 Register name_;
710};
711
712
713// Generate code to check that a global property cell is empty. Create
714// the property cell at compilation time if no cell exists for the
715// property.
716static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
717 GlobalObject* global,
718 String* name,
719 Register scratch,
720 Label* miss) {
721 Object* probe = global->EnsurePropertyCell(name);
722 if (probe->IsFailure()) return probe;
723 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
724 ASSERT(cell->value()->IsTheHole());
725 __ mov(scratch, Operand(Handle<Object>(cell)));
726 __ ldr(scratch,
727 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
728 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
729 __ cmp(scratch, ip);
730 __ b(ne, miss);
731 return cell;
732}
733
734
Steve Blocka7e24c12009-10-30 11:49:00 +0000735#undef __
736#define __ ACCESS_MASM(masm())
737
738
739Register StubCompiler::CheckPrototypes(JSObject* object,
740 Register object_reg,
741 JSObject* holder,
742 Register holder_reg,
743 Register scratch,
744 String* name,
Andrei Popescu402d9372010-02-26 13:31:12 +0000745 int save_at_depth,
Steve Blocka7e24c12009-10-30 11:49:00 +0000746 Label* miss) {
747 // Check that the maps haven't changed.
748 Register result =
Steve Block6ded16b2010-05-10 14:33:55 +0100749 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch,
750 save_at_depth, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000751
752 // If we've skipped any global objects, it's not enough to verify
Steve Block6ded16b2010-05-10 14:33:55 +0100753 // that their maps haven't changed. We also need to check that the
754 // property cell for the property is still empty.
Steve Blocka7e24c12009-10-30 11:49:00 +0000755 while (object != holder) {
756 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100757 Object* cell = GenerateCheckPropertyCell(masm(),
758 GlobalObject::cast(object),
759 name,
760 scratch,
761 miss);
762 if (cell->IsFailure()) {
763 set_failure(Failure::cast(cell));
Steve Blocka7e24c12009-10-30 11:49:00 +0000764 return result;
765 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000766 }
767 object = JSObject::cast(object->GetPrototype());
768 }
769
Andrei Popescu402d9372010-02-26 13:31:12 +0000770 // Return the register containing the holder.
Steve Blocka7e24c12009-10-30 11:49:00 +0000771 return result;
772}
773
774
775void StubCompiler::GenerateLoadField(JSObject* object,
776 JSObject* holder,
777 Register receiver,
778 Register scratch1,
779 Register scratch2,
780 int index,
781 String* name,
782 Label* miss) {
783 // Check that the receiver isn't a smi.
784 __ tst(receiver, Operand(kSmiTagMask));
785 __ b(eq, miss);
786
787 // Check that the maps haven't changed.
788 Register reg =
789 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
790 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
791 __ Ret();
792}
793
794
795void StubCompiler::GenerateLoadConstant(JSObject* object,
796 JSObject* holder,
797 Register receiver,
798 Register scratch1,
799 Register scratch2,
800 Object* value,
801 String* name,
802 Label* miss) {
803 // Check that the receiver isn't a smi.
804 __ tst(receiver, Operand(kSmiTagMask));
805 __ b(eq, miss);
806
807 // Check that the maps haven't changed.
808 Register reg =
809 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
810
811 // Return the constant value.
812 __ mov(r0, Operand(Handle<Object>(value)));
813 __ Ret();
814}
815
816
Leon Clarkee46be812010-01-19 14:06:41 +0000817bool StubCompiler::GenerateLoadCallback(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +0000818 JSObject* holder,
819 Register receiver,
820 Register name_reg,
821 Register scratch1,
822 Register scratch2,
823 AccessorInfo* callback,
824 String* name,
Leon Clarkee46be812010-01-19 14:06:41 +0000825 Label* miss,
826 Failure** failure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000827 // Check that the receiver isn't a smi.
828 __ tst(receiver, Operand(kSmiTagMask));
829 __ b(eq, miss);
830
831 // Check that the maps haven't changed.
832 Register reg =
833 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
834
835 // Push the arguments on the JS stack of the caller.
Steve Block6ded16b2010-05-10 14:33:55 +0100836 __ push(receiver); // Receiver.
837 __ push(reg); // Holder.
Steve Blocka7e24c12009-10-30 11:49:00 +0000838 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
Steve Blocka7e24c12009-10-30 11:49:00 +0000839 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
Steve Block6ded16b2010-05-10 14:33:55 +0100840 __ Push(ip, reg, name_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000841
842 // Do tail-call to the runtime system.
843 ExternalReference load_callback_property =
844 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +0100845 __ TailCallExternalReference(load_callback_property, 5, 1);
Leon Clarkee46be812010-01-19 14:06:41 +0000846
847 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000848}
849
850
851void StubCompiler::GenerateLoadInterceptor(JSObject* object,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100852 JSObject* interceptor_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000853 LookupResult* lookup,
854 Register receiver,
855 Register name_reg,
856 Register scratch1,
857 Register scratch2,
858 String* name,
859 Label* miss) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100860 ASSERT(interceptor_holder->HasNamedInterceptor());
861 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
862
863 // Check that the receiver isn't a smi.
864 __ BranchOnSmi(receiver, miss);
865
866 // So far the most popular follow ups for interceptor loads are FIELD
867 // and CALLBACKS, so inline only them, other cases may be added
868 // later.
869 bool compile_followup_inline = false;
870 if (lookup->IsProperty() && lookup->IsCacheable()) {
871 if (lookup->type() == FIELD) {
872 compile_followup_inline = true;
873 } else if (lookup->type() == CALLBACKS &&
874 lookup->GetCallbackObject()->IsAccessorInfo() &&
875 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
876 compile_followup_inline = true;
877 }
878 }
879
880 if (compile_followup_inline) {
881 // Compile the interceptor call, followed by inline code to load the
882 // property from further up the prototype chain if the call fails.
883 // Check that the maps haven't changed.
884 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
885 scratch1, scratch2, name, miss);
886 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
887
888 // Save necessary data before invoking an interceptor.
889 // Requires a frame to make GC aware of pushed pointers.
890 __ EnterInternalFrame();
891
892 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
893 // CALLBACKS case needs a receiver to be passed into C++ callback.
894 __ Push(receiver, holder_reg, name_reg);
895 } else {
896 __ Push(holder_reg, name_reg);
897 }
898
899 // Invoke an interceptor. Note: map checks from receiver to
900 // interceptor's holder has been compiled before (see a caller
901 // of this method.)
902 CompileCallLoadPropertyWithInterceptor(masm(),
903 receiver,
904 holder_reg,
905 name_reg,
906 interceptor_holder);
907
908 // Check if interceptor provided a value for property. If it's
909 // the case, return immediately.
910 Label interceptor_failed;
911 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
912 __ cmp(r0, scratch1);
913 __ b(eq, &interceptor_failed);
914 __ LeaveInternalFrame();
915 __ Ret();
916
917 __ bind(&interceptor_failed);
918 __ pop(name_reg);
919 __ pop(holder_reg);
920 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
921 __ pop(receiver);
922 }
923
924 __ LeaveInternalFrame();
925
926 // Check that the maps from interceptor's holder to lookup's holder
927 // haven't changed. And load lookup's holder into |holder| register.
928 if (interceptor_holder != lookup->holder()) {
929 holder_reg = CheckPrototypes(interceptor_holder,
930 holder_reg,
931 lookup->holder(),
932 scratch1,
933 scratch2,
934 name,
935 miss);
936 }
937
938 if (lookup->type() == FIELD) {
939 // We found FIELD property in prototype chain of interceptor's holder.
940 // Retrieve a field from field's holder.
941 GenerateFastPropertyLoad(masm(), r0, holder_reg,
942 lookup->holder(), lookup->GetFieldIndex());
943 __ Ret();
944 } else {
945 // We found CALLBACKS property in prototype chain of interceptor's
946 // holder.
947 ASSERT(lookup->type() == CALLBACKS);
948 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
949 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
950 ASSERT(callback != NULL);
951 ASSERT(callback->getter() != NULL);
952
953 // Tail call to runtime.
954 // Important invariant in CALLBACKS case: the code above must be
955 // structured to never clobber |receiver| register.
956 __ Move(scratch2, Handle<AccessorInfo>(callback));
957 // holder_reg is either receiver or scratch1.
958 if (!receiver.is(holder_reg)) {
959 ASSERT(scratch1.is(holder_reg));
960 __ Push(receiver, holder_reg, scratch2);
961 __ ldr(scratch1,
962 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
963 __ Push(scratch1, name_reg);
964 } else {
965 __ push(receiver);
966 __ ldr(scratch1,
967 FieldMemOperand(holder_reg, AccessorInfo::kDataOffset));
968 __ Push(holder_reg, scratch2, scratch1, name_reg);
969 }
970
971 ExternalReference ref =
972 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
973 __ TailCallExternalReference(ref, 5, 1);
974 }
975 } else { // !compile_followup_inline
976 // Call the runtime system to load the interceptor.
977 // Check that the maps haven't changed.
978 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
979 scratch1, scratch2, name, miss);
980 PushInterceptorArguments(masm(), receiver, holder_reg,
981 name_reg, interceptor_holder);
982
983 ExternalReference ref = ExternalReference(
984 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
985 __ TailCallExternalReference(ref, 5, 1);
986 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000987}
988
989
990Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
991 // ----------- S t a t e -------------
992 // -- r1: function
993 // -- lr: return address
994 // -----------------------------------
995
996 // Enter an internal frame.
997 __ EnterInternalFrame();
998
999 // Preserve the function.
1000 __ push(r1);
1001
1002 // Push the function on the stack as the argument to the runtime function.
1003 __ push(r1);
1004 __ CallRuntime(Runtime::kLazyCompile, 1);
1005
1006 // Calculate the entry point.
1007 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
1008
1009 // Restore saved function.
1010 __ pop(r1);
1011
1012 // Tear down temporary frame.
1013 __ LeaveInternalFrame();
1014
1015 // Do a tail-call of the compiled function.
1016 __ Jump(r2);
1017
1018 return GetCodeWithFlags(flags, "LazyCompileStub");
1019}
1020
1021
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001022void CallStubCompiler::GenerateMissBranch() {
1023 Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_);
1024 __ Jump(ic, RelocInfo::CODE_TARGET);
1025}
1026
1027
Andrei Popescu402d9372010-02-26 13:31:12 +00001028Object* CallStubCompiler::CompileCallField(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001029 JSObject* holder,
1030 int index,
1031 String* name) {
1032 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001033 // -- r2 : name
1034 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001035 // -----------------------------------
1036 Label miss;
1037
1038 const int argc = arguments().immediate();
1039
1040 // Get the receiver of the function from the stack into r0.
1041 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1042 // Check that the receiver isn't a smi.
1043 __ tst(r0, Operand(kSmiTagMask));
1044 __ b(eq, &miss);
1045
1046 // Do the right check and compute the holder register.
Andrei Popescu402d9372010-02-26 13:31:12 +00001047 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001048 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
1049
Leon Clarke4515c472010-02-03 11:58:03 +00001050 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001051
1052 // Handle call cache miss.
1053 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001054 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001055
1056 // Return the generated code.
1057 return GetCode(FIELD, name);
1058}
1059
1060
Steve Block6ded16b2010-05-10 14:33:55 +01001061Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1062 JSObject* holder,
1063 JSFunction* function,
1064 String* name,
1065 CheckType check) {
1066 // ----------- S t a t e -------------
1067 // -- r2 : name
1068 // -- lr : return address
1069 // -----------------------------------
1070
1071 // If object is not an array, bail out to regular call.
1072 if (!object->IsJSArray()) {
1073 return Heap::undefined_value();
1074 }
1075
1076 // TODO(639): faster implementation.
1077 ASSERT(check == RECEIVER_MAP_CHECK);
1078
1079 Label miss;
1080
1081 // Get the receiver from the stack
1082 const int argc = arguments().immediate();
1083 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1084
1085 // Check that the receiver isn't a smi.
1086 __ tst(r1, Operand(kSmiTagMask));
1087 __ b(eq, &miss);
1088
1089 // Check that the maps haven't changed.
1090 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1091
1092 if (object->IsGlobalObject()) {
1093 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1094 __ str(r3, MemOperand(sp, argc * kPointerSize));
1095 }
1096
1097 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1098 argc + 1,
1099 1);
1100
1101 // Handle call cache miss.
1102 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001103 GenerateMissBranch();
Steve Block6ded16b2010-05-10 14:33:55 +01001104
1105 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001106 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001107}
1108
1109
1110Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1111 JSObject* holder,
1112 JSFunction* function,
1113 String* name,
1114 CheckType check) {
1115 // ----------- S t a t e -------------
1116 // -- r2 : name
1117 // -- lr : return address
1118 // -----------------------------------
1119
1120 // If object is not an array, bail out to regular call.
1121 if (!object->IsJSArray()) {
1122 return Heap::undefined_value();
1123 }
1124
1125 // TODO(642): faster implementation.
1126 ASSERT(check == RECEIVER_MAP_CHECK);
1127
1128 Label miss;
1129
1130 // Get the receiver from the stack
1131 const int argc = arguments().immediate();
1132 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1133
1134 // Check that the receiver isn't a smi.
1135 __ tst(r1, Operand(kSmiTagMask));
1136 __ b(eq, &miss);
1137
1138 // Check that the maps haven't changed.
1139 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1140
1141 if (object->IsGlobalObject()) {
1142 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1143 __ str(r3, MemOperand(sp, argc * kPointerSize));
1144 }
1145
1146 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1147 argc + 1,
1148 1);
1149
1150 // Handle call cache miss.
1151 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001152 GenerateMissBranch();
Steve Block6ded16b2010-05-10 14:33:55 +01001153
1154 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001155 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001156}
1157
1158
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001159Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
1160 JSObject* holder,
1161 JSFunction* function,
1162 String* name,
1163 CheckType check) {
1164 // TODO(722): implement this.
1165 return Heap::undefined_value();
1166}
1167
1168
1169Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
1170 JSObject* holder,
1171 JSFunction* function,
1172 String* name,
1173 CheckType check) {
1174 // TODO(722): implement this.
1175 return Heap::undefined_value();
1176}
1177
1178
Steve Blocka7e24c12009-10-30 11:49:00 +00001179Object* CallStubCompiler::CompileCallConstant(Object* object,
1180 JSObject* holder,
1181 JSFunction* function,
1182 String* name,
1183 CheckType check) {
1184 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001185 // -- r2 : name
1186 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001187 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001188 SharedFunctionInfo* function_info = function->shared();
1189 if (function_info->HasCustomCallGenerator()) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001190 const int id = function_info->custom_call_generator_id();
1191 Object* result =
1192 CompileCustomCall(id, object, holder, function, name, check);
Steve Block6ded16b2010-05-10 14:33:55 +01001193 // undefined means bail out to regular compiler.
1194 if (!result->IsUndefined()) {
1195 return result;
1196 }
1197 }
1198
1199 Label miss_in_smi_check;
Steve Blocka7e24c12009-10-30 11:49:00 +00001200
1201 // Get the receiver from the stack
1202 const int argc = arguments().immediate();
1203 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1204
1205 // Check that the receiver isn't a smi.
1206 if (check != NUMBER_CHECK) {
1207 __ tst(r1, Operand(kSmiTagMask));
Steve Block6ded16b2010-05-10 14:33:55 +01001208 __ b(eq, &miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001209 }
1210
1211 // Make sure that it's okay not to patch the on stack receiver
1212 // unless we're doing a receiver map check.
1213 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1214
Steve Block6ded16b2010-05-10 14:33:55 +01001215 CallOptimization optimization(function);
1216 int depth = kInvalidProtoDepth;
1217 Label miss;
1218
Steve Blocka7e24c12009-10-30 11:49:00 +00001219 switch (check) {
1220 case RECEIVER_MAP_CHECK:
Steve Block6ded16b2010-05-10 14:33:55 +01001221 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1222
1223 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1224 depth = optimization.GetPrototypeDepthOfExpectedType(
1225 JSObject::cast(object), holder);
1226 }
1227
1228 if (depth != kInvalidProtoDepth) {
1229 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1230 ReserveSpaceForFastApiCall(masm(), r0);
1231 }
1232
Steve Blocka7e24c12009-10-30 11:49:00 +00001233 // Check that the maps haven't changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001234 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, name,
1235 depth, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001236
1237 // Patch the receiver on the stack with the global proxy if
1238 // necessary.
1239 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001240 ASSERT(depth == kInvalidProtoDepth);
Steve Blocka7e24c12009-10-30 11:49:00 +00001241 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1242 __ str(r3, MemOperand(sp, argc * kPointerSize));
1243 }
1244 break;
1245
1246 case STRING_CHECK:
Leon Clarkee46be812010-01-19 14:06:41 +00001247 if (!function->IsBuiltin()) {
1248 // Calling non-builtins with a value as receiver requires boxing.
1249 __ jmp(&miss);
1250 } else {
1251 // Check that the object is a two-byte string or a symbol.
Andrei Popescu402d9372010-02-26 13:31:12 +00001252 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001253 __ b(hs, &miss);
1254 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001255 GenerateDirectLoadGlobalFunctionPrototype(
1256 masm(), Context::STRING_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001257 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001258 r1, name, &miss);
1259 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001260 break;
1261
1262 case NUMBER_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001263 if (!function->IsBuiltin()) {
1264 // Calling non-builtins with a value as receiver requires boxing.
1265 __ jmp(&miss);
1266 } else {
1267 Label fast;
1268 // Check that the object is a smi or a heap number.
1269 __ tst(r1, Operand(kSmiTagMask));
1270 __ b(eq, &fast);
Andrei Popescu402d9372010-02-26 13:31:12 +00001271 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001272 __ b(ne, &miss);
1273 __ bind(&fast);
1274 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001275 GenerateDirectLoadGlobalFunctionPrototype(
1276 masm(), Context::NUMBER_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001277 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001278 r1, name, &miss);
1279 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001280 break;
1281 }
1282
1283 case BOOLEAN_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001284 if (!function->IsBuiltin()) {
1285 // Calling non-builtins with a value as receiver requires boxing.
1286 __ jmp(&miss);
1287 } else {
1288 Label fast;
1289 // Check that the object is a boolean.
1290 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1291 __ cmp(r1, ip);
1292 __ b(eq, &fast);
1293 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1294 __ cmp(r1, ip);
1295 __ b(ne, &miss);
1296 __ bind(&fast);
1297 // Check that the maps starting from the prototype haven't changed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001298 GenerateDirectLoadGlobalFunctionPrototype(
1299 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001300 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001301 r1, name, &miss);
1302 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001303 break;
1304 }
1305
Steve Blocka7e24c12009-10-30 11:49:00 +00001306 default:
1307 UNREACHABLE();
1308 }
1309
Steve Block6ded16b2010-05-10 14:33:55 +01001310 if (depth != kInvalidProtoDepth) {
1311 GenerateFastApiCall(masm(), optimization, argc);
1312 } else {
1313 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1314 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001315
1316 // Handle call cache miss.
1317 __ bind(&miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001318 if (depth != kInvalidProtoDepth) {
1319 FreeSpaceForFastApiCall(masm());
1320 }
1321
1322 __ bind(&miss_in_smi_check);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001323 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001324
1325 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001326 return GetCode(function);
Steve Blocka7e24c12009-10-30 11:49:00 +00001327}
1328
1329
Andrei Popescu402d9372010-02-26 13:31:12 +00001330Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001331 JSObject* holder,
1332 String* name) {
1333 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001334 // -- r2 : name
1335 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001336 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001337
Steve Block6ded16b2010-05-10 14:33:55 +01001338 Label miss;
Andrei Popescu402d9372010-02-26 13:31:12 +00001339
Leon Clarke4515c472010-02-03 11:58:03 +00001340 // Get the number of arguments.
1341 const int argc = arguments().immediate();
1342
1343 LookupResult lookup;
1344 LookupPostInterceptor(holder, name, &lookup);
1345
Steve Block6ded16b2010-05-10 14:33:55 +01001346 // Get the receiver from the stack.
1347 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001348
Steve Block6ded16b2010-05-10 14:33:55 +01001349 CallInterceptorCompiler compiler(this, arguments(), r2);
1350 compiler.Compile(masm(),
1351 object,
1352 holder,
1353 name,
1354 &lookup,
1355 r1,
1356 r3,
1357 r4,
1358 &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001359
1360 // Move returned value, the function to call, to r1.
1361 __ mov(r1, r0);
Leon Clarke4515c472010-02-03 11:58:03 +00001362 // Restore receiver.
Steve Block6ded16b2010-05-10 14:33:55 +01001363 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001364
1365 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001366
1367 // Handle call cache miss.
1368 __ bind(&miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001369 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001370
1371 // Return the generated code.
1372 return GetCode(INTERCEPTOR, name);
1373}
1374
1375
1376Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1377 GlobalObject* holder,
1378 JSGlobalPropertyCell* cell,
1379 JSFunction* function,
1380 String* name) {
1381 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001382 // -- r2 : name
1383 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001384 // -----------------------------------
1385 Label miss;
1386
1387 // Get the number of arguments.
1388 const int argc = arguments().immediate();
1389
1390 // Get the receiver from the stack.
1391 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1392
1393 // If the object is the holder then we know that it's a global
1394 // object which can only happen for contextual calls. In this case,
1395 // the receiver cannot be a smi.
1396 if (object != holder) {
1397 __ tst(r0, Operand(kSmiTagMask));
1398 __ b(eq, &miss);
1399 }
1400
1401 // Check that the maps haven't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001402 CheckPrototypes(object, r0, holder, r3, r1, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001403
1404 // Get the value from the cell.
1405 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1406 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1407
1408 // Check that the cell contains the same function.
Leon Clarkee46be812010-01-19 14:06:41 +00001409 if (Heap::InNewSpace(function)) {
1410 // We can't embed a pointer to a function in new space so we have
1411 // to verify that the shared function info is unchanged. This has
1412 // the nice side effect that multiple closures based on the same
1413 // function can all use this call IC. Before we load through the
1414 // function, we have to verify that it still is a function.
1415 __ tst(r1, Operand(kSmiTagMask));
1416 __ b(eq, &miss);
1417 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1418 __ b(ne, &miss);
1419
1420 // Check the shared function info. Make sure it hasn't changed.
1421 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
Andrei Popescu402d9372010-02-26 13:31:12 +00001422 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1423 __ cmp(r4, r3);
Leon Clarkee46be812010-01-19 14:06:41 +00001424 __ b(ne, &miss);
1425 } else {
1426 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1427 __ b(ne, &miss);
1428 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001429
1430 // Patch the receiver on the stack with the global proxy if
1431 // necessary.
1432 if (object->IsGlobalObject()) {
1433 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1434 __ str(r3, MemOperand(sp, argc * kPointerSize));
1435 }
1436
1437 // Setup the context (function already in r1).
1438 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1439
1440 // Jump to the cached code (tail call).
Steve Block6ded16b2010-05-10 14:33:55 +01001441 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001442 ASSERT(function->is_compiled());
1443 Handle<Code> code(function->code());
1444 ParameterCount expected(function->shared()->formal_parameter_count());
1445 __ InvokeCode(code, expected, arguments(),
1446 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1447
1448 // Handle call cache miss.
1449 __ bind(&miss);
1450 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001451 GenerateMissBranch();
Steve Blocka7e24c12009-10-30 11:49:00 +00001452
1453 // Return the generated code.
1454 return GetCode(NORMAL, name);
1455}
1456
1457
1458Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1459 int index,
1460 Map* transition,
1461 String* name) {
1462 // ----------- S t a t e -------------
1463 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001464 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001465 // -- r2 : name
1466 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001467 // -----------------------------------
1468 Label miss;
1469
Steve Blocka7e24c12009-10-30 11:49:00 +00001470 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001471 object,
1472 index,
1473 transition,
Andrei Popescu402d9372010-02-26 13:31:12 +00001474 r1, r2, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001475 &miss);
1476 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001477 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1478 __ Jump(ic, RelocInfo::CODE_TARGET);
1479
1480 // Return the generated code.
1481 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1482}
1483
1484
1485Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1486 AccessorInfo* callback,
1487 String* name) {
1488 // ----------- S t a t e -------------
1489 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001490 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001491 // -- r2 : name
1492 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001493 // -----------------------------------
1494 Label miss;
1495
Steve Blocka7e24c12009-10-30 11:49:00 +00001496 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001497 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001498 __ b(eq, &miss);
1499
1500 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001501 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1502 __ cmp(r3, Operand(Handle<Map>(object->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001503 __ b(ne, &miss);
1504
1505 // Perform global security token check if needed.
1506 if (object->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001507 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001508 }
1509
1510 // Stub never generated for non-global objects that require access
1511 // checks.
1512 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1513
Andrei Popescu402d9372010-02-26 13:31:12 +00001514 __ push(r1); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001515 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
Steve Block6ded16b2010-05-10 14:33:55 +01001516 __ Push(ip, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001517
1518 // Do tail-call to the runtime system.
1519 ExternalReference store_callback_property =
1520 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001521 __ TailCallExternalReference(store_callback_property, 4, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001522
1523 // Handle store cache miss.
1524 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001525 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1526 __ Jump(ic, RelocInfo::CODE_TARGET);
1527
1528 // Return the generated code.
1529 return GetCode(CALLBACKS, name);
1530}
1531
1532
1533Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1534 String* name) {
1535 // ----------- S t a t e -------------
1536 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001537 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001538 // -- r2 : name
1539 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001540 // -----------------------------------
1541 Label miss;
1542
Steve Blocka7e24c12009-10-30 11:49:00 +00001543 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001544 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001545 __ b(eq, &miss);
1546
1547 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001548 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1549 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001550 __ b(ne, &miss);
1551
1552 // Perform global security token check if needed.
1553 if (receiver->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001554 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001555 }
1556
Andrei Popescu402d9372010-02-26 13:31:12 +00001557 // Stub is never generated for non-global objects that require access
Steve Blocka7e24c12009-10-30 11:49:00 +00001558 // checks.
1559 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1560
Steve Block6ded16b2010-05-10 14:33:55 +01001561 __ Push(r1, r2, r0); // Receiver, name, value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001562
1563 // Do tail-call to the runtime system.
1564 ExternalReference store_ic_property =
1565 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001566 __ TailCallExternalReference(store_ic_property, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001567
1568 // Handle store cache miss.
1569 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001570 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1571 __ Jump(ic, RelocInfo::CODE_TARGET);
1572
1573 // Return the generated code.
1574 return GetCode(INTERCEPTOR, name);
1575}
1576
1577
1578Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1579 JSGlobalPropertyCell* cell,
1580 String* name) {
1581 // ----------- S t a t e -------------
1582 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001583 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001584 // -- r2 : name
1585 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001586 // -----------------------------------
1587 Label miss;
1588
1589 // Check that the map of the global has not changed.
Steve Blocka7e24c12009-10-30 11:49:00 +00001590 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1591 __ cmp(r3, Operand(Handle<Map>(object->map())));
1592 __ b(ne, &miss);
1593
1594 // Store the value in the cell.
1595 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1596 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
1597
Andrei Popescu402d9372010-02-26 13:31:12 +00001598 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001599 __ Ret();
1600
1601 // Handle store cache miss.
1602 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001603 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001604 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1605 __ Jump(ic, RelocInfo::CODE_TARGET);
1606
1607 // Return the generated code.
1608 return GetCode(NORMAL, name);
1609}
1610
1611
Steve Block6ded16b2010-05-10 14:33:55 +01001612Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1613 JSObject* object,
1614 JSObject* last) {
1615 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001616 // -- r0 : receiver
Steve Block6ded16b2010-05-10 14:33:55 +01001617 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001618 // -----------------------------------
1619 Label miss;
1620
Steve Block6ded16b2010-05-10 14:33:55 +01001621 // Check that receiver is not a smi.
1622 __ tst(r0, Operand(kSmiTagMask));
1623 __ b(eq, &miss);
1624
1625 // Check the maps of the full prototype chain.
1626 CheckPrototypes(object, r0, last, r3, r1, name, &miss);
1627
1628 // If the last object in the prototype chain is a global object,
1629 // check that the global property cell is empty.
1630 if (last->IsGlobalObject()) {
1631 Object* cell = GenerateCheckPropertyCell(masm(),
1632 GlobalObject::cast(last),
1633 name,
1634 r1,
1635 &miss);
1636 if (cell->IsFailure()) return cell;
1637 }
1638
1639 // Return undefined if maps of the full prototype chain are still the
1640 // same and no global property with this name contains a value.
1641 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1642 __ Ret();
1643
1644 __ bind(&miss);
1645 GenerateLoadMiss(masm(), Code::LOAD_IC);
1646
1647 // Return the generated code.
1648 return GetCode(NONEXISTENT, Heap::empty_string());
1649}
1650
1651
Steve Blocka7e24c12009-10-30 11:49:00 +00001652Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1653 JSObject* holder,
1654 int index,
1655 String* name) {
1656 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001657 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001658 // -- r2 : name
1659 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001660 // -----------------------------------
1661 Label miss;
1662
Steve Blocka7e24c12009-10-30 11:49:00 +00001663 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
1664 __ bind(&miss);
1665 GenerateLoadMiss(masm(), Code::LOAD_IC);
1666
1667 // Return the generated code.
1668 return GetCode(FIELD, name);
1669}
1670
1671
Leon Clarkee46be812010-01-19 14:06:41 +00001672Object* LoadStubCompiler::CompileLoadCallback(String* name,
1673 JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001674 JSObject* holder,
Leon Clarkee46be812010-01-19 14:06:41 +00001675 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001676 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001677 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001678 // -- r2 : name
1679 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001680 // -----------------------------------
1681 Label miss;
1682
Leon Clarkee46be812010-01-19 14:06:41 +00001683 Failure* failure = Failure::InternalError();
1684 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
1685 callback, name, &miss, &failure);
1686 if (!success) return failure;
1687
Steve Blocka7e24c12009-10-30 11:49:00 +00001688 __ bind(&miss);
1689 GenerateLoadMiss(masm(), Code::LOAD_IC);
1690
1691 // Return the generated code.
1692 return GetCode(CALLBACKS, name);
1693}
1694
1695
1696Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1697 JSObject* holder,
1698 Object* value,
1699 String* name) {
1700 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001701 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001702 // -- r2 : name
1703 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001704 // -----------------------------------
1705 Label miss;
1706
Steve Blocka7e24c12009-10-30 11:49:00 +00001707 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
1708 __ bind(&miss);
1709 GenerateLoadMiss(masm(), Code::LOAD_IC);
1710
1711 // Return the generated code.
1712 return GetCode(CONSTANT_FUNCTION, name);
1713}
1714
1715
1716Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1717 JSObject* holder,
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 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001727 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001728 GenerateLoadInterceptor(object,
1729 holder,
1730 &lookup,
1731 r0,
1732 r2,
1733 r3,
1734 r1,
1735 name,
1736 &miss);
1737 __ bind(&miss);
1738 GenerateLoadMiss(masm(), Code::LOAD_IC);
1739
1740 // Return the generated code.
1741 return GetCode(INTERCEPTOR, name);
1742}
1743
1744
1745Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1746 GlobalObject* holder,
1747 JSGlobalPropertyCell* cell,
1748 String* name,
1749 bool is_dont_delete) {
1750 // ----------- S t a t e -------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001751 // -- r0 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001752 // -- r2 : name
1753 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001754 // -----------------------------------
1755 Label miss;
1756
Steve Blocka7e24c12009-10-30 11:49:00 +00001757 // If the object is the holder then we know that it's a global
1758 // object which can only happen for contextual calls. In this case,
1759 // the receiver cannot be a smi.
1760 if (object != holder) {
Steve Block6ded16b2010-05-10 14:33:55 +01001761 __ tst(r0, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001762 __ b(eq, &miss);
1763 }
1764
1765 // Check that the map of the global has not changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001766 CheckPrototypes(object, r0, holder, r3, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001767
1768 // Get the value from the cell.
1769 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
Steve Block6ded16b2010-05-10 14:33:55 +01001770 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001771
1772 // Check for deleted property if property can actually be deleted.
1773 if (!is_dont_delete) {
1774 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
Steve Block6ded16b2010-05-10 14:33:55 +01001775 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00001776 __ b(eq, &miss);
1777 }
1778
Steve Block6ded16b2010-05-10 14:33:55 +01001779 __ mov(r0, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001780 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1781 __ Ret();
1782
1783 __ bind(&miss);
1784 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1785 GenerateLoadMiss(masm(), Code::LOAD_IC);
1786
1787 // Return the generated code.
1788 return GetCode(NORMAL, name);
1789}
1790
1791
1792Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1793 JSObject* receiver,
1794 JSObject* holder,
1795 int index) {
1796 // ----------- S t a t e -------------
1797 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001798 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001799 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001800 // -----------------------------------
1801 Label miss;
1802
Steve Block6ded16b2010-05-10 14:33:55 +01001803 // Check the key is the cached one.
1804 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001805 __ b(ne, &miss);
1806
Steve Block6ded16b2010-05-10 14:33:55 +01001807 GenerateLoadField(receiver, holder, r1, r2, r3, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001808 __ bind(&miss);
1809 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1810
1811 return GetCode(FIELD, name);
1812}
1813
1814
1815Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1816 JSObject* receiver,
1817 JSObject* holder,
1818 AccessorInfo* callback) {
1819 // ----------- S t a t e -------------
1820 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001821 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001822 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001823 // -----------------------------------
1824 Label miss;
1825
Steve Block6ded16b2010-05-10 14:33:55 +01001826 // Check the key is the cached one.
1827 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001828 __ b(ne, &miss);
1829
Leon Clarkee46be812010-01-19 14:06:41 +00001830 Failure* failure = Failure::InternalError();
Steve Block6ded16b2010-05-10 14:33:55 +01001831 bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001832 callback, name, &miss, &failure);
1833 if (!success) return failure;
1834
Steve Blocka7e24c12009-10-30 11:49:00 +00001835 __ bind(&miss);
1836 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1837
1838 return GetCode(CALLBACKS, name);
1839}
1840
1841
1842Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1843 JSObject* receiver,
1844 JSObject* holder,
1845 Object* value) {
1846 // ----------- S t a t e -------------
1847 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001848 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001849 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001850 // -----------------------------------
1851 Label miss;
1852
Steve Block6ded16b2010-05-10 14:33:55 +01001853 // Check the key is the cached one.
1854 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001855 __ b(ne, &miss);
1856
Steve Block6ded16b2010-05-10 14:33:55 +01001857 GenerateLoadConstant(receiver, holder, r1, r2, r3, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001858 __ bind(&miss);
1859 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1860
1861 // Return the generated code.
1862 return GetCode(CONSTANT_FUNCTION, name);
1863}
1864
1865
1866Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1867 JSObject* holder,
1868 String* name) {
1869 // ----------- S t a t e -------------
1870 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001871 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001872 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001873 // -----------------------------------
1874 Label miss;
1875
Steve Block6ded16b2010-05-10 14:33:55 +01001876 // Check the key is the cached one.
1877 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001878 __ b(ne, &miss);
1879
1880 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001881 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001882 GenerateLoadInterceptor(receiver,
1883 holder,
1884 &lookup,
Steve Block6ded16b2010-05-10 14:33:55 +01001885 r1,
Steve Blocka7e24c12009-10-30 11:49:00 +00001886 r0,
1887 r2,
1888 r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001889 name,
1890 &miss);
1891 __ bind(&miss);
1892 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1893
1894 return GetCode(INTERCEPTOR, name);
1895}
1896
1897
1898Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1899 // ----------- S t a t e -------------
1900 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001901 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001902 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001903 // -----------------------------------
1904 Label miss;
1905
Steve Block6ded16b2010-05-10 14:33:55 +01001906 // Check the key is the cached one.
1907 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001908 __ b(ne, &miss);
1909
Steve Block6ded16b2010-05-10 14:33:55 +01001910 GenerateLoadArrayLength(masm(), r1, r2, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001911 __ bind(&miss);
1912 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1913
1914 return GetCode(CALLBACKS, name);
1915}
1916
1917
1918Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
1919 // ----------- S t a t e -------------
1920 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001921 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001922 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001923 // -----------------------------------
1924 Label miss;
1925 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1926
Steve Block6ded16b2010-05-10 14:33:55 +01001927 // Check the key is the cached one.
1928 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001929 __ b(ne, &miss);
1930
Steve Block6ded16b2010-05-10 14:33:55 +01001931 GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001932 __ bind(&miss);
1933 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1934
1935 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1936
1937 return GetCode(CALLBACKS, name);
1938}
1939
1940
1941// TODO(1224671): implement the fast case.
1942Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1943 // ----------- S t a t e -------------
1944 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001945 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001946 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001947 // -----------------------------------
1948 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1949
1950 return GetCode(CALLBACKS, name);
1951}
1952
1953
1954Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1955 int index,
1956 Map* transition,
1957 String* name) {
1958 // ----------- S t a t e -------------
1959 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01001960 // -- r1 : key
1961 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001962 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001963 // -----------------------------------
1964 Label miss;
1965
Leon Clarkef7060e22010-06-03 12:02:55 +01001966 __ IncrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001967
1968 // Check that the name has not changed.
Leon Clarkef7060e22010-06-03 12:02:55 +01001969 __ cmp(r1, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001970 __ b(ne, &miss);
1971
Leon Clarkef7060e22010-06-03 12:02:55 +01001972 // r3 is used as scratch register. r1 and r2 keep their values if a jump to
1973 // the miss label is generated.
Steve Blocka7e24c12009-10-30 11:49:00 +00001974 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001975 object,
1976 index,
1977 transition,
Leon Clarkef7060e22010-06-03 12:02:55 +01001978 r2, r1, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001979 &miss);
1980 __ bind(&miss);
1981
Leon Clarkef7060e22010-06-03 12:02:55 +01001982 __ DecrementCounter(&Counters::keyed_store_field, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001983 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
Leon Clarkef7060e22010-06-03 12:02:55 +01001984
Steve Blocka7e24c12009-10-30 11:49:00 +00001985 __ Jump(ic, RelocInfo::CODE_TARGET);
1986
1987 // Return the generated code.
1988 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1989}
1990
1991
1992Object* ConstructStubCompiler::CompileConstructStub(
1993 SharedFunctionInfo* shared) {
1994 // ----------- S t a t e -------------
1995 // -- r0 : argc
1996 // -- r1 : constructor
1997 // -- lr : return address
1998 // -- [sp] : last argument
1999 // -----------------------------------
2000 Label generic_stub_call;
2001
2002 // Use r7 for holding undefined which is used in several places below.
2003 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2004
2005#ifdef ENABLE_DEBUGGER_SUPPORT
2006 // Check to see whether there are any break points in the function code. If
2007 // there are jump to the generic constructor stub which calls the actual
2008 // code for the function thereby hitting the break points.
2009 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2010 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2011 __ cmp(r2, r7);
2012 __ b(ne, &generic_stub_call);
2013#endif
2014
2015 // Load the initial map and verify that it is in fact a map.
2016 // r1: constructor function
2017 // r7: undefined
2018 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2019 __ tst(r2, Operand(kSmiTagMask));
2020 __ b(eq, &generic_stub_call);
2021 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2022 __ b(ne, &generic_stub_call);
2023
2024#ifdef DEBUG
2025 // Cannot construct functions this way.
2026 // r0: argc
2027 // r1: constructor function
2028 // r2: initial map
2029 // r7: undefined
2030 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2031 __ Check(ne, "Function constructed by construct stub.");
2032#endif
2033
2034 // Now allocate the JSObject in new space.
2035 // r0: argc
2036 // r1: constructor function
2037 // r2: initial map
2038 // r7: undefined
2039 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
2040 __ AllocateInNewSpace(r3,
2041 r4,
2042 r5,
2043 r6,
2044 &generic_stub_call,
Kristian Monsen25f61362010-05-21 11:50:48 +01002045 SIZE_IN_WORDS);
Steve Blocka7e24c12009-10-30 11:49:00 +00002046
2047 // Allocated the JSObject, now initialize the fields. Map is set to initial
2048 // map and properties and elements are set to empty fixed array.
2049 // r0: argc
2050 // r1: constructor function
2051 // r2: initial map
2052 // r3: object size (in words)
2053 // r4: JSObject (not tagged)
2054 // r7: undefined
2055 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2056 __ mov(r5, r4);
2057 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2058 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2059 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2060 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2061 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2062 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2063
2064 // Calculate the location of the first argument. The stack contains only the
2065 // argc arguments.
2066 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2067
2068 // Fill all the in-object properties with undefined.
2069 // r0: argc
2070 // r1: first argument
2071 // r3: object size (in words)
2072 // r4: JSObject (not tagged)
2073 // r5: First in-object property of JSObject (not tagged)
2074 // r7: undefined
2075 // Fill the initialized properties with a constant value or a passed argument
2076 // depending on the this.x = ...; assignment in the function.
2077 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2078 if (shared->IsThisPropertyAssignmentArgument(i)) {
2079 Label not_passed, next;
2080 // Check if the argument assigned to the property is actually passed.
2081 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2082 __ cmp(r0, Operand(arg_number));
2083 __ b(le, &not_passed);
2084 // Argument passed - find it on the stack.
2085 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2086 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2087 __ b(&next);
2088 __ bind(&not_passed);
2089 // Set the property to undefined.
2090 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2091 __ bind(&next);
2092 } else {
2093 // Set the property to the constant value.
2094 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2095 __ mov(r2, Operand(constant));
2096 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2097 }
2098 }
2099
2100 // Fill the unused in-object property fields with undefined.
2101 for (int i = shared->this_property_assignments_count();
2102 i < shared->CalculateInObjectProperties();
2103 i++) {
2104 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2105 }
2106
2107 // r0: argc
2108 // r4: JSObject (not tagged)
2109 // Move argc to r1 and the JSObject to return to r0 and tag it.
2110 __ mov(r1, r0);
2111 __ mov(r0, r4);
2112 __ orr(r0, r0, Operand(kHeapObjectTag));
2113
2114 // r0: JSObject
2115 // r1: argc
2116 // Remove caller arguments and receiver from the stack and return.
2117 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2118 __ add(sp, sp, Operand(kPointerSize));
2119 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2120 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2121 __ Jump(lr);
2122
2123 // Jump to the generic stub in case the specialized code cannot handle the
2124 // construction.
2125 __ bind(&generic_stub_call);
2126 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2127 Handle<Code> generic_construct_stub(code);
2128 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2129
2130 // Return the generated code.
2131 return GetCode();
2132}
2133
2134
2135#undef __
2136
2137} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01002138
2139#endif // V8_TARGET_ARCH_ARM