blob: e0e166cf7e0ccf2a3d3d215b58cfc23fb1a55c78 [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
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000603// Generate code to check that a global property cell is empty. Create
604// the property cell at compilation time if no cell exists for the
605// property.
606static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
607 GlobalObject* global,
608 String* name,
609 Register scratch,
610 Label* miss) {
611 Object* probe = global->EnsurePropertyCell(name);
612 if (probe->IsFailure()) return probe;
613 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
614 ASSERT(cell->value()->IsTheHole());
615 __ mov(scratch, Operand(Handle<Object>(cell)));
616 __ ldr(scratch,
617 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
618 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
619 __ cmp(scratch, ip);
620 __ b(ne, miss);
621 return cell;
622}
623
624
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000625#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000626#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000627
628
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000629Register StubCompiler::CheckPrototypes(JSObject* object,
630 Register object_reg,
631 JSObject* holder,
632 Register holder_reg,
633 Register scratch,
634 String* name,
ager@chromium.org5c838252010-02-19 08:53:10 +0000635 int save_at_depth,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000636 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000637 // TODO(602): support object saving.
638 ASSERT(save_at_depth == kInvalidProtoDepth);
639
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000640 // Check that the maps haven't changed.
641 Register result =
642 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
643
644 // If we've skipped any global objects, it's not enough to verify
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000645 // that their maps haven't changed. We also need to check that the
646 // property cell for the property is still empty.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000647 while (object != holder) {
648 if (object->IsGlobalObject()) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000649 Object* cell = GenerateCheckPropertyCell(masm(),
650 GlobalObject::cast(object),
651 name,
652 scratch,
653 miss);
654 if (cell->IsFailure()) {
655 set_failure(Failure::cast(cell));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000656 return result;
657 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000658 }
659 object = JSObject::cast(object->GetPrototype());
660 }
661
ager@chromium.org5c838252010-02-19 08:53:10 +0000662 // Return the register containing the holder.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000663 return result;
664}
665
666
667void StubCompiler::GenerateLoadField(JSObject* object,
668 JSObject* holder,
669 Register receiver,
670 Register scratch1,
671 Register scratch2,
672 int index,
673 String* name,
674 Label* miss) {
675 // Check that the receiver isn't a smi.
676 __ tst(receiver, Operand(kSmiTagMask));
677 __ b(eq, miss);
678
679 // Check that the maps haven't changed.
680 Register reg =
681 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
682 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
683 __ Ret();
684}
685
686
687void StubCompiler::GenerateLoadConstant(JSObject* object,
688 JSObject* holder,
689 Register receiver,
690 Register scratch1,
691 Register scratch2,
692 Object* value,
693 String* name,
694 Label* miss) {
695 // Check that the receiver isn't a smi.
696 __ tst(receiver, Operand(kSmiTagMask));
697 __ b(eq, miss);
698
699 // Check that the maps haven't changed.
700 Register reg =
701 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
702
703 // Return the constant value.
704 __ mov(r0, Operand(Handle<Object>(value)));
705 __ Ret();
706}
707
708
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000709bool StubCompiler::GenerateLoadCallback(JSObject* object,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000710 JSObject* holder,
711 Register receiver,
712 Register name_reg,
713 Register scratch1,
714 Register scratch2,
715 AccessorInfo* callback,
716 String* name,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000717 Label* miss,
718 Failure** failure) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000719 // Check that the receiver isn't a smi.
720 __ tst(receiver, Operand(kSmiTagMask));
721 __ b(eq, miss);
722
723 // Check that the maps haven't changed.
724 Register reg =
725 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
726
727 // Push the arguments on the JS stack of the caller.
728 __ push(receiver); // receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000729 __ push(reg); // holder
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000730 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
731 __ push(ip);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000732 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
733 __ push(reg);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000734 __ push(name_reg); // name
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000735
736 // Do tail-call to the runtime system.
737 ExternalReference load_callback_property =
738 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000739 __ TailCallExternalReference(load_callback_property, 5, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000740
741 return true;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000742}
743
744
745void StubCompiler::GenerateLoadInterceptor(JSObject* object,
746 JSObject* holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000747 LookupResult* lookup,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000748 Register receiver,
749 Register name_reg,
750 Register scratch1,
751 Register scratch2,
752 String* name,
753 Label* miss) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000754 LoadInterceptorCompiler compiler(name_reg);
755 CompileLoadInterceptor(&compiler,
756 this,
757 masm(),
758 object,
759 holder,
760 name,
761 lookup,
762 receiver,
763 scratch1,
764 scratch2,
765 miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000766}
767
768
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000770 // ----------- S t a t e -------------
771 // -- r1: function
772 // -- lr: return address
773 // -----------------------------------
774
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000775 // Enter an internal frame.
776 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000778 // Preserve the function.
779 __ push(r1);
780
781 // Push the function on the stack as the argument to the runtime function.
782 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000783 __ CallRuntime(Runtime::kLazyCompile, 1);
784
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000785 // Calculate the entry point.
786 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000788 // Restore saved function.
789 __ pop(r1);
790
791 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000792 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793
794 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000795 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000796
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000797 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798}
799
800
ager@chromium.org5c838252010-02-19 08:53:10 +0000801Object* CallStubCompiler::CompileCallField(JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000802 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000803 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000804 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000805 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000806 // -- r2 : name
807 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000809 Label miss;
810
mads.s.ager31e71382008-08-13 09:32:07 +0000811 const int argc = arguments().immediate();
812
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000813 // Get the receiver of the function from the stack into r0.
814 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000815 // Check that the receiver isn't a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000816 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000817 __ b(eq, &miss);
818
819 // Do the right check and compute the holder register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000820 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000821 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000822
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000823 GenerateCallFunction(masm(), object, arguments(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000824
825 // Handle call cache miss.
826 __ bind(&miss);
827 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000828 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000829
830 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000831 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832}
833
834
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000835Object* CallStubCompiler::CompileArrayPushCall(Object* object,
836 JSObject* holder,
837 JSFunction* function,
838 String* name,
839 CheckType check) {
840 // ----------- S t a t e -------------
841 // -- r2 : name
842 // -- lr : return address
843 // -----------------------------------
844
845 // TODO(639): faster implementation.
846 ASSERT(check == RECEIVER_MAP_CHECK);
847
848 Label miss;
849
850 // Get the receiver from the stack
851 const int argc = arguments().immediate();
852 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
853
854 // Check that the receiver isn't a smi.
855 __ tst(r1, Operand(kSmiTagMask));
856 __ b(eq, &miss);
857
858 // Check that the maps haven't changed.
859 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
860
861 if (object->IsGlobalObject()) {
862 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
863 __ str(r3, MemOperand(sp, argc * kPointerSize));
864 }
865
866 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
867 argc + 1,
868 1);
869
870 // Handle call cache miss.
871 __ bind(&miss);
872 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
873 __ Jump(ic, RelocInfo::CODE_TARGET);
874
875 // Return the generated code.
876 String* function_name = NULL;
877 if (function->shared()->name()->IsString()) {
878 function_name = String::cast(function->shared()->name());
879 }
880 return GetCode(CONSTANT_FUNCTION, function_name);
881}
882
883
884Object* CallStubCompiler::CompileArrayPopCall(Object* object,
885 JSObject* holder,
886 JSFunction* function,
887 String* name,
888 CheckType check) {
889 // ----------- S t a t e -------------
890 // -- r2 : name
891 // -- lr : return address
892 // -----------------------------------
893
894 // TODO(642): faster implementation.
895 ASSERT(check == RECEIVER_MAP_CHECK);
896
897 Label miss;
898
899 // Get the receiver from the stack
900 const int argc = arguments().immediate();
901 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
902
903 // Check that the receiver isn't a smi.
904 __ tst(r1, Operand(kSmiTagMask));
905 __ b(eq, &miss);
906
907 // Check that the maps haven't changed.
908 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
909
910 if (object->IsGlobalObject()) {
911 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
912 __ str(r3, MemOperand(sp, argc * kPointerSize));
913 }
914
915 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
916 argc + 1,
917 1);
918
919 // Handle call cache miss.
920 __ bind(&miss);
921 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
922 __ Jump(ic, RelocInfo::CODE_TARGET);
923
924 // Return the generated code.
925 String* function_name = NULL;
926 if (function->shared()->name()->IsString()) {
927 function_name = String::cast(function->shared()->name());
928 }
929 return GetCode(CONSTANT_FUNCTION, function_name);
930}
931
932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933Object* CallStubCompiler::CompileCallConstant(Object* object,
934 JSObject* holder,
935 JSFunction* function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000936 String* name,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000937 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000939 // -- r2 : name
940 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000941 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000942 SharedFunctionInfo* function_info = function->shared();
943 if (function_info->HasCustomCallGenerator()) {
944 CustomCallGenerator generator =
945 ToCData<CustomCallGenerator>(function_info->function_data());
946 return generator(this, object, holder, function, name, check);
947 }
948
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000949 Label miss;
950
mads.s.ager31e71382008-08-13 09:32:07 +0000951 // Get the receiver from the stack
952 const int argc = arguments().immediate();
953 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000955 // Check that the receiver isn't a smi.
956 if (check != NUMBER_CHECK) {
957 __ tst(r1, Operand(kSmiTagMask));
958 __ b(eq, &miss);
959 }
960
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000961 // Make sure that it's okay not to patch the on stack receiver
962 // unless we're doing a receiver map check.
963 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
964
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000965 switch (check) {
966 case RECEIVER_MAP_CHECK:
967 // Check that the maps haven't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +0000968 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000969
970 // Patch the receiver on the stack with the global proxy if
971 // necessary.
972 if (object->IsGlobalObject()) {
973 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
974 __ str(r3, MemOperand(sp, argc * kPointerSize));
975 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976 break;
977
978 case STRING_CHECK:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000979 if (!function->IsBuiltin()) {
980 // Calling non-builtins with a value as receiver requires boxing.
981 __ jmp(&miss);
982 } else {
983 // Check that the object is a two-byte string or a symbol.
ager@chromium.org5c838252010-02-19 08:53:10 +0000984 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000985 __ b(hs, &miss);
986 // Check that the maps starting from the prototype haven't changed.
987 GenerateLoadGlobalFunctionPrototype(masm(),
988 Context::STRING_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +0000989 r0);
990 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000991 r1, name, &miss);
992 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993 break;
994
995 case NUMBER_CHECK: {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000996 if (!function->IsBuiltin()) {
997 // Calling non-builtins with a value as receiver requires boxing.
998 __ jmp(&miss);
999 } else {
1000 Label fast;
1001 // Check that the object is a smi or a heap number.
1002 __ tst(r1, Operand(kSmiTagMask));
1003 __ b(eq, &fast);
ager@chromium.org5c838252010-02-19 08:53:10 +00001004 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001005 __ b(ne, &miss);
1006 __ bind(&fast);
1007 // Check that the maps starting from the prototype haven't changed.
1008 GenerateLoadGlobalFunctionPrototype(masm(),
1009 Context::NUMBER_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +00001010 r0);
1011 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001012 r1, name, &miss);
1013 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014 break;
1015 }
1016
1017 case BOOLEAN_CHECK: {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001018 if (!function->IsBuiltin()) {
1019 // Calling non-builtins with a value as receiver requires boxing.
1020 __ jmp(&miss);
1021 } else {
1022 Label fast;
1023 // Check that the object is a boolean.
1024 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1025 __ cmp(r1, ip);
1026 __ b(eq, &fast);
1027 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1028 __ cmp(r1, ip);
1029 __ b(ne, &miss);
1030 __ bind(&fast);
1031 // Check that the maps starting from the prototype haven't changed.
1032 GenerateLoadGlobalFunctionPrototype(masm(),
1033 Context::BOOLEAN_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +00001034 r0);
1035 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001036 r1, name, &miss);
1037 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038 break;
1039 }
1040
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041 default:
1042 UNREACHABLE();
1043 }
1044
ager@chromium.org5c838252010-02-19 08:53:10 +00001045 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046
1047 // Handle call cache miss.
1048 __ bind(&miss);
1049 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001050 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051
1052 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001053 String* function_name = NULL;
1054 if (function->shared()->name()->IsString()) {
1055 function_name = String::cast(function->shared()->name());
1056 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001057 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058}
1059
1060
ager@chromium.org5c838252010-02-19 08:53:10 +00001061Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062 JSObject* holder,
1063 String* name) {
1064 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001065 // -- r2 : name
1066 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001067 // -----------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001068 ASSERT(holder->HasNamedInterceptor());
1069 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070 Label miss;
1071
ager@chromium.org5c838252010-02-19 08:53:10 +00001072 const Register receiver = r0;
1073 const Register holder_reg = r1;
1074 const Register name_reg = r2;
1075 const Register scratch = r3;
1076
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001077 // Get the number of arguments.
1078 const int argc = arguments().immediate();
1079
1080 LookupResult lookup;
1081 LookupPostInterceptor(holder, name, &lookup);
1082
1083 // Get the receiver from the stack into r0.
1084 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001085
ager@chromium.org5c838252010-02-19 08:53:10 +00001086 // Check that the receiver isn't a smi.
1087 __ BranchOnSmi(receiver, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001088
ager@chromium.org5c838252010-02-19 08:53:10 +00001089 // Check that the maps haven't changed.
1090 Register reg = CheckPrototypes(object, receiver, holder, holder_reg,
1091 scratch, name, &miss);
1092 if (!reg.is(holder_reg)) {
1093 __ mov(holder_reg, reg);
1094 }
1095
1096 // If we call a constant function when the interceptor returns
1097 // the no-result sentinel, generate code that optimizes this case.
1098 if (lookup.IsProperty() &&
1099 lookup.IsCacheable() &&
1100 lookup.type() == CONSTANT_FUNCTION &&
1101 lookup.GetConstantFunction()->is_compiled() &&
1102 !holder->IsJSArray()) {
1103 // Constant functions cannot sit on global object.
1104 ASSERT(!lookup.holder()->IsGlobalObject());
1105
1106 // Call the interceptor.
1107 __ EnterInternalFrame();
1108 __ push(holder_reg);
1109 __ push(name_reg);
1110 CompileCallLoadPropertyWithInterceptor(masm(),
1111 receiver,
1112 holder_reg,
1113 name_reg,
1114 holder);
1115 __ pop(name_reg);
1116 __ pop(holder_reg);
1117 __ LeaveInternalFrame();
1118 // r0 no longer contains the receiver.
1119
1120 // If interceptor returns no-result sentinal, call the constant function.
1121 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1122 __ cmp(r0, scratch);
1123 Label invoke;
1124 __ b(ne, &invoke);
1125 // Check the prototypes between the interceptor's holder and the
1126 // constant function's holder.
1127 CheckPrototypes(holder, holder_reg,
1128 lookup.holder(), r0,
1129 scratch,
1130 name,
1131 &miss);
1132
1133 __ InvokeFunction(lookup.GetConstantFunction(),
1134 arguments(),
1135 JUMP_FUNCTION);
1136
1137 __ bind(&invoke);
1138
1139 } else {
1140 // Call a runtime function to load the interceptor property.
1141 __ EnterInternalFrame();
1142 __ push(name_reg);
1143
1144 PushInterceptorArguments(masm(), receiver, holder_reg, name_reg, holder);
1145
1146 __ CallExternalReference(
1147 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
1148 5);
1149
1150 __ pop(name_reg);
1151 __ LeaveInternalFrame();
1152 }
1153
1154 // Move returned value, the function to call, to r1.
1155 __ mov(r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001156 // Restore receiver.
ager@chromium.org5c838252010-02-19 08:53:10 +00001157 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001158
1159 GenerateCallFunction(masm(), object, arguments(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001160
1161 // Handle call cache miss.
1162 __ bind(&miss);
1163 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001164 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165
1166 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001167 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168}
1169
1170
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001171Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1172 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001173 JSGlobalPropertyCell* cell,
1174 JSFunction* function,
1175 String* name) {
1176 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001177 // -- r2 : name
1178 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001179 // -----------------------------------
1180 Label miss;
1181
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001182 // Get the number of arguments.
1183 const int argc = arguments().immediate();
1184
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001185 // Get the receiver from the stack.
1186 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1187
1188 // If the object is the holder then we know that it's a global
1189 // object which can only happen for contextual calls. In this case,
1190 // the receiver cannot be a smi.
1191 if (object != holder) {
1192 __ tst(r0, Operand(kSmiTagMask));
1193 __ b(eq, &miss);
1194 }
1195
1196 // Check that the maps haven't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001197 CheckPrototypes(object, r0, holder, r3, r1, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001198
1199 // Get the value from the cell.
1200 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1201 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1202
1203 // Check that the cell contains the same function.
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001204 if (Heap::InNewSpace(function)) {
1205 // We can't embed a pointer to a function in new space so we have
1206 // to verify that the shared function info is unchanged. This has
1207 // the nice side effect that multiple closures based on the same
1208 // function can all use this call IC. Before we load through the
1209 // function, we have to verify that it still is a function.
1210 __ tst(r1, Operand(kSmiTagMask));
1211 __ b(eq, &miss);
1212 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1213 __ b(ne, &miss);
1214
1215 // Check the shared function info. Make sure it hasn't changed.
1216 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
ager@chromium.org5c838252010-02-19 08:53:10 +00001217 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1218 __ cmp(r4, r3);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001219 __ b(ne, &miss);
1220 } else {
1221 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1222 __ b(ne, &miss);
1223 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001224
1225 // Patch the receiver on the stack with the global proxy if
1226 // necessary.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001227 if (object->IsGlobalObject()) {
1228 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1229 __ str(r3, MemOperand(sp, argc * kPointerSize));
1230 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001231
1232 // Setup the context (function already in r1).
1233 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1234
1235 // Jump to the cached code (tail call).
ager@chromium.org5c838252010-02-19 08:53:10 +00001236 __ IncrementCounter(&Counters::call_global_inline, 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001237 ASSERT(function->is_compiled());
1238 Handle<Code> code(function->code());
1239 ParameterCount expected(function->shared()->formal_parameter_count());
1240 __ InvokeCode(code, expected, arguments(),
1241 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1242
1243 // Handle call cache miss.
1244 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001245 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
1246 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1247 __ Jump(ic, RelocInfo::CODE_TARGET);
1248
1249 // Return the generated code.
1250 return GetCode(NORMAL, name);
1251}
1252
1253
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1255 int index,
1256 Map* transition,
1257 String* name) {
1258 // ----------- S t a t e -------------
1259 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001260 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261 // -- r2 : name
1262 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001264 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001266 GenerateStoreField(masm(),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001267 object,
1268 index,
1269 transition,
ager@chromium.org5c838252010-02-19 08:53:10 +00001270 r1, r2, r3,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001271 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001273 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001274 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275
1276 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001277 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278}
1279
1280
1281Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1282 AccessorInfo* callback,
1283 String* name) {
1284 // ----------- S t a t e -------------
1285 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001286 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287 // -- r2 : name
1288 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001289 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290 Label miss;
1291
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292 // Check that the object isn't a smi.
ager@chromium.org5c838252010-02-19 08:53:10 +00001293 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 __ b(eq, &miss);
1295
1296 // Check that the map of the object hasn't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001297 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1298 __ cmp(r3, Operand(Handle<Map>(object->map())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299 __ b(ne, &miss);
1300
1301 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001302 if (object->IsJSGlobalProxy()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001303 __ CheckAccessGlobalProxy(r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 }
1305
1306 // Stub never generated for non-global objects that require access
1307 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001308 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309
ager@chromium.org5c838252010-02-19 08:53:10 +00001310 __ push(r1); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
ager@chromium.org5c838252010-02-19 08:53:10 +00001312 __ stm(db_w, sp, ip.bit() | r2.bit() | r0.bit());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313
mads.s.ager31e71382008-08-13 09:32:07 +00001314 // Do tail-call to the runtime system.
1315 ExternalReference store_callback_property =
1316 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001317 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318
1319 // Handle store cache miss.
1320 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001322 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323
1324 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001325 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326}
1327
1328
1329Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1330 String* name) {
1331 // ----------- S t a t e -------------
1332 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001333 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001334 // -- r2 : name
1335 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337 Label miss;
1338
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339 // Check that the object isn't a smi.
ager@chromium.org5c838252010-02-19 08:53:10 +00001340 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341 __ b(eq, &miss);
1342
1343 // Check that the map of the object hasn't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001344 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1345 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346 __ b(ne, &miss);
1347
1348 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001349 if (receiver->IsJSGlobalProxy()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001350 __ CheckAccessGlobalProxy(r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351 }
1352
ager@chromium.org5c838252010-02-19 08:53:10 +00001353 // Stub is never generated for non-global objects that require access
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001354 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001355 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356
ager@chromium.org5c838252010-02-19 08:53:10 +00001357 __ push(r1); // receiver.
1358 __ push(r2); // name.
1359 __ push(r0); // value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360
mads.s.ager31e71382008-08-13 09:32:07 +00001361 // Do tail-call to the runtime system.
1362 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001363 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001364 __ TailCallExternalReference(store_ic_property, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365
1366 // Handle store cache miss.
1367 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001369 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370
1371 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001372 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001373}
1374
1375
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001376Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1377 JSGlobalPropertyCell* cell,
1378 String* name) {
1379 // ----------- S t a t e -------------
1380 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001381 // -- r1 : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001382 // -- r2 : name
1383 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001384 // -----------------------------------
1385 Label miss;
1386
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001387 // Check that the map of the global has not changed.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001388 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1389 __ cmp(r3, Operand(Handle<Map>(object->map())));
1390 __ b(ne, &miss);
1391
1392 // Store the value in the cell.
1393 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1394 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001395
ager@chromium.org5c838252010-02-19 08:53:10 +00001396 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001397 __ Ret();
1398
1399 // Handle store cache miss.
1400 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001401 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001402 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1403 __ Jump(ic, RelocInfo::CODE_TARGET);
1404
1405 // Return the generated code.
1406 return GetCode(NORMAL, name);
1407}
1408
1409
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001410Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1411 JSObject* object,
1412 JSObject* last) {
1413 // ----------- S t a t e -------------
1414 // -- r2 : name
1415 // -- lr : return address
1416 // -- [sp] : receiver
1417 // -----------------------------------
1418 Label miss;
1419
1420 // Load receiver.
1421 __ ldr(r0, MemOperand(sp, 0));
1422
1423 // Check that receiver is not a smi.
1424 __ tst(r0, Operand(kSmiTagMask));
1425 __ b(eq, &miss);
1426
1427 // Check the maps of the full prototype chain.
1428 CheckPrototypes(object, r0, last, r3, r1, name, &miss);
1429
1430 // If the last object in the prototype chain is a global object,
1431 // check that the global property cell is empty.
1432 if (last->IsGlobalObject()) {
1433 Object* cell = GenerateCheckPropertyCell(masm(),
1434 GlobalObject::cast(last),
1435 name,
1436 r1,
1437 &miss);
1438 if (cell->IsFailure()) return cell;
1439 }
1440
1441 // Return undefined if maps of the full prototype chain are still the
1442 // same and no global property with this name contains a value.
1443 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1444 __ Ret();
1445
1446 __ bind(&miss);
1447 GenerateLoadMiss(masm(), Code::LOAD_IC);
1448
1449 // Return the generated code.
1450 return GetCode(NONEXISTENT, Heap::empty_string());
1451}
1452
1453
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001454Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1455 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001456 int index,
1457 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459 // -- r2 : name
1460 // -- lr : return address
1461 // -- [sp] : receiver
1462 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463 Label miss;
1464
mads.s.ager31e71382008-08-13 09:32:07 +00001465 __ ldr(r0, MemOperand(sp, 0));
1466
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001467 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001469 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470
1471 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001472 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473}
1474
1475
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001476Object* LoadStubCompiler::CompileLoadCallback(String* name,
1477 JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478 JSObject* holder,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001479 AccessorInfo* callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001481 // -- r2 : name
1482 // -- lr : return address
1483 // -- [sp] : receiver
1484 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485 Label miss;
1486
mads.s.ager31e71382008-08-13 09:32:07 +00001487 __ ldr(r0, MemOperand(sp, 0));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001488 Failure* failure = Failure::InternalError();
1489 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
1490 callback, name, &miss, &failure);
1491 if (!success) return failure;
1492
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001494 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001495
1496 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001497 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001498}
1499
1500
1501Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1502 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001503 Object* value,
1504 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001505 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001506 // -- r2 : name
1507 // -- lr : return address
1508 // -- [sp] : receiver
1509 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510 Label miss;
1511
mads.s.ager31e71382008-08-13 09:32:07 +00001512 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001513
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001514 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001516 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517
1518 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001519 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001520}
1521
1522
1523Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1524 JSObject* holder,
1525 String* name) {
1526 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 // -- r2 : name
1528 // -- lr : return address
1529 // -- [sp] : receiver
1530 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 Label miss;
1532
mads.s.ager31e71382008-08-13 09:32:07 +00001533 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001535 LookupResult lookup;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001536 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001537 GenerateLoadInterceptor(object,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001538 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001539 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001540 r0,
1541 r2,
1542 r3,
1543 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001544 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001545 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001547 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548
1549 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001550 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551}
1552
1553
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001554Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1555 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001556 JSGlobalPropertyCell* cell,
1557 String* name,
1558 bool is_dont_delete) {
1559 // ----------- S t a t e -------------
1560 // -- r2 : name
1561 // -- lr : return address
1562 // -- [sp] : receiver
1563 // -----------------------------------
1564 Label miss;
1565
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001566 // Get the receiver from the stack.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001567 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001568
1569 // If the object is the holder then we know that it's a global
1570 // object which can only happen for contextual calls. In this case,
1571 // the receiver cannot be a smi.
1572 if (object != holder) {
1573 __ tst(r1, Operand(kSmiTagMask));
1574 __ b(eq, &miss);
1575 }
1576
1577 // Check that the map of the global has not changed.
1578 CheckPrototypes(object, r1, holder, r3, r0, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001579
1580 // Get the value from the cell.
1581 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1582 __ ldr(r0, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1583
1584 // Check for deleted property if property can actually be deleted.
1585 if (!is_dont_delete) {
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001586 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1587 __ cmp(r0, ip);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001588 __ b(eq, &miss);
1589 }
1590
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001591 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001592 __ Ret();
1593
1594 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001595 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1596 GenerateLoadMiss(masm(), Code::LOAD_IC);
1597
1598 // Return the generated code.
1599 return GetCode(NORMAL, name);
1600}
1601
1602
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1604 JSObject* receiver,
1605 JSObject* holder,
1606 int index) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001607 // ----------- S t a t e -------------
1608 // -- lr : return address
1609 // -- sp[0] : key
1610 // -- sp[4] : receiver
1611 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001612 Label miss;
1613
1614 __ ldr(r2, MemOperand(sp, 0));
1615 __ ldr(r0, MemOperand(sp, kPointerSize));
1616
1617 __ cmp(r2, Operand(Handle<String>(name)));
1618 __ b(ne, &miss);
1619
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001620 GenerateLoadField(receiver, holder, r0, r3, r1, index, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001621 __ bind(&miss);
1622 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1623
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001624 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625}
1626
1627
1628Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1629 JSObject* receiver,
1630 JSObject* holder,
1631 AccessorInfo* callback) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001632 // ----------- S t a t e -------------
1633 // -- lr : return address
1634 // -- sp[0] : key
1635 // -- sp[4] : receiver
1636 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001637 Label miss;
1638
1639 __ ldr(r2, MemOperand(sp, 0));
1640 __ ldr(r0, MemOperand(sp, kPointerSize));
1641
1642 __ cmp(r2, Operand(Handle<String>(name)));
1643 __ b(ne, &miss);
1644
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001645 Failure* failure = Failure::InternalError();
1646 bool success = GenerateLoadCallback(receiver, holder, r0, r2, r3, r1,
1647 callback, name, &miss, &failure);
1648 if (!success) return failure;
1649
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(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001654}
1655
1656
1657Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1658 JSObject* receiver,
1659 JSObject* holder,
1660 Object* value) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001661 // ----------- S t a t e -------------
1662 // -- lr : return address
1663 // -- sp[0] : key
1664 // -- sp[4] : receiver
1665 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001666 Label miss;
1667
1668 // Check the key is the cached one
1669 __ ldr(r2, MemOperand(sp, 0));
1670 __ ldr(r0, MemOperand(sp, kPointerSize));
1671
1672 __ cmp(r2, Operand(Handle<String>(name)));
1673 __ b(ne, &miss);
1674
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001675 GenerateLoadConstant(receiver, holder, r0, r3, r1, value, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001676 __ bind(&miss);
1677 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1678
1679 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001680 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001681}
1682
1683
1684Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1685 JSObject* holder,
1686 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001687 // ----------- S t a t e -------------
1688 // -- lr : return address
1689 // -- sp[0] : key
1690 // -- sp[4] : receiver
1691 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001692 Label miss;
1693
1694 // Check the key is the cached one
1695 __ ldr(r2, MemOperand(sp, 0));
1696 __ ldr(r0, MemOperand(sp, kPointerSize));
1697
1698 __ cmp(r2, Operand(Handle<String>(name)));
1699 __ b(ne, &miss);
1700
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001701 LookupResult lookup;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001702 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001703 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001704 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001705 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001706 r0,
1707 r2,
1708 r3,
1709 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001710 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001711 &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001712 __ bind(&miss);
1713 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1714
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001715 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001716}
1717
1718
1719Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001720 // ----------- S t a t e -------------
1721 // -- lr : return address
1722 // -- sp[0] : key
1723 // -- sp[4] : receiver
1724 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001725 Label miss;
1726
1727 // Check the key is the cached one
1728 __ ldr(r2, MemOperand(sp, 0));
1729 __ ldr(r0, MemOperand(sp, kPointerSize));
1730
1731 __ cmp(r2, Operand(Handle<String>(name)));
1732 __ b(ne, &miss);
1733
1734 GenerateLoadArrayLength(masm(), r0, r3, &miss);
1735 __ bind(&miss);
1736 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1737
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001738 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001739}
1740
1741
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001742Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001743 // ----------- S t a t e -------------
1744 // -- lr : return address
1745 // -- sp[0] : key
1746 // -- sp[4] : receiver
1747 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001748 Label miss;
1749 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1750
1751 __ ldr(r2, MemOperand(sp));
1752 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver
1753
1754 __ cmp(r2, Operand(Handle<String>(name)));
1755 __ b(ne, &miss);
1756
ager@chromium.org5c838252010-02-19 08:53:10 +00001757 GenerateLoadStringLength(masm(), r0, r1, r3, &miss);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001758 __ bind(&miss);
1759 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1760
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001761 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1762
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001763 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001764}
1765
1766
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001767// TODO(1224671): implement the fast case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001769 // ----------- S t a t e -------------
1770 // -- lr : return address
1771 // -- sp[0] : key
1772 // -- sp[4] : receiver
1773 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001774 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1775
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001776 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001777}
1778
1779
1780Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1781 int index,
1782 Map* transition,
1783 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001784 // ----------- S t a t e -------------
1785 // -- r0 : value
1786 // -- r2 : name
1787 // -- lr : return address
1788 // -- [sp] : receiver
1789 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001790 Label miss;
1791
1792 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1793
1794 // Check that the name has not changed.
1795 __ cmp(r2, Operand(Handle<String>(name)));
1796 __ b(ne, &miss);
1797
1798 // Load receiver from the stack.
1799 __ ldr(r3, MemOperand(sp));
1800 // r1 is used as scratch register, r3 and r2 might be clobbered.
1801 GenerateStoreField(masm(),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001802 object,
1803 index,
1804 transition,
1805 r3, r2, r1,
1806 &miss);
1807 __ bind(&miss);
1808
1809 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1810 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001811 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
1812 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001814 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001815 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001816}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817
1818
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001819Object* ConstructStubCompiler::CompileConstructStub(
1820 SharedFunctionInfo* shared) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001821 // ----------- S t a t e -------------
1822 // -- r0 : argc
1823 // -- r1 : constructor
1824 // -- lr : return address
1825 // -- [sp] : last argument
1826 // -----------------------------------
1827 Label generic_stub_call;
1828
1829 // Use r7 for holding undefined which is used in several places below.
1830 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
1831
1832#ifdef ENABLE_DEBUGGER_SUPPORT
1833 // Check to see whether there are any break points in the function code. If
1834 // there are jump to the generic constructor stub which calls the actual
1835 // code for the function thereby hitting the break points.
1836 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1837 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
1838 __ cmp(r2, r7);
1839 __ b(ne, &generic_stub_call);
1840#endif
1841
1842 // Load the initial map and verify that it is in fact a map.
1843 // r1: constructor function
1844 // r7: undefined
1845 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
1846 __ tst(r2, Operand(kSmiTagMask));
1847 __ b(eq, &generic_stub_call);
1848 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
1849 __ b(ne, &generic_stub_call);
1850
1851#ifdef DEBUG
1852 // Cannot construct functions this way.
1853 // r0: argc
1854 // r1: constructor function
1855 // r2: initial map
1856 // r7: undefined
1857 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
1858 __ Check(ne, "Function constructed by construct stub.");
1859#endif
1860
1861 // Now allocate the JSObject in new space.
1862 // r0: argc
1863 // r1: constructor function
1864 // r2: initial map
1865 // r7: undefined
1866 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001867 __ AllocateInNewSpace(r3,
1868 r4,
1869 r5,
1870 r6,
1871 &generic_stub_call,
1872 NO_ALLOCATION_FLAGS);
ager@chromium.orga1645e22009-09-09 19:27:10 +00001873
1874 // Allocated the JSObject, now initialize the fields. Map is set to initial
1875 // map and properties and elements are set to empty fixed array.
1876 // r0: argc
1877 // r1: constructor function
1878 // r2: initial map
1879 // r3: object size (in words)
1880 // r4: JSObject (not tagged)
1881 // r7: undefined
1882 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
1883 __ mov(r5, r4);
1884 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
1885 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1886 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
1887 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1888 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
1889 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1890
1891 // Calculate the location of the first argument. The stack contains only the
1892 // argc arguments.
1893 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
1894
1895 // Fill all the in-object properties with undefined.
1896 // r0: argc
1897 // r1: first argument
1898 // r3: object size (in words)
1899 // r4: JSObject (not tagged)
1900 // r5: First in-object property of JSObject (not tagged)
1901 // r7: undefined
1902 // Fill the initialized properties with a constant value or a passed argument
1903 // depending on the this.x = ...; assignment in the function.
1904 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
1905 if (shared->IsThisPropertyAssignmentArgument(i)) {
1906 Label not_passed, next;
1907 // Check if the argument assigned to the property is actually passed.
1908 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
1909 __ cmp(r0, Operand(arg_number));
1910 __ b(le, &not_passed);
1911 // Argument passed - find it on the stack.
1912 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
1913 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1914 __ b(&next);
1915 __ bind(&not_passed);
1916 // Set the property to undefined.
1917 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1918 __ bind(&next);
1919 } else {
1920 // Set the property to the constant value.
1921 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
1922 __ mov(r2, Operand(constant));
1923 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1924 }
1925 }
1926
1927 // Fill the unused in-object property fields with undefined.
1928 for (int i = shared->this_property_assignments_count();
1929 i < shared->CalculateInObjectProperties();
1930 i++) {
1931 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1932 }
1933
1934 // r0: argc
1935 // r4: JSObject (not tagged)
1936 // Move argc to r1 and the JSObject to return to r0 and tag it.
1937 __ mov(r1, r0);
1938 __ mov(r0, r4);
1939 __ orr(r0, r0, Operand(kHeapObjectTag));
1940
1941 // r0: JSObject
1942 // r1: argc
1943 // Remove caller arguments and receiver from the stack and return.
1944 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
1945 __ add(sp, sp, Operand(kPointerSize));
1946 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
1947 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
1948 __ Jump(lr);
1949
1950 // Jump to the generic stub in case the specialized code cannot handle the
1951 // construction.
1952 __ bind(&generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001953 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1954 Handle<Code> generic_construct_stub(code);
1955 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
1956
1957 // Return the generated code.
1958 return GetCode();
1959}
1960
1961
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962#undef __
1963
1964} } // namespace v8::internal