blob: bbffef22da54a69541a91a11dd7ab3c62bdb92c7 [file] [log] [blame]
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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
30#include "ic-inl.h"
31#include "codegen-inl.h"
32#include "stub-cache.h"
33
kasperl@chromium.org71affb52009-05-26 05:44:31 +000034namespace v8 {
35namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
ager@chromium.org65dad4b2009-04-23 08:48:43 +000037#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
39
40static void ProbeTable(MacroAssembler* masm,
41 Code::Flags flags,
42 StubCache::Table table,
43 Register name,
44 Register offset) {
45 ExternalReference key_offset(SCTableReference::keyReference(table));
46 ExternalReference value_offset(SCTableReference::valueReference(table));
47
48 Label miss;
49
50 // Save the offset on the stack.
51 __ push(offset);
52
53 // Check that the key in the entry matches the name.
54 __ mov(ip, Operand(key_offset));
55 __ ldr(ip, MemOperand(ip, offset, LSL, 1));
56 __ cmp(name, Operand(ip));
57 __ b(ne, &miss);
58
59 // Get the code entry from the cache.
60 __ mov(ip, Operand(value_offset));
61 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
62
63 // Check that the flags match what we're looking for.
64 __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
kasperl@chromium.org71affb52009-05-26 05:44:31 +000065 __ and_(offset, offset, Operand(~Code::kFlagsNotUsedInLookup));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066 __ cmp(offset, Operand(flags));
67 __ b(ne, &miss);
68
69 // Restore offset and re-load code entry from cache.
70 __ pop(offset);
71 __ mov(ip, Operand(value_offset));
72 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
73
74 // Jump to the first instruction in the code stub.
75 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
76 __ Jump(offset);
77
78 // Miss: Restore offset and fall through.
79 __ bind(&miss);
80 __ pop(offset);
81}
82
83
84void StubCache::GenerateProbe(MacroAssembler* masm,
85 Code::Flags flags,
86 Register receiver,
87 Register name,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000088 Register scratch,
89 Register extra) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090 Label miss;
91
92 // Make sure that code is valid. The shifting code relies on the
93 // entry size being 8.
94 ASSERT(sizeof(Entry) == 8);
95
96 // Make sure the flags does not name a specific type.
97 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
98
99 // Make sure that there are no register conflicts.
100 ASSERT(!scratch.is(receiver));
101 ASSERT(!scratch.is(name));
102
103 // Check that the receiver isn't a smi.
104 __ tst(receiver, Operand(kSmiTagMask));
105 __ b(eq, &miss);
106
107 // Get the map of the receiver and compute the hash.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000108 __ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000109 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 __ add(scratch, scratch, Operand(ip));
111 __ eor(scratch, scratch, Operand(flags));
112 __ and_(scratch,
113 scratch,
114 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
115
116 // Probe the primary table.
117 ProbeTable(masm, flags, kPrimary, name, scratch);
118
119 // Primary miss: Compute hash for secondary probe.
120 __ sub(scratch, scratch, Operand(name));
121 __ add(scratch, scratch, Operand(flags));
122 __ and_(scratch,
123 scratch,
124 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
125
126 // Probe the secondary table.
127 ProbeTable(masm, flags, kSecondary, name, scratch);
128
129 // Cache miss: Fall-through and let caller handle the miss by
130 // entering the runtime system.
131 __ bind(&miss);
132}
133
134
135void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
136 int index,
137 Register prototype) {
138 // Load the global or builtins object from the current context.
139 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
140 // Load the global context from the global or builtins object.
141 __ ldr(prototype,
142 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
143 // Load the function from the global context.
144 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
145 // Load the initial map. The global functions all have initial maps.
146 __ ldr(prototype,
147 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
148 // Load the prototype from the initial map.
149 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
150}
151
152
ager@chromium.org7c537e22008-10-16 08:43:32 +0000153// Load a fast property out of a holder object (src). In-object properties
154// are loaded directly otherwise the property is loaded from the properties
155// fixed array.
156void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
157 Register dst, Register src,
158 JSObject* holder, int index) {
159 // Adjust for the number of properties stored in the holder.
160 index -= holder->map()->inobject_properties();
161 if (index < 0) {
162 // Get the property straight out of the holder.
163 int offset = holder->map()->instance_size() + (index * kPointerSize);
164 __ ldr(dst, FieldMemOperand(src, offset));
165 } else {
166 // Calculate the offset into the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000167 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000168 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
169 __ ldr(dst, FieldMemOperand(dst, offset));
170 }
171}
172
173
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000174void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
175 Register receiver,
176 Register scratch,
177 Label* miss_label) {
178 // Check that the receiver isn't a smi.
179 __ tst(receiver, Operand(kSmiTagMask));
180 __ b(eq, miss_label);
181
182 // Check that the object is a JS array.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000183 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000184 __ b(ne, miss_label);
185
186 // Load length directly from the JS array.
187 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
188 __ Ret();
189}
190
191
ager@chromium.org5c838252010-02-19 08:53:10 +0000192// Generate code to check if an object is a string. If the object is a
193// heap object, its map's instance type is left in the scratch1 register.
194// If this is not needed, scratch1 and scratch2 may be the same register.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000195static void GenerateStringCheck(MacroAssembler* masm,
196 Register receiver,
197 Register scratch1,
198 Register scratch2,
199 Label* smi,
200 Label* non_string_object) {
201 // Check that the receiver isn't a smi.
202 __ tst(receiver, Operand(kSmiTagMask));
203 __ b(eq, smi);
204
205 // Check that the object is a string.
206 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
207 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
208 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
209 // The cast is to resolve the overload for the argument of 0x0.
210 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
211 __ b(ne, non_string_object);
212}
213
214
ager@chromium.org32912102009-01-16 10:38:43 +0000215// Generate code to load the length from a string object and return the length.
216// If the receiver object is not a string or a wrapped string object the
217// execution continues at the miss label. The register containing the
218// receiver is potentially clobbered.
ager@chromium.org5c838252010-02-19 08:53:10 +0000219void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
220 Register receiver,
221 Register scratch1,
222 Register scratch2,
223 Label* miss) {
224 Label check_wrapper;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000225
226 // Check if the object is a string leaving the instance type in the
227 // scratch1 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000228 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000229
230 // Load length directly from the string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000231 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000232 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
233 __ Ret();
234
235 // Check if the object is a JSValue wrapper.
236 __ bind(&check_wrapper);
237 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
238 __ b(ne, miss);
239
ager@chromium.org5c838252010-02-19 08:53:10 +0000240 // Unwrap the value and check if the wrapped value is a string.
241 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
242 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
243 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
244 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
245 __ Ret();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000246}
247
248
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000249void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
250 Register receiver,
251 Register scratch1,
252 Register scratch2,
253 Label* miss_label) {
254 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
255 __ mov(r0, scratch1);
256 __ Ret();
257}
258
259
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000260// Generate StoreField code, value is passed in r0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000261// When leaving generated code after success, the receiver_reg and name_reg
262// may be clobbered. Upon branch to miss_label, the receiver and name
263// registers have their original values.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000264void StubCompiler::GenerateStoreField(MacroAssembler* masm,
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000265 JSObject* object,
266 int index,
267 Map* transition,
268 Register receiver_reg,
269 Register name_reg,
270 Register scratch,
271 Label* miss_label) {
272 // r0 : value
273 Label exit;
274
275 // Check that the receiver isn't a smi.
276 __ tst(receiver_reg, Operand(kSmiTagMask));
277 __ b(eq, miss_label);
278
279 // Check that the map of the receiver hasn't changed.
280 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
281 __ cmp(scratch, Operand(Handle<Map>(object->map())));
282 __ b(ne, miss_label);
283
284 // Perform global security token check if needed.
285 if (object->IsJSGlobalProxy()) {
286 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
287 }
288
289 // Stub never generated for non-global objects that require access
290 // checks.
291 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
292
293 // Perform map transition for the receiver if necessary.
294 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
295 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000296 // We jump to a runtime call that extends the properties array.
ager@chromium.org5c838252010-02-19 08:53:10 +0000297 __ push(receiver_reg);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000298 __ mov(r2, Operand(Handle<Map>(transition)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000299 __ stm(db_w, sp, r2.bit() | r0.bit());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000300 __ TailCallExternalReference(
ager@chromium.org5c838252010-02-19 08:53:10 +0000301 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)),
302 3, 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000303 return;
304 }
305
306 if (transition != NULL) {
307 // Update the map of the object; no write barrier updating is
308 // needed because the map is never in new space.
309 __ mov(ip, Operand(Handle<Map>(transition)));
310 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
311 }
312
313 // Adjust for the number of properties stored in the object. Even in the
314 // face of a transition we can use the old map here because the size of the
315 // object and the number of in-object properties is not going to change.
316 index -= object->map()->inobject_properties();
317
318 if (index < 0) {
319 // Set the property straight into the object.
320 int offset = object->map()->instance_size() + (index * kPointerSize);
321 __ str(r0, FieldMemOperand(receiver_reg, offset));
322
323 // Skip updating write barrier if storing a smi.
324 __ tst(r0, Operand(kSmiTagMask));
325 __ b(eq, &exit);
326
327 // Update the write barrier for the array address.
328 // Pass the value being stored in the now unused name_reg.
329 __ mov(name_reg, Operand(offset));
330 __ RecordWrite(receiver_reg, name_reg, scratch);
331 } else {
332 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000333 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000334 // Get the properties array
335 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
336 __ str(r0, FieldMemOperand(scratch, offset));
337
338 // Skip updating write barrier if storing a smi.
339 __ tst(r0, Operand(kSmiTagMask));
340 __ b(eq, &exit);
341
342 // Update the write barrier for the array address.
343 // Ok to clobber receiver_reg and name_reg, since we return.
344 __ mov(name_reg, Operand(offset));
345 __ RecordWrite(scratch, name_reg, receiver_reg);
346 }
347
348 // Return the value (register r0).
349 __ bind(&exit);
350 __ Ret();
351}
352
353
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000354void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
355 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
356 Code* code = NULL;
357 if (kind == Code::LOAD_IC) {
358 code = Builtins::builtin(Builtins::LoadIC_Miss);
359 } else {
360 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
361 }
362
363 Handle<Code> ic(code);
364 __ Jump(ic, RelocInfo::CODE_TARGET);
365}
366
367
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000368static void GenerateCallFunction(MacroAssembler* masm,
369 Object* object,
370 const ParameterCount& arguments,
371 Label* miss) {
372 // ----------- S t a t e -------------
373 // -- r0: receiver
374 // -- r1: function to call
375 // -----------------------------------
376
377 // Check that the function really is a function.
378 __ BranchOnSmi(r1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000379 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000380 __ b(ne, miss);
381
382 // Patch the receiver on the stack with the global proxy if
383 // necessary.
384 if (object->IsGlobalObject()) {
385 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
386 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
387 }
388
389 // Invoke the function.
390 __ InvokeFunction(r1, arguments, JUMP_FUNCTION);
391}
392
393
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000394static void PushInterceptorArguments(MacroAssembler* masm,
395 Register receiver,
396 Register holder,
397 Register name,
398 JSObject* holder_obj) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000399 __ push(name);
400 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
401 ASSERT(!Heap::InNewSpace(interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000402 Register scratch = name;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000403 __ mov(scratch, Operand(Handle<Object>(interceptor)));
404 __ push(scratch);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000405 __ push(receiver);
406 __ push(holder);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000407 __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
408 __ push(scratch);
409}
410
411
412static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
413 Register receiver,
414 Register holder,
415 Register name,
416 JSObject* holder_obj) {
417 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
418
419 ExternalReference ref =
420 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
421 __ mov(r0, Operand(5));
422 __ mov(r1, Operand(ref));
423
424 CEntryStub stub(1);
425 __ CallStub(&stub);
426}
427
428
429class LoadInterceptorCompiler BASE_EMBEDDED {
430 public:
431 explicit LoadInterceptorCompiler(Register name) : name_(name) {}
432
433 void CompileCacheable(MacroAssembler* masm,
434 StubCompiler* stub_compiler,
435 Register receiver,
436 Register holder,
437 Register scratch1,
438 Register scratch2,
439 JSObject* holder_obj,
440 LookupResult* lookup,
441 String* name,
442 Label* miss_label) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000443 AccessorInfo* callback = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000444 bool optimize = false;
445 // So far the most popular follow ups for interceptor loads are FIELD
446 // and CALLBACKS, so inline only them, other cases may be added
447 // later.
448 if (lookup->type() == FIELD) {
449 optimize = true;
450 } else if (lookup->type() == CALLBACKS) {
451 Object* callback_object = lookup->GetCallbackObject();
452 if (callback_object->IsAccessorInfo()) {
453 callback = AccessorInfo::cast(callback_object);
454 optimize = callback->getter() != NULL;
455 }
456 }
457
458 if (!optimize) {
459 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label);
460 return;
461 }
462
463 // Note: starting a frame here makes GC aware of pointers pushed below.
464 __ EnterInternalFrame();
465
ager@chromium.org5c838252010-02-19 08:53:10 +0000466 __ push(receiver);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000467 __ push(holder);
468 __ push(name_);
469
470 CompileCallLoadPropertyWithInterceptor(masm,
471 receiver,
472 holder,
473 name_,
474 holder_obj);
475
476 Label interceptor_failed;
477 // Compare with no_interceptor_result_sentinel.
478 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
479 __ cmp(r0, scratch1);
480 __ b(eq, &interceptor_failed);
481 __ LeaveInternalFrame();
482 __ Ret();
483
484 __ bind(&interceptor_failed);
485 __ pop(name_);
486 __ pop(holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000487 __ pop(receiver);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000488
489 __ LeaveInternalFrame();
490
491 if (lookup->type() == FIELD) {
492 holder = stub_compiler->CheckPrototypes(holder_obj,
493 holder,
494 lookup->holder(),
495 scratch1,
496 scratch2,
497 name,
498 miss_label);
499 stub_compiler->GenerateFastPropertyLoad(masm,
500 r0,
501 holder,
502 lookup->holder(),
503 lookup->GetFieldIndex());
504 __ Ret();
505 } else {
506 ASSERT(lookup->type() == CALLBACKS);
507 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
508 ASSERT(callback != NULL);
509 ASSERT(callback->getter() != NULL);
510
511 Label cleanup;
512 __ pop(scratch2);
513 __ push(receiver);
514 __ push(scratch2);
515
516 holder = stub_compiler->CheckPrototypes(holder_obj, holder,
517 lookup->holder(), scratch1,
518 scratch2,
519 name,
520 &cleanup);
521
522 __ push(holder);
523 __ Move(holder, Handle<AccessorInfo>(callback));
524 __ push(holder);
525 __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset));
526 __ push(scratch1);
527 __ push(name_);
528
529 ExternalReference ref =
530 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000531 __ TailCallExternalReference(ref, 5, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000532
533 __ bind(&cleanup);
534 __ pop(scratch1);
535 __ pop(scratch2);
536 __ push(scratch1);
537 }
538 }
539
540
541 void CompileRegular(MacroAssembler* masm,
542 Register receiver,
543 Register holder,
544 Register scratch,
545 JSObject* holder_obj,
546 Label* miss_label) {
547 PushInterceptorArguments(masm, receiver, holder, name_, holder_obj);
548
549 ExternalReference ref = ExternalReference(
550 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000551 __ TailCallExternalReference(ref, 5, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000552 }
553
554 private:
555 Register name_;
556};
557
558
ager@chromium.org5c838252010-02-19 08:53:10 +0000559static void CompileLoadInterceptor(LoadInterceptorCompiler* compiler,
560 StubCompiler* stub_compiler,
561 MacroAssembler* masm,
562 JSObject* object,
563 JSObject* holder,
564 String* name,
565 LookupResult* lookup,
566 Register receiver,
567 Register scratch1,
568 Register scratch2,
569 Label* miss) {
570 ASSERT(holder->HasNamedInterceptor());
571 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000572
ager@chromium.org5c838252010-02-19 08:53:10 +0000573 // Check that the receiver isn't a smi.
574 __ BranchOnSmi(receiver, miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000575
ager@chromium.org5c838252010-02-19 08:53:10 +0000576 // Check that the maps haven't changed.
577 Register reg =
578 stub_compiler->CheckPrototypes(object, receiver, holder,
579 scratch1, scratch2, name, miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000580
ager@chromium.org5c838252010-02-19 08:53:10 +0000581 if (lookup->IsProperty() && lookup->IsCacheable()) {
582 compiler->CompileCacheable(masm,
583 stub_compiler,
584 receiver,
585 reg,
586 scratch1,
587 scratch2,
588 holder,
589 lookup,
590 name,
591 miss);
592 } else {
593 compiler->CompileRegular(masm,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000594 receiver,
ager@chromium.org5c838252010-02-19 08:53:10 +0000595 reg,
596 scratch2,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000597 holder,
ager@chromium.org5c838252010-02-19 08:53:10 +0000598 miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000599 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000600}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000601
602
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000604#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000605
606
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000607Register StubCompiler::CheckPrototypes(JSObject* object,
608 Register object_reg,
609 JSObject* holder,
610 Register holder_reg,
611 Register scratch,
612 String* name,
ager@chromium.org5c838252010-02-19 08:53:10 +0000613 int save_at_depth,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000614 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000615 // TODO(602): support object saving.
616 ASSERT(save_at_depth == kInvalidProtoDepth);
617
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000618 // Check that the maps haven't changed.
619 Register result =
620 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
621
622 // If we've skipped any global objects, it's not enough to verify
623 // that their maps haven't changed.
624 while (object != holder) {
625 if (object->IsGlobalObject()) {
626 GlobalObject* global = GlobalObject::cast(object);
627 Object* probe = global->EnsurePropertyCell(name);
628 if (probe->IsFailure()) {
629 set_failure(Failure::cast(probe));
630 return result;
631 }
632 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
633 ASSERT(cell->value()->IsTheHole());
634 __ mov(scratch, Operand(Handle<Object>(cell)));
635 __ ldr(scratch,
636 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000637 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
638 __ cmp(scratch, ip);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000639 __ b(ne, miss);
640 }
641 object = JSObject::cast(object->GetPrototype());
642 }
643
ager@chromium.org5c838252010-02-19 08:53:10 +0000644 // Return the register containing the holder.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000645 return result;
646}
647
648
649void StubCompiler::GenerateLoadField(JSObject* object,
650 JSObject* holder,
651 Register receiver,
652 Register scratch1,
653 Register scratch2,
654 int index,
655 String* name,
656 Label* miss) {
657 // Check that the receiver isn't a smi.
658 __ tst(receiver, Operand(kSmiTagMask));
659 __ b(eq, miss);
660
661 // Check that the maps haven't changed.
662 Register reg =
663 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
664 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
665 __ Ret();
666}
667
668
669void StubCompiler::GenerateLoadConstant(JSObject* object,
670 JSObject* holder,
671 Register receiver,
672 Register scratch1,
673 Register scratch2,
674 Object* value,
675 String* name,
676 Label* miss) {
677 // Check that the receiver isn't a smi.
678 __ tst(receiver, Operand(kSmiTagMask));
679 __ b(eq, miss);
680
681 // Check that the maps haven't changed.
682 Register reg =
683 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
684
685 // Return the constant value.
686 __ mov(r0, Operand(Handle<Object>(value)));
687 __ Ret();
688}
689
690
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000691bool StubCompiler::GenerateLoadCallback(JSObject* object,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000692 JSObject* holder,
693 Register receiver,
694 Register name_reg,
695 Register scratch1,
696 Register scratch2,
697 AccessorInfo* callback,
698 String* name,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000699 Label* miss,
700 Failure** failure) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000701 // Check that the receiver isn't a smi.
702 __ tst(receiver, Operand(kSmiTagMask));
703 __ b(eq, miss);
704
705 // Check that the maps haven't changed.
706 Register reg =
707 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
708
709 // Push the arguments on the JS stack of the caller.
710 __ push(receiver); // receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000711 __ push(reg); // holder
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000712 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
713 __ push(ip);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000714 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
715 __ push(reg);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000716 __ push(name_reg); // name
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000717
718 // Do tail-call to the runtime system.
719 ExternalReference load_callback_property =
720 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000721 __ TailCallExternalReference(load_callback_property, 5, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000722
723 return true;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000724}
725
726
727void StubCompiler::GenerateLoadInterceptor(JSObject* object,
728 JSObject* holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000729 LookupResult* lookup,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000730 Register receiver,
731 Register name_reg,
732 Register scratch1,
733 Register scratch2,
734 String* name,
735 Label* miss) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000736 LoadInterceptorCompiler compiler(name_reg);
737 CompileLoadInterceptor(&compiler,
738 this,
739 masm(),
740 object,
741 holder,
742 name,
743 lookup,
744 receiver,
745 scratch1,
746 scratch2,
747 miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000748}
749
750
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000752 // ----------- S t a t e -------------
753 // -- r1: function
754 // -- lr: return address
755 // -----------------------------------
756
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000757 // Enter an internal frame.
758 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000759
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000760 // Preserve the function.
761 __ push(r1);
762
763 // Push the function on the stack as the argument to the runtime function.
764 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000765 __ CallRuntime(Runtime::kLazyCompile, 1);
766
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000767 // Calculate the entry point.
768 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000770 // Restore saved function.
771 __ pop(r1);
772
773 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000774 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000775
776 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000777 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000779 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000780}
781
782
ager@chromium.org5c838252010-02-19 08:53:10 +0000783Object* CallStubCompiler::CompileCallField(JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000784 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000785 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000786 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000788 // -- r2 : name
789 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000790 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000791 Label miss;
792
mads.s.ager31e71382008-08-13 09:32:07 +0000793 const int argc = arguments().immediate();
794
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000795 // Get the receiver of the function from the stack into r0.
796 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 // Check that the receiver isn't a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000798 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000799 __ b(eq, &miss);
800
801 // Do the right check and compute the holder register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000802 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000803 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000804
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000805 GenerateCallFunction(masm(), object, arguments(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806
807 // Handle call cache miss.
808 __ bind(&miss);
809 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000810 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811
812 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000813 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000814}
815
816
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000817Object* CallStubCompiler::CompileArrayPushCall(Object* object,
818 JSObject* holder,
819 JSFunction* function,
820 String* name,
821 CheckType check) {
822 // ----------- S t a t e -------------
823 // -- r2 : name
824 // -- lr : return address
825 // -----------------------------------
826
827 // TODO(639): faster implementation.
828 ASSERT(check == RECEIVER_MAP_CHECK);
829
830 Label miss;
831
832 // Get the receiver from the stack
833 const int argc = arguments().immediate();
834 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
835
836 // Check that the receiver isn't a smi.
837 __ tst(r1, Operand(kSmiTagMask));
838 __ b(eq, &miss);
839
840 // Check that the maps haven't changed.
841 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
842
843 if (object->IsGlobalObject()) {
844 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
845 __ str(r3, MemOperand(sp, argc * kPointerSize));
846 }
847
848 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
849 argc + 1,
850 1);
851
852 // Handle call cache miss.
853 __ bind(&miss);
854 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
855 __ Jump(ic, RelocInfo::CODE_TARGET);
856
857 // Return the generated code.
858 String* function_name = NULL;
859 if (function->shared()->name()->IsString()) {
860 function_name = String::cast(function->shared()->name());
861 }
862 return GetCode(CONSTANT_FUNCTION, function_name);
863}
864
865
866Object* CallStubCompiler::CompileArrayPopCall(Object* object,
867 JSObject* holder,
868 JSFunction* function,
869 String* name,
870 CheckType check) {
871 // ----------- S t a t e -------------
872 // -- r2 : name
873 // -- lr : return address
874 // -----------------------------------
875
876 // TODO(642): faster implementation.
877 ASSERT(check == RECEIVER_MAP_CHECK);
878
879 Label miss;
880
881 // Get the receiver from the stack
882 const int argc = arguments().immediate();
883 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
884
885 // Check that the receiver isn't a smi.
886 __ tst(r1, Operand(kSmiTagMask));
887 __ b(eq, &miss);
888
889 // Check that the maps haven't changed.
890 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
891
892 if (object->IsGlobalObject()) {
893 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
894 __ str(r3, MemOperand(sp, argc * kPointerSize));
895 }
896
897 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
898 argc + 1,
899 1);
900
901 // Handle call cache miss.
902 __ bind(&miss);
903 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
904 __ Jump(ic, RelocInfo::CODE_TARGET);
905
906 // Return the generated code.
907 String* function_name = NULL;
908 if (function->shared()->name()->IsString()) {
909 function_name = String::cast(function->shared()->name());
910 }
911 return GetCode(CONSTANT_FUNCTION, function_name);
912}
913
914
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000915Object* CallStubCompiler::CompileCallConstant(Object* object,
916 JSObject* holder,
917 JSFunction* function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000918 String* name,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000919 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000921 // -- r2 : name
922 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000924 SharedFunctionInfo* function_info = function->shared();
925 if (function_info->HasCustomCallGenerator()) {
926 CustomCallGenerator generator =
927 ToCData<CustomCallGenerator>(function_info->function_data());
928 return generator(this, object, holder, function, name, check);
929 }
930
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 Label miss;
932
mads.s.ager31e71382008-08-13 09:32:07 +0000933 // Get the receiver from the stack
934 const int argc = arguments().immediate();
935 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
936
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937 // Check that the receiver isn't a smi.
938 if (check != NUMBER_CHECK) {
939 __ tst(r1, Operand(kSmiTagMask));
940 __ b(eq, &miss);
941 }
942
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000943 // Make sure that it's okay not to patch the on stack receiver
944 // unless we're doing a receiver map check.
945 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
946
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947 switch (check) {
948 case RECEIVER_MAP_CHECK:
949 // Check that the maps haven't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +0000950 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000951
952 // Patch the receiver on the stack with the global proxy if
953 // necessary.
954 if (object->IsGlobalObject()) {
955 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
956 __ str(r3, MemOperand(sp, argc * kPointerSize));
957 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000958 break;
959
960 case STRING_CHECK:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000961 if (!function->IsBuiltin()) {
962 // Calling non-builtins with a value as receiver requires boxing.
963 __ jmp(&miss);
964 } else {
965 // Check that the object is a two-byte string or a symbol.
ager@chromium.org5c838252010-02-19 08:53:10 +0000966 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000967 __ b(hs, &miss);
968 // Check that the maps starting from the prototype haven't changed.
969 GenerateLoadGlobalFunctionPrototype(masm(),
970 Context::STRING_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +0000971 r0);
972 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000973 r1, name, &miss);
974 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000975 break;
976
977 case NUMBER_CHECK: {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000978 if (!function->IsBuiltin()) {
979 // Calling non-builtins with a value as receiver requires boxing.
980 __ jmp(&miss);
981 } else {
982 Label fast;
983 // Check that the object is a smi or a heap number.
984 __ tst(r1, Operand(kSmiTagMask));
985 __ b(eq, &fast);
ager@chromium.org5c838252010-02-19 08:53:10 +0000986 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000987 __ b(ne, &miss);
988 __ bind(&fast);
989 // Check that the maps starting from the prototype haven't changed.
990 GenerateLoadGlobalFunctionPrototype(masm(),
991 Context::NUMBER_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +0000992 r0);
993 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000994 r1, name, &miss);
995 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 break;
997 }
998
999 case BOOLEAN_CHECK: {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001000 if (!function->IsBuiltin()) {
1001 // Calling non-builtins with a value as receiver requires boxing.
1002 __ jmp(&miss);
1003 } else {
1004 Label fast;
1005 // Check that the object is a boolean.
1006 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1007 __ cmp(r1, ip);
1008 __ b(eq, &fast);
1009 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1010 __ cmp(r1, ip);
1011 __ b(ne, &miss);
1012 __ bind(&fast);
1013 // Check that the maps starting from the prototype haven't changed.
1014 GenerateLoadGlobalFunctionPrototype(masm(),
1015 Context::BOOLEAN_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +00001016 r0);
1017 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001018 r1, name, &miss);
1019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020 break;
1021 }
1022
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023 default:
1024 UNREACHABLE();
1025 }
1026
ager@chromium.org5c838252010-02-19 08:53:10 +00001027 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001028
1029 // Handle call cache miss.
1030 __ bind(&miss);
1031 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001032 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033
1034 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001035 String* function_name = NULL;
1036 if (function->shared()->name()->IsString()) {
1037 function_name = String::cast(function->shared()->name());
1038 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001039 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001040}
1041
1042
ager@chromium.org5c838252010-02-19 08:53:10 +00001043Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044 JSObject* holder,
1045 String* name) {
1046 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001047 // -- r2 : name
1048 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049 // -----------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001050 ASSERT(holder->HasNamedInterceptor());
1051 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052 Label miss;
1053
ager@chromium.org5c838252010-02-19 08:53:10 +00001054 const Register receiver = r0;
1055 const Register holder_reg = r1;
1056 const Register name_reg = r2;
1057 const Register scratch = r3;
1058
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001059 // Get the number of arguments.
1060 const int argc = arguments().immediate();
1061
1062 LookupResult lookup;
1063 LookupPostInterceptor(holder, name, &lookup);
1064
1065 // Get the receiver from the stack into r0.
1066 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001067
ager@chromium.org5c838252010-02-19 08:53:10 +00001068 // Check that the receiver isn't a smi.
1069 __ BranchOnSmi(receiver, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001070
ager@chromium.org5c838252010-02-19 08:53:10 +00001071 // Check that the maps haven't changed.
1072 Register reg = CheckPrototypes(object, receiver, holder, holder_reg,
1073 scratch, name, &miss);
1074 if (!reg.is(holder_reg)) {
1075 __ mov(holder_reg, reg);
1076 }
1077
1078 // If we call a constant function when the interceptor returns
1079 // the no-result sentinel, generate code that optimizes this case.
1080 if (lookup.IsProperty() &&
1081 lookup.IsCacheable() &&
1082 lookup.type() == CONSTANT_FUNCTION &&
1083 lookup.GetConstantFunction()->is_compiled() &&
1084 !holder->IsJSArray()) {
1085 // Constant functions cannot sit on global object.
1086 ASSERT(!lookup.holder()->IsGlobalObject());
1087
1088 // Call the interceptor.
1089 __ EnterInternalFrame();
1090 __ push(holder_reg);
1091 __ push(name_reg);
1092 CompileCallLoadPropertyWithInterceptor(masm(),
1093 receiver,
1094 holder_reg,
1095 name_reg,
1096 holder);
1097 __ pop(name_reg);
1098 __ pop(holder_reg);
1099 __ LeaveInternalFrame();
1100 // r0 no longer contains the receiver.
1101
1102 // If interceptor returns no-result sentinal, call the constant function.
1103 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1104 __ cmp(r0, scratch);
1105 Label invoke;
1106 __ b(ne, &invoke);
1107 // Check the prototypes between the interceptor's holder and the
1108 // constant function's holder.
1109 CheckPrototypes(holder, holder_reg,
1110 lookup.holder(), r0,
1111 scratch,
1112 name,
1113 &miss);
1114
1115 __ InvokeFunction(lookup.GetConstantFunction(),
1116 arguments(),
1117 JUMP_FUNCTION);
1118
1119 __ bind(&invoke);
1120
1121 } else {
1122 // Call a runtime function to load the interceptor property.
1123 __ EnterInternalFrame();
1124 __ push(name_reg);
1125
1126 PushInterceptorArguments(masm(), receiver, holder_reg, name_reg, holder);
1127
1128 __ CallExternalReference(
1129 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
1130 5);
1131
1132 __ pop(name_reg);
1133 __ LeaveInternalFrame();
1134 }
1135
1136 // Move returned value, the function to call, to r1.
1137 __ mov(r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001138 // Restore receiver.
ager@chromium.org5c838252010-02-19 08:53:10 +00001139 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001140
1141 GenerateCallFunction(masm(), object, arguments(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142
1143 // Handle call cache miss.
1144 __ bind(&miss);
1145 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001146 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147
1148 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001149 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150}
1151
1152
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001153Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1154 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001155 JSGlobalPropertyCell* cell,
1156 JSFunction* function,
1157 String* name) {
1158 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001159 // -- r2 : name
1160 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001161 // -----------------------------------
1162 Label miss;
1163
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001164 // Get the number of arguments.
1165 const int argc = arguments().immediate();
1166
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001167 // Get the receiver from the stack.
1168 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1169
1170 // If the object is the holder then we know that it's a global
1171 // object which can only happen for contextual calls. In this case,
1172 // the receiver cannot be a smi.
1173 if (object != holder) {
1174 __ tst(r0, Operand(kSmiTagMask));
1175 __ b(eq, &miss);
1176 }
1177
1178 // Check that the maps haven't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001179 CheckPrototypes(object, r0, holder, r3, r1, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001180
1181 // Get the value from the cell.
1182 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1183 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1184
1185 // Check that the cell contains the same function.
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001186 if (Heap::InNewSpace(function)) {
1187 // We can't embed a pointer to a function in new space so we have
1188 // to verify that the shared function info is unchanged. This has
1189 // the nice side effect that multiple closures based on the same
1190 // function can all use this call IC. Before we load through the
1191 // function, we have to verify that it still is a function.
1192 __ tst(r1, Operand(kSmiTagMask));
1193 __ b(eq, &miss);
1194 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1195 __ b(ne, &miss);
1196
1197 // Check the shared function info. Make sure it hasn't changed.
1198 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
ager@chromium.org5c838252010-02-19 08:53:10 +00001199 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1200 __ cmp(r4, r3);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001201 __ b(ne, &miss);
1202 } else {
1203 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1204 __ b(ne, &miss);
1205 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001206
1207 // Patch the receiver on the stack with the global proxy if
1208 // necessary.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001209 if (object->IsGlobalObject()) {
1210 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1211 __ str(r3, MemOperand(sp, argc * kPointerSize));
1212 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001213
1214 // Setup the context (function already in r1).
1215 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1216
1217 // Jump to the cached code (tail call).
ager@chromium.org5c838252010-02-19 08:53:10 +00001218 __ IncrementCounter(&Counters::call_global_inline, 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001219 ASSERT(function->is_compiled());
1220 Handle<Code> code(function->code());
1221 ParameterCount expected(function->shared()->formal_parameter_count());
1222 __ InvokeCode(code, expected, arguments(),
1223 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1224
1225 // Handle call cache miss.
1226 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001227 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
1228 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1229 __ Jump(ic, RelocInfo::CODE_TARGET);
1230
1231 // Return the generated code.
1232 return GetCode(NORMAL, name);
1233}
1234
1235
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1237 int index,
1238 Map* transition,
1239 String* name) {
1240 // ----------- S t a t e -------------
1241 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001242 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001243 // -- r2 : name
1244 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001246 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001248 GenerateStoreField(masm(),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001249 object,
1250 index,
1251 transition,
ager@chromium.org5c838252010-02-19 08:53:10 +00001252 r1, r2, r3,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001253 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001256 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257
1258 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001259 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260}
1261
1262
1263Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1264 AccessorInfo* callback,
1265 String* name) {
1266 // ----------- S t a t e -------------
1267 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001268 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269 // -- r2 : name
1270 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001271 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272 Label miss;
1273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 // Check that the object isn't a smi.
ager@chromium.org5c838252010-02-19 08:53:10 +00001275 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001276 __ b(eq, &miss);
1277
1278 // Check that the map of the object hasn't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001279 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1280 __ cmp(r3, Operand(Handle<Map>(object->map())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281 __ b(ne, &miss);
1282
1283 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001284 if (object->IsJSGlobalProxy()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001285 __ CheckAccessGlobalProxy(r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 }
1287
1288 // Stub never generated for non-global objects that require access
1289 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001290 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291
ager@chromium.org5c838252010-02-19 08:53:10 +00001292 __ push(r1); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
ager@chromium.org5c838252010-02-19 08:53:10 +00001294 __ stm(db_w, sp, ip.bit() | r2.bit() | r0.bit());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295
mads.s.ager31e71382008-08-13 09:32:07 +00001296 // Do tail-call to the runtime system.
1297 ExternalReference store_callback_property =
1298 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001299 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300
1301 // Handle store cache miss.
1302 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001304 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305
1306 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001307 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001308}
1309
1310
1311Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1312 String* name) {
1313 // ----------- S t a t e -------------
1314 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001315 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 // -- r2 : name
1317 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319 Label miss;
1320
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 // Check that the object isn't a smi.
ager@chromium.org5c838252010-02-19 08:53:10 +00001322 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323 __ b(eq, &miss);
1324
1325 // Check that the map of the object hasn't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001326 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1327 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001328 __ b(ne, &miss);
1329
1330 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001331 if (receiver->IsJSGlobalProxy()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001332 __ CheckAccessGlobalProxy(r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333 }
1334
ager@chromium.org5c838252010-02-19 08:53:10 +00001335 // Stub is never generated for non-global objects that require access
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001337 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338
ager@chromium.org5c838252010-02-19 08:53:10 +00001339 __ push(r1); // receiver.
1340 __ push(r2); // name.
1341 __ push(r0); // value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342
mads.s.ager31e71382008-08-13 09:32:07 +00001343 // Do tail-call to the runtime system.
1344 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001346 __ TailCallExternalReference(store_ic_property, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347
1348 // Handle store cache miss.
1349 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001351 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352
1353 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001354 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355}
1356
1357
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001358Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1359 JSGlobalPropertyCell* cell,
1360 String* name) {
1361 // ----------- S t a t e -------------
1362 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001363 // -- r1 : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001364 // -- r2 : name
1365 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001366 // -----------------------------------
1367 Label miss;
1368
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001369 // Check that the map of the global has not changed.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001370 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1371 __ cmp(r3, Operand(Handle<Map>(object->map())));
1372 __ b(ne, &miss);
1373
1374 // Store the value in the cell.
1375 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1376 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001377
ager@chromium.org5c838252010-02-19 08:53:10 +00001378 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001379 __ Ret();
1380
1381 // Handle store cache miss.
1382 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001383 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001384 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1385 __ Jump(ic, RelocInfo::CODE_TARGET);
1386
1387 // Return the generated code.
1388 return GetCode(NORMAL, name);
1389}
1390
1391
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001392Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1393 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001394 int index,
1395 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397 // -- r2 : name
1398 // -- lr : return address
1399 // -- [sp] : receiver
1400 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001401 Label miss;
1402
mads.s.ager31e71382008-08-13 09:32:07 +00001403 __ ldr(r0, MemOperand(sp, 0));
1404
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001405 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001407 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408
1409 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001410 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411}
1412
1413
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001414Object* LoadStubCompiler::CompileLoadCallback(String* name,
1415 JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001416 JSObject* holder,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001417 AccessorInfo* callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 // -- r2 : name
1420 // -- lr : return address
1421 // -- [sp] : receiver
1422 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423 Label miss;
1424
mads.s.ager31e71382008-08-13 09:32:07 +00001425 __ ldr(r0, MemOperand(sp, 0));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001426 Failure* failure = Failure::InternalError();
1427 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
1428 callback, name, &miss, &failure);
1429 if (!success) return failure;
1430
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001432 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
1434 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001435 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436}
1437
1438
1439Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1440 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001441 Object* value,
1442 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001443 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 // -- r2 : name
1445 // -- lr : return address
1446 // -- [sp] : receiver
1447 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001448 Label miss;
1449
mads.s.ager31e71382008-08-13 09:32:07 +00001450 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001452 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001454 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001455
1456 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001457 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458}
1459
1460
1461Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1462 JSObject* holder,
1463 String* name) {
1464 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465 // -- r2 : name
1466 // -- lr : return address
1467 // -- [sp] : receiver
1468 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 Label miss;
1470
mads.s.ager31e71382008-08-13 09:32:07 +00001471 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001473 LookupResult lookup;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001474 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001475 GenerateLoadInterceptor(object,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001476 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001477 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001478 r0,
1479 r2,
1480 r3,
1481 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001482 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001483 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001485 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486
1487 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001488 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489}
1490
1491
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001492Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1493 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001494 JSGlobalPropertyCell* cell,
1495 String* name,
1496 bool is_dont_delete) {
1497 // ----------- S t a t e -------------
1498 // -- r2 : name
1499 // -- lr : return address
1500 // -- [sp] : receiver
1501 // -----------------------------------
1502 Label miss;
1503
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001504 // Get the receiver from the stack.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001505 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001506
1507 // If the object is the holder then we know that it's a global
1508 // object which can only happen for contextual calls. In this case,
1509 // the receiver cannot be a smi.
1510 if (object != holder) {
1511 __ tst(r1, Operand(kSmiTagMask));
1512 __ b(eq, &miss);
1513 }
1514
1515 // Check that the map of the global has not changed.
1516 CheckPrototypes(object, r1, holder, r3, r0, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001517
1518 // Get the value from the cell.
1519 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1520 __ ldr(r0, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1521
1522 // Check for deleted property if property can actually be deleted.
1523 if (!is_dont_delete) {
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001524 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1525 __ cmp(r0, ip);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001526 __ b(eq, &miss);
1527 }
1528
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001529 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001530 __ Ret();
1531
1532 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001533 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1534 GenerateLoadMiss(masm(), Code::LOAD_IC);
1535
1536 // Return the generated code.
1537 return GetCode(NORMAL, name);
1538}
1539
1540
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001541Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1542 JSObject* receiver,
1543 JSObject* holder,
1544 int index) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001545 // ----------- S t a t e -------------
1546 // -- lr : return address
1547 // -- sp[0] : key
1548 // -- sp[4] : receiver
1549 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001550 Label miss;
1551
1552 __ ldr(r2, MemOperand(sp, 0));
1553 __ ldr(r0, MemOperand(sp, kPointerSize));
1554
1555 __ cmp(r2, Operand(Handle<String>(name)));
1556 __ b(ne, &miss);
1557
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001558 GenerateLoadField(receiver, holder, r0, r3, r1, index, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001559 __ bind(&miss);
1560 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1561
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001562 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563}
1564
1565
1566Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1567 JSObject* receiver,
1568 JSObject* holder,
1569 AccessorInfo* callback) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001570 // ----------- S t a t e -------------
1571 // -- lr : return address
1572 // -- sp[0] : key
1573 // -- sp[4] : receiver
1574 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001575 Label miss;
1576
1577 __ ldr(r2, MemOperand(sp, 0));
1578 __ ldr(r0, MemOperand(sp, kPointerSize));
1579
1580 __ cmp(r2, Operand(Handle<String>(name)));
1581 __ b(ne, &miss);
1582
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001583 Failure* failure = Failure::InternalError();
1584 bool success = GenerateLoadCallback(receiver, holder, r0, r2, r3, r1,
1585 callback, name, &miss, &failure);
1586 if (!success) return failure;
1587
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001588 __ bind(&miss);
1589 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1590
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001591 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592}
1593
1594
1595Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1596 JSObject* receiver,
1597 JSObject* holder,
1598 Object* value) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001599 // ----------- S t a t e -------------
1600 // -- lr : return address
1601 // -- sp[0] : key
1602 // -- sp[4] : receiver
1603 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001604 Label miss;
1605
1606 // Check the key is the cached one
1607 __ ldr(r2, MemOperand(sp, 0));
1608 __ ldr(r0, MemOperand(sp, kPointerSize));
1609
1610 __ cmp(r2, Operand(Handle<String>(name)));
1611 __ b(ne, &miss);
1612
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001613 GenerateLoadConstant(receiver, holder, r0, r3, r1, value, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001614 __ bind(&miss);
1615 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1616
1617 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001618 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619}
1620
1621
1622Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1623 JSObject* holder,
1624 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001625 // ----------- S t a t e -------------
1626 // -- lr : return address
1627 // -- sp[0] : key
1628 // -- sp[4] : receiver
1629 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001630 Label miss;
1631
1632 // Check the key is the cached one
1633 __ ldr(r2, MemOperand(sp, 0));
1634 __ ldr(r0, MemOperand(sp, kPointerSize));
1635
1636 __ cmp(r2, Operand(Handle<String>(name)));
1637 __ b(ne, &miss);
1638
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001639 LookupResult lookup;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001640 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001641 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001642 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001643 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001644 r0,
1645 r2,
1646 r3,
1647 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001648 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001649 &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001650 __ bind(&miss);
1651 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1652
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001653 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001654}
1655
1656
1657Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001658 // ----------- S t a t e -------------
1659 // -- lr : return address
1660 // -- sp[0] : key
1661 // -- sp[4] : receiver
1662 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001663 Label miss;
1664
1665 // Check the key is the cached one
1666 __ ldr(r2, MemOperand(sp, 0));
1667 __ ldr(r0, MemOperand(sp, kPointerSize));
1668
1669 __ cmp(r2, Operand(Handle<String>(name)));
1670 __ b(ne, &miss);
1671
1672 GenerateLoadArrayLength(masm(), r0, r3, &miss);
1673 __ bind(&miss);
1674 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1675
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001676 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001677}
1678
1679
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001680Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001681 // ----------- S t a t e -------------
1682 // -- lr : return address
1683 // -- sp[0] : key
1684 // -- sp[4] : receiver
1685 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001686 Label miss;
1687 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1688
1689 __ ldr(r2, MemOperand(sp));
1690 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver
1691
1692 __ cmp(r2, Operand(Handle<String>(name)));
1693 __ b(ne, &miss);
1694
ager@chromium.org5c838252010-02-19 08:53:10 +00001695 GenerateLoadStringLength(masm(), r0, r1, r3, &miss);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001696 __ bind(&miss);
1697 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1698
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001699 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1700
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001701 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702}
1703
1704
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001705// TODO(1224671): implement the fast case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001707 // ----------- S t a t e -------------
1708 // -- lr : return address
1709 // -- sp[0] : key
1710 // -- sp[4] : receiver
1711 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001712 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1713
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001714 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001715}
1716
1717
1718Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1719 int index,
1720 Map* transition,
1721 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001722 // ----------- S t a t e -------------
1723 // -- r0 : value
1724 // -- r2 : name
1725 // -- lr : return address
1726 // -- [sp] : receiver
1727 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001728 Label miss;
1729
1730 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1731
1732 // Check that the name has not changed.
1733 __ cmp(r2, Operand(Handle<String>(name)));
1734 __ b(ne, &miss);
1735
1736 // Load receiver from the stack.
1737 __ ldr(r3, MemOperand(sp));
1738 // r1 is used as scratch register, r3 and r2 might be clobbered.
1739 GenerateStoreField(masm(),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001740 object,
1741 index,
1742 transition,
1743 r3, r2, r1,
1744 &miss);
1745 __ bind(&miss);
1746
1747 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1748 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001749 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
1750 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001751
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001752 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001753 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001754}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001755
1756
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001757Object* ConstructStubCompiler::CompileConstructStub(
1758 SharedFunctionInfo* shared) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001759 // ----------- S t a t e -------------
1760 // -- r0 : argc
1761 // -- r1 : constructor
1762 // -- lr : return address
1763 // -- [sp] : last argument
1764 // -----------------------------------
1765 Label generic_stub_call;
1766
1767 // Use r7 for holding undefined which is used in several places below.
1768 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
1769
1770#ifdef ENABLE_DEBUGGER_SUPPORT
1771 // Check to see whether there are any break points in the function code. If
1772 // there are jump to the generic constructor stub which calls the actual
1773 // code for the function thereby hitting the break points.
1774 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1775 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
1776 __ cmp(r2, r7);
1777 __ b(ne, &generic_stub_call);
1778#endif
1779
1780 // Load the initial map and verify that it is in fact a map.
1781 // r1: constructor function
1782 // r7: undefined
1783 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
1784 __ tst(r2, Operand(kSmiTagMask));
1785 __ b(eq, &generic_stub_call);
1786 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
1787 __ b(ne, &generic_stub_call);
1788
1789#ifdef DEBUG
1790 // Cannot construct functions this way.
1791 // r0: argc
1792 // r1: constructor function
1793 // r2: initial map
1794 // r7: undefined
1795 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
1796 __ Check(ne, "Function constructed by construct stub.");
1797#endif
1798
1799 // Now allocate the JSObject in new space.
1800 // r0: argc
1801 // r1: constructor function
1802 // r2: initial map
1803 // r7: undefined
1804 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001805 __ AllocateInNewSpace(r3,
1806 r4,
1807 r5,
1808 r6,
1809 &generic_stub_call,
1810 NO_ALLOCATION_FLAGS);
ager@chromium.orga1645e22009-09-09 19:27:10 +00001811
1812 // Allocated the JSObject, now initialize the fields. Map is set to initial
1813 // map and properties and elements are set to empty fixed array.
1814 // r0: argc
1815 // r1: constructor function
1816 // r2: initial map
1817 // r3: object size (in words)
1818 // r4: JSObject (not tagged)
1819 // r7: undefined
1820 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
1821 __ mov(r5, r4);
1822 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
1823 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1824 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
1825 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1826 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
1827 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1828
1829 // Calculate the location of the first argument. The stack contains only the
1830 // argc arguments.
1831 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
1832
1833 // Fill all the in-object properties with undefined.
1834 // r0: argc
1835 // r1: first argument
1836 // r3: object size (in words)
1837 // r4: JSObject (not tagged)
1838 // r5: First in-object property of JSObject (not tagged)
1839 // r7: undefined
1840 // Fill the initialized properties with a constant value or a passed argument
1841 // depending on the this.x = ...; assignment in the function.
1842 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
1843 if (shared->IsThisPropertyAssignmentArgument(i)) {
1844 Label not_passed, next;
1845 // Check if the argument assigned to the property is actually passed.
1846 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
1847 __ cmp(r0, Operand(arg_number));
1848 __ b(le, &not_passed);
1849 // Argument passed - find it on the stack.
1850 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
1851 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1852 __ b(&next);
1853 __ bind(&not_passed);
1854 // Set the property to undefined.
1855 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1856 __ bind(&next);
1857 } else {
1858 // Set the property to the constant value.
1859 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
1860 __ mov(r2, Operand(constant));
1861 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1862 }
1863 }
1864
1865 // Fill the unused in-object property fields with undefined.
1866 for (int i = shared->this_property_assignments_count();
1867 i < shared->CalculateInObjectProperties();
1868 i++) {
1869 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1870 }
1871
1872 // r0: argc
1873 // r4: JSObject (not tagged)
1874 // Move argc to r1 and the JSObject to return to r0 and tag it.
1875 __ mov(r1, r0);
1876 __ mov(r0, r4);
1877 __ orr(r0, r0, Operand(kHeapObjectTag));
1878
1879 // r0: JSObject
1880 // r1: argc
1881 // Remove caller arguments and receiver from the stack and return.
1882 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
1883 __ add(sp, sp, Operand(kPointerSize));
1884 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
1885 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
1886 __ Jump(lr);
1887
1888 // Jump to the generic stub in case the specialized code cannot handle the
1889 // construction.
1890 __ bind(&generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001891 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1892 Handle<Code> generic_construct_stub(code);
1893 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
1894
1895 // Return the generated code.
1896 return GetCode();
1897}
1898
1899
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001900#undef __
1901
1902} } // namespace v8::internal