blob: a770d160f028bc76314a2f0c24f517400f84fd74 [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));
fschneider@chromium.org013f3e12010-04-26 13:27:52 +000056 __ cmp(name, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057 __ 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));
kmillikin@chromium.orgf8253d72010-05-03 09:56:08 +0000232 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000233 __ 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));
kmillikin@chromium.orgf8253d72010-05-03 09:56:08 +0000244 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
ager@chromium.org5c838252010-02-19 08:53:10 +0000245 __ 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)));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000299 __ Push(r2, r0);
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);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000467 __ Push(holder, name_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000468
469 CompileCallLoadPropertyWithInterceptor(masm,
470 receiver,
471 holder,
472 name_,
473 holder_obj);
474
475 Label interceptor_failed;
476 // Compare with no_interceptor_result_sentinel.
477 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
478 __ cmp(r0, scratch1);
479 __ b(eq, &interceptor_failed);
480 __ LeaveInternalFrame();
481 __ Ret();
482
483 __ bind(&interceptor_failed);
484 __ pop(name_);
485 __ pop(holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000486 __ pop(receiver);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000487
488 __ LeaveInternalFrame();
489
490 if (lookup->type() == FIELD) {
491 holder = stub_compiler->CheckPrototypes(holder_obj,
492 holder,
493 lookup->holder(),
494 scratch1,
495 scratch2,
496 name,
497 miss_label);
498 stub_compiler->GenerateFastPropertyLoad(masm,
499 r0,
500 holder,
501 lookup->holder(),
502 lookup->GetFieldIndex());
503 __ Ret();
504 } else {
505 ASSERT(lookup->type() == CALLBACKS);
506 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
507 ASSERT(callback != NULL);
508 ASSERT(callback->getter() != NULL);
509
510 Label cleanup;
511 __ pop(scratch2);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000512 __ Push(receiver, scratch2);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000513
514 holder = stub_compiler->CheckPrototypes(holder_obj, holder,
515 lookup->holder(), scratch1,
516 scratch2,
517 name,
518 &cleanup);
519
520 __ push(holder);
521 __ Move(holder, Handle<AccessorInfo>(callback));
522 __ push(holder);
523 __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000524 __ Push(scratch1, name_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000525
526 ExternalReference ref =
527 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000528 __ TailCallExternalReference(ref, 5, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000529
530 __ bind(&cleanup);
531 __ pop(scratch1);
532 __ pop(scratch2);
533 __ push(scratch1);
534 }
535 }
536
537
538 void CompileRegular(MacroAssembler* masm,
539 Register receiver,
540 Register holder,
541 Register scratch,
542 JSObject* holder_obj,
543 Label* miss_label) {
544 PushInterceptorArguments(masm, receiver, holder, name_, holder_obj);
545
546 ExternalReference ref = ExternalReference(
547 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000548 __ TailCallExternalReference(ref, 5, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000549 }
550
551 private:
552 Register name_;
553};
554
555
ager@chromium.org5c838252010-02-19 08:53:10 +0000556static void CompileLoadInterceptor(LoadInterceptorCompiler* compiler,
557 StubCompiler* stub_compiler,
558 MacroAssembler* masm,
559 JSObject* object,
560 JSObject* holder,
561 String* name,
562 LookupResult* lookup,
563 Register receiver,
564 Register scratch1,
565 Register scratch2,
566 Label* miss) {
567 ASSERT(holder->HasNamedInterceptor());
568 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000569
ager@chromium.org5c838252010-02-19 08:53:10 +0000570 // Check that the receiver isn't a smi.
571 __ BranchOnSmi(receiver, miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000572
ager@chromium.org5c838252010-02-19 08:53:10 +0000573 // Check that the maps haven't changed.
574 Register reg =
575 stub_compiler->CheckPrototypes(object, receiver, holder,
576 scratch1, scratch2, name, miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000577
ager@chromium.org5c838252010-02-19 08:53:10 +0000578 if (lookup->IsProperty() && lookup->IsCacheable()) {
579 compiler->CompileCacheable(masm,
580 stub_compiler,
581 receiver,
582 reg,
583 scratch1,
584 scratch2,
585 holder,
586 lookup,
587 name,
588 miss);
589 } else {
590 compiler->CompileRegular(masm,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000591 receiver,
ager@chromium.org5c838252010-02-19 08:53:10 +0000592 reg,
593 scratch2,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000594 holder,
ager@chromium.org5c838252010-02-19 08:53:10 +0000595 miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000596 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000597}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000598
599
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000600// Generate code to check that a global property cell is empty. Create
601// the property cell at compilation time if no cell exists for the
602// property.
603static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
604 GlobalObject* global,
605 String* name,
606 Register scratch,
607 Label* miss) {
608 Object* probe = global->EnsurePropertyCell(name);
609 if (probe->IsFailure()) return probe;
610 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
611 ASSERT(cell->value()->IsTheHole());
612 __ mov(scratch, Operand(Handle<Object>(cell)));
613 __ ldr(scratch,
614 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
615 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
616 __ cmp(scratch, ip);
617 __ b(ne, miss);
618 return cell;
619}
620
621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000623#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624
625
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000626Register StubCompiler::CheckPrototypes(JSObject* object,
627 Register object_reg,
628 JSObject* holder,
629 Register holder_reg,
630 Register scratch,
631 String* name,
ager@chromium.org5c838252010-02-19 08:53:10 +0000632 int save_at_depth,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000633 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000634 // TODO(602): support object saving.
635 ASSERT(save_at_depth == kInvalidProtoDepth);
636
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000637 // Check that the maps haven't changed.
638 Register result =
639 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
640
641 // If we've skipped any global objects, it's not enough to verify
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000642 // that their maps haven't changed. We also need to check that the
643 // property cell for the property is still empty.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000644 while (object != holder) {
645 if (object->IsGlobalObject()) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000646 Object* cell = GenerateCheckPropertyCell(masm(),
647 GlobalObject::cast(object),
648 name,
649 scratch,
650 miss);
651 if (cell->IsFailure()) {
652 set_failure(Failure::cast(cell));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000653 return result;
654 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000655 }
656 object = JSObject::cast(object->GetPrototype());
657 }
658
ager@chromium.org5c838252010-02-19 08:53:10 +0000659 // Return the register containing the holder.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000660 return result;
661}
662
663
664void StubCompiler::GenerateLoadField(JSObject* object,
665 JSObject* holder,
666 Register receiver,
667 Register scratch1,
668 Register scratch2,
669 int index,
670 String* name,
671 Label* miss) {
672 // Check that the receiver isn't a smi.
673 __ tst(receiver, Operand(kSmiTagMask));
674 __ b(eq, miss);
675
676 // Check that the maps haven't changed.
677 Register reg =
678 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
679 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
680 __ Ret();
681}
682
683
684void StubCompiler::GenerateLoadConstant(JSObject* object,
685 JSObject* holder,
686 Register receiver,
687 Register scratch1,
688 Register scratch2,
689 Object* value,
690 String* name,
691 Label* miss) {
692 // Check that the receiver isn't a smi.
693 __ tst(receiver, Operand(kSmiTagMask));
694 __ b(eq, miss);
695
696 // Check that the maps haven't changed.
697 Register reg =
698 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
699
700 // Return the constant value.
701 __ mov(r0, Operand(Handle<Object>(value)));
702 __ Ret();
703}
704
705
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000706bool StubCompiler::GenerateLoadCallback(JSObject* object,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000707 JSObject* holder,
708 Register receiver,
709 Register name_reg,
710 Register scratch1,
711 Register scratch2,
712 AccessorInfo* callback,
713 String* name,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000714 Label* miss,
715 Failure** failure) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000716 // Check that the receiver isn't a smi.
717 __ tst(receiver, Operand(kSmiTagMask));
718 __ b(eq, miss);
719
720 // Check that the maps haven't changed.
721 Register reg =
722 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
723
724 // Push the arguments on the JS stack of the caller.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000725 __ push(receiver); // Receiver.
726 __ push(reg); // Holder.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000727 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000728 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000729 __ Push(ip, reg, name_reg);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000730
731 // Do tail-call to the runtime system.
732 ExternalReference load_callback_property =
733 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000734 __ TailCallExternalReference(load_callback_property, 5, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000735
736 return true;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000737}
738
739
740void StubCompiler::GenerateLoadInterceptor(JSObject* object,
741 JSObject* holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000742 LookupResult* lookup,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000743 Register receiver,
744 Register name_reg,
745 Register scratch1,
746 Register scratch2,
747 String* name,
748 Label* miss) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000749 LoadInterceptorCompiler compiler(name_reg);
750 CompileLoadInterceptor(&compiler,
751 this,
752 masm(),
753 object,
754 holder,
755 name,
756 lookup,
757 receiver,
758 scratch1,
759 scratch2,
760 miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000761}
762
763
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000765 // ----------- S t a t e -------------
766 // -- r1: function
767 // -- lr: return address
768 // -----------------------------------
769
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000770 // Enter an internal frame.
771 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000773 // Preserve the function.
774 __ push(r1);
775
776 // Push the function on the stack as the argument to the runtime function.
777 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778 __ CallRuntime(Runtime::kLazyCompile, 1);
779
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000780 // Calculate the entry point.
781 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000782
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000783 // Restore saved function.
784 __ pop(r1);
785
786 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000787 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000788
789 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000790 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000791
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000792 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793}
794
795
ager@chromium.org5c838252010-02-19 08:53:10 +0000796Object* CallStubCompiler::CompileCallField(JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000798 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000799 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000800 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000801 // -- r2 : name
802 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000804 Label miss;
805
mads.s.ager31e71382008-08-13 09:32:07 +0000806 const int argc = arguments().immediate();
807
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000808 // Get the receiver of the function from the stack into r0.
809 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000810 // Check that the receiver isn't a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000811 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000812 __ b(eq, &miss);
813
814 // Do the right check and compute the holder register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000815 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000816 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000817
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000818 GenerateCallFunction(masm(), object, arguments(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819
820 // Handle call cache miss.
821 __ bind(&miss);
822 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000823 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000824
825 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000826 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827}
828
829
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000830Object* CallStubCompiler::CompileArrayPushCall(Object* object,
831 JSObject* holder,
832 JSFunction* function,
833 String* name,
834 CheckType check) {
835 // ----------- S t a t e -------------
836 // -- r2 : name
837 // -- lr : return address
838 // -----------------------------------
839
840 // TODO(639): faster implementation.
841 ASSERT(check == RECEIVER_MAP_CHECK);
842
843 Label miss;
844
845 // Get the receiver from the stack
846 const int argc = arguments().immediate();
847 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
848
849 // Check that the receiver isn't a smi.
850 __ tst(r1, Operand(kSmiTagMask));
851 __ b(eq, &miss);
852
853 // Check that the maps haven't changed.
854 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
855
856 if (object->IsGlobalObject()) {
857 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
858 __ str(r3, MemOperand(sp, argc * kPointerSize));
859 }
860
861 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
862 argc + 1,
863 1);
864
865 // Handle call cache miss.
866 __ bind(&miss);
867 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
868 __ Jump(ic, RelocInfo::CODE_TARGET);
869
870 // Return the generated code.
871 String* function_name = NULL;
872 if (function->shared()->name()->IsString()) {
873 function_name = String::cast(function->shared()->name());
874 }
875 return GetCode(CONSTANT_FUNCTION, function_name);
876}
877
878
879Object* CallStubCompiler::CompileArrayPopCall(Object* object,
880 JSObject* holder,
881 JSFunction* function,
882 String* name,
883 CheckType check) {
884 // ----------- S t a t e -------------
885 // -- r2 : name
886 // -- lr : return address
887 // -----------------------------------
888
889 // TODO(642): faster implementation.
890 ASSERT(check == RECEIVER_MAP_CHECK);
891
892 Label miss;
893
894 // Get the receiver from the stack
895 const int argc = arguments().immediate();
896 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
897
898 // Check that the receiver isn't a smi.
899 __ tst(r1, Operand(kSmiTagMask));
900 __ b(eq, &miss);
901
902 // Check that the maps haven't changed.
903 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
904
905 if (object->IsGlobalObject()) {
906 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
907 __ str(r3, MemOperand(sp, argc * kPointerSize));
908 }
909
910 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
911 argc + 1,
912 1);
913
914 // Handle call cache miss.
915 __ bind(&miss);
916 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
917 __ Jump(ic, RelocInfo::CODE_TARGET);
918
919 // Return the generated code.
920 String* function_name = NULL;
921 if (function->shared()->name()->IsString()) {
922 function_name = String::cast(function->shared()->name());
923 }
924 return GetCode(CONSTANT_FUNCTION, function_name);
925}
926
927
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928Object* CallStubCompiler::CompileCallConstant(Object* object,
929 JSObject* holder,
930 JSFunction* function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000931 String* name,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000932 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000934 // -- r2 : name
935 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000936 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000937 SharedFunctionInfo* function_info = function->shared();
938 if (function_info->HasCustomCallGenerator()) {
939 CustomCallGenerator generator =
940 ToCData<CustomCallGenerator>(function_info->function_data());
941 return generator(this, object, holder, function, name, check);
942 }
943
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000944 Label miss;
945
mads.s.ager31e71382008-08-13 09:32:07 +0000946 // Get the receiver from the stack
947 const int argc = arguments().immediate();
948 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
949
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000950 // Check that the receiver isn't a smi.
951 if (check != NUMBER_CHECK) {
952 __ tst(r1, Operand(kSmiTagMask));
953 __ b(eq, &miss);
954 }
955
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000956 // Make sure that it's okay not to patch the on stack receiver
957 // unless we're doing a receiver map check.
958 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
959
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960 switch (check) {
961 case RECEIVER_MAP_CHECK:
962 // Check that the maps haven't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +0000963 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000964
965 // Patch the receiver on the stack with the global proxy if
966 // necessary.
967 if (object->IsGlobalObject()) {
968 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
969 __ str(r3, MemOperand(sp, argc * kPointerSize));
970 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000971 break;
972
973 case STRING_CHECK:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000974 if (!function->IsBuiltin()) {
975 // Calling non-builtins with a value as receiver requires boxing.
976 __ jmp(&miss);
977 } else {
978 // Check that the object is a two-byte string or a symbol.
ager@chromium.org5c838252010-02-19 08:53:10 +0000979 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000980 __ b(hs, &miss);
981 // Check that the maps starting from the prototype haven't changed.
982 GenerateLoadGlobalFunctionPrototype(masm(),
983 Context::STRING_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +0000984 r0);
985 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000986 r1, name, &miss);
987 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 break;
989
990 case NUMBER_CHECK: {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000991 if (!function->IsBuiltin()) {
992 // Calling non-builtins with a value as receiver requires boxing.
993 __ jmp(&miss);
994 } else {
995 Label fast;
996 // Check that the object is a smi or a heap number.
997 __ tst(r1, Operand(kSmiTagMask));
998 __ b(eq, &fast);
ager@chromium.org5c838252010-02-19 08:53:10 +0000999 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001000 __ b(ne, &miss);
1001 __ bind(&fast);
1002 // Check that the maps starting from the prototype haven't changed.
1003 GenerateLoadGlobalFunctionPrototype(masm(),
1004 Context::NUMBER_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +00001005 r0);
1006 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001007 r1, name, &miss);
1008 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009 break;
1010 }
1011
1012 case BOOLEAN_CHECK: {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001013 if (!function->IsBuiltin()) {
1014 // Calling non-builtins with a value as receiver requires boxing.
1015 __ jmp(&miss);
1016 } else {
1017 Label fast;
1018 // Check that the object is a boolean.
1019 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1020 __ cmp(r1, ip);
1021 __ b(eq, &fast);
1022 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1023 __ cmp(r1, ip);
1024 __ b(ne, &miss);
1025 __ bind(&fast);
1026 // Check that the maps starting from the prototype haven't changed.
1027 GenerateLoadGlobalFunctionPrototype(masm(),
1028 Context::BOOLEAN_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +00001029 r0);
1030 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001031 r1, name, &miss);
1032 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033 break;
1034 }
1035
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001036 default:
1037 UNREACHABLE();
1038 }
1039
ager@chromium.org5c838252010-02-19 08:53:10 +00001040 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041
1042 // Handle call cache miss.
1043 __ bind(&miss);
1044 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001045 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046
1047 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001048 String* function_name = NULL;
1049 if (function->shared()->name()->IsString()) {
1050 function_name = String::cast(function->shared()->name());
1051 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001052 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053}
1054
1055
ager@chromium.org5c838252010-02-19 08:53:10 +00001056Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 JSObject* holder,
1058 String* name) {
1059 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001060 // -- r2 : name
1061 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062 // -----------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001063 ASSERT(holder->HasNamedInterceptor());
1064 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065 Label miss;
1066
ager@chromium.org5c838252010-02-19 08:53:10 +00001067 const Register receiver = r0;
1068 const Register holder_reg = r1;
1069 const Register name_reg = r2;
1070 const Register scratch = r3;
1071
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001072 // Get the number of arguments.
1073 const int argc = arguments().immediate();
1074
1075 LookupResult lookup;
1076 LookupPostInterceptor(holder, name, &lookup);
1077
1078 // Get the receiver from the stack into r0.
1079 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001080
ager@chromium.org5c838252010-02-19 08:53:10 +00001081 // Check that the receiver isn't a smi.
1082 __ BranchOnSmi(receiver, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001083
ager@chromium.org5c838252010-02-19 08:53:10 +00001084 // Check that the maps haven't changed.
1085 Register reg = CheckPrototypes(object, receiver, holder, holder_reg,
1086 scratch, name, &miss);
1087 if (!reg.is(holder_reg)) {
1088 __ mov(holder_reg, reg);
1089 }
1090
1091 // If we call a constant function when the interceptor returns
1092 // the no-result sentinel, generate code that optimizes this case.
1093 if (lookup.IsProperty() &&
1094 lookup.IsCacheable() &&
1095 lookup.type() == CONSTANT_FUNCTION &&
1096 lookup.GetConstantFunction()->is_compiled() &&
1097 !holder->IsJSArray()) {
1098 // Constant functions cannot sit on global object.
1099 ASSERT(!lookup.holder()->IsGlobalObject());
1100
1101 // Call the interceptor.
1102 __ EnterInternalFrame();
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001103 __ Push(holder_reg, name_reg);
ager@chromium.org5c838252010-02-19 08:53:10 +00001104 CompileCallLoadPropertyWithInterceptor(masm(),
1105 receiver,
1106 holder_reg,
1107 name_reg,
1108 holder);
1109 __ pop(name_reg);
1110 __ pop(holder_reg);
1111 __ LeaveInternalFrame();
1112 // r0 no longer contains the receiver.
1113
1114 // If interceptor returns no-result sentinal, call the constant function.
1115 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1116 __ cmp(r0, scratch);
1117 Label invoke;
1118 __ b(ne, &invoke);
1119 // Check the prototypes between the interceptor's holder and the
1120 // constant function's holder.
1121 CheckPrototypes(holder, holder_reg,
1122 lookup.holder(), r0,
1123 scratch,
1124 name,
1125 &miss);
1126
1127 __ InvokeFunction(lookup.GetConstantFunction(),
1128 arguments(),
1129 JUMP_FUNCTION);
1130
1131 __ bind(&invoke);
1132
1133 } else {
1134 // Call a runtime function to load the interceptor property.
1135 __ EnterInternalFrame();
1136 __ push(name_reg);
1137
1138 PushInterceptorArguments(masm(), receiver, holder_reg, name_reg, holder);
1139
1140 __ CallExternalReference(
1141 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
1142 5);
1143
1144 __ pop(name_reg);
1145 __ LeaveInternalFrame();
1146 }
1147
1148 // Move returned value, the function to call, to r1.
1149 __ mov(r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001150 // Restore receiver.
ager@chromium.org5c838252010-02-19 08:53:10 +00001151 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001152
1153 GenerateCallFunction(masm(), object, arguments(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001154
1155 // Handle call cache miss.
1156 __ bind(&miss);
1157 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001158 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001159
1160 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001161 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162}
1163
1164
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001165Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1166 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001167 JSGlobalPropertyCell* cell,
1168 JSFunction* function,
1169 String* name) {
1170 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001171 // -- r2 : name
1172 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001173 // -----------------------------------
1174 Label miss;
1175
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001176 // Get the number of arguments.
1177 const int argc = arguments().immediate();
1178
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001179 // Get the receiver from the stack.
1180 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1181
1182 // If the object is the holder then we know that it's a global
1183 // object which can only happen for contextual calls. In this case,
1184 // the receiver cannot be a smi.
1185 if (object != holder) {
1186 __ tst(r0, Operand(kSmiTagMask));
1187 __ b(eq, &miss);
1188 }
1189
1190 // Check that the maps haven't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001191 CheckPrototypes(object, r0, holder, r3, r1, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001192
1193 // Get the value from the cell.
1194 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1195 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1196
1197 // Check that the cell contains the same function.
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001198 if (Heap::InNewSpace(function)) {
1199 // We can't embed a pointer to a function in new space so we have
1200 // to verify that the shared function info is unchanged. This has
1201 // the nice side effect that multiple closures based on the same
1202 // function can all use this call IC. Before we load through the
1203 // function, we have to verify that it still is a function.
1204 __ tst(r1, Operand(kSmiTagMask));
1205 __ b(eq, &miss);
1206 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1207 __ b(ne, &miss);
1208
1209 // Check the shared function info. Make sure it hasn't changed.
1210 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
ager@chromium.org5c838252010-02-19 08:53:10 +00001211 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1212 __ cmp(r4, r3);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001213 __ b(ne, &miss);
1214 } else {
1215 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1216 __ b(ne, &miss);
1217 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001218
1219 // Patch the receiver on the stack with the global proxy if
1220 // necessary.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001221 if (object->IsGlobalObject()) {
1222 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1223 __ str(r3, MemOperand(sp, argc * kPointerSize));
1224 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001225
1226 // Setup the context (function already in r1).
1227 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1228
1229 // Jump to the cached code (tail call).
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001230 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001231 ASSERT(function->is_compiled());
1232 Handle<Code> code(function->code());
1233 ParameterCount expected(function->shared()->formal_parameter_count());
1234 __ InvokeCode(code, expected, arguments(),
1235 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1236
1237 // Handle call cache miss.
1238 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001239 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
1240 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1241 __ Jump(ic, RelocInfo::CODE_TARGET);
1242
1243 // Return the generated code.
1244 return GetCode(NORMAL, name);
1245}
1246
1247
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001248Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1249 int index,
1250 Map* transition,
1251 String* name) {
1252 // ----------- S t a t e -------------
1253 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001254 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 // -- r2 : name
1256 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001258 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001259
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001260 GenerateStoreField(masm(),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001261 object,
1262 index,
1263 transition,
ager@chromium.org5c838252010-02-19 08:53:10 +00001264 r1, r2, r3,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001265 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001268 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269
1270 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001271 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272}
1273
1274
1275Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1276 AccessorInfo* callback,
1277 String* name) {
1278 // ----------- S t a t e -------------
1279 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001280 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281 // -- r2 : name
1282 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 Label miss;
1285
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 // Check that the object isn't a smi.
ager@chromium.org5c838252010-02-19 08:53:10 +00001287 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 __ b(eq, &miss);
1289
1290 // Check that the map of the object hasn't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001291 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1292 __ cmp(r3, Operand(Handle<Map>(object->map())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 __ b(ne, &miss);
1294
1295 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001296 if (object->IsJSGlobalProxy()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001297 __ CheckAccessGlobalProxy(r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 }
1299
1300 // Stub never generated for non-global objects that require access
1301 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001302 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303
ager@chromium.org5c838252010-02-19 08:53:10 +00001304 __ push(r1); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001306 __ Push(ip, r2, r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307
mads.s.ager31e71382008-08-13 09:32:07 +00001308 // Do tail-call to the runtime system.
1309 ExternalReference store_callback_property =
1310 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001311 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
1313 // Handle store cache miss.
1314 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001316 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317
1318 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001319 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320}
1321
1322
1323Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1324 String* name) {
1325 // ----------- S t a t e -------------
1326 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001327 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001328 // -- r2 : name
1329 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331 Label miss;
1332
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333 // Check that the object isn't a smi.
ager@chromium.org5c838252010-02-19 08:53:10 +00001334 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335 __ b(eq, &miss);
1336
1337 // Check that the map of the object hasn't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001338 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1339 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340 __ b(ne, &miss);
1341
1342 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001343 if (receiver->IsJSGlobalProxy()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001344 __ CheckAccessGlobalProxy(r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 }
1346
ager@chromium.org5c838252010-02-19 08:53:10 +00001347 // Stub is never generated for non-global objects that require access
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001349 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001351 __ Push(r1, r2, r0); // Receiver, name, value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352
mads.s.ager31e71382008-08-13 09:32:07 +00001353 // Do tail-call to the runtime system.
1354 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001356 __ TailCallExternalReference(store_ic_property, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357
1358 // Handle store cache miss.
1359 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001361 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001362
1363 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001364 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365}
1366
1367
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001368Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1369 JSGlobalPropertyCell* cell,
1370 String* name) {
1371 // ----------- S t a t e -------------
1372 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001373 // -- r1 : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001374 // -- r2 : name
1375 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001376 // -----------------------------------
1377 Label miss;
1378
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001379 // Check that the map of the global has not changed.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001380 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1381 __ cmp(r3, Operand(Handle<Map>(object->map())));
1382 __ b(ne, &miss);
1383
1384 // Store the value in the cell.
1385 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1386 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001387
ager@chromium.org5c838252010-02-19 08:53:10 +00001388 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001389 __ Ret();
1390
1391 // Handle store cache miss.
1392 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001393 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001394 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1395 __ Jump(ic, RelocInfo::CODE_TARGET);
1396
1397 // Return the generated code.
1398 return GetCode(NORMAL, name);
1399}
1400
1401
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001402Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1403 JSObject* object,
1404 JSObject* last) {
1405 // ----------- S t a t e -------------
1406 // -- r2 : name
1407 // -- lr : return address
1408 // -- [sp] : receiver
1409 // -----------------------------------
1410 Label miss;
1411
1412 // Load receiver.
1413 __ ldr(r0, MemOperand(sp, 0));
1414
1415 // Check that receiver is not a smi.
1416 __ tst(r0, Operand(kSmiTagMask));
1417 __ b(eq, &miss);
1418
1419 // Check the maps of the full prototype chain.
1420 CheckPrototypes(object, r0, last, r3, r1, name, &miss);
1421
1422 // If the last object in the prototype chain is a global object,
1423 // check that the global property cell is empty.
1424 if (last->IsGlobalObject()) {
1425 Object* cell = GenerateCheckPropertyCell(masm(),
1426 GlobalObject::cast(last),
1427 name,
1428 r1,
1429 &miss);
1430 if (cell->IsFailure()) return cell;
1431 }
1432
1433 // Return undefined if maps of the full prototype chain are still the
1434 // same and no global property with this name contains a value.
1435 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1436 __ Ret();
1437
1438 __ bind(&miss);
1439 GenerateLoadMiss(masm(), Code::LOAD_IC);
1440
1441 // Return the generated code.
1442 return GetCode(NONEXISTENT, Heap::empty_string());
1443}
1444
1445
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001446Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1447 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001448 int index,
1449 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451 // -- r2 : name
1452 // -- lr : return address
1453 // -- [sp] : receiver
1454 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001455 Label miss;
1456
mads.s.ager31e71382008-08-13 09:32:07 +00001457 __ ldr(r0, MemOperand(sp, 0));
1458
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001459 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001461 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001462
1463 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001464 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465}
1466
1467
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001468Object* LoadStubCompiler::CompileLoadCallback(String* name,
1469 JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 JSObject* holder,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001471 AccessorInfo* callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473 // -- r2 : name
1474 // -- lr : return address
1475 // -- [sp] : receiver
1476 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477 Label miss;
1478
mads.s.ager31e71382008-08-13 09:32:07 +00001479 __ ldr(r0, MemOperand(sp, 0));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001480 Failure* failure = Failure::InternalError();
1481 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
1482 callback, name, &miss, &failure);
1483 if (!success) return failure;
1484
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001486 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487
1488 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001489 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490}
1491
1492
1493Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1494 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001495 Object* value,
1496 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001498 // -- r2 : name
1499 // -- lr : return address
1500 // -- [sp] : receiver
1501 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 Label miss;
1503
mads.s.ager31e71382008-08-13 09:32:07 +00001504 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001505
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001506 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001508 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509
1510 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001511 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001512}
1513
1514
1515Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1516 JSObject* holder,
1517 String* name) {
1518 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519 // -- r2 : name
1520 // -- lr : return address
1521 // -- [sp] : receiver
1522 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523 Label miss;
1524
mads.s.ager31e71382008-08-13 09:32:07 +00001525 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001527 LookupResult lookup;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001528 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001529 GenerateLoadInterceptor(object,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001530 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001531 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001532 r0,
1533 r2,
1534 r3,
1535 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001536 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001537 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001538 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001539 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540
1541 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001542 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543}
1544
1545
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001546Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1547 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001548 JSGlobalPropertyCell* cell,
1549 String* name,
1550 bool is_dont_delete) {
1551 // ----------- S t a t e -------------
1552 // -- r2 : name
1553 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001554 // -- r0 : receiver
1555 // -- sp[0] : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001556 // -----------------------------------
1557 Label miss;
1558
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001559 // If the object is the holder then we know that it's a global
1560 // object which can only happen for contextual calls. In this case,
1561 // the receiver cannot be a smi.
1562 if (object != holder) {
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001563 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001564 __ b(eq, &miss);
1565 }
1566
1567 // Check that the map of the global has not changed.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001568 CheckPrototypes(object, r0, holder, r3, r4, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001569
1570 // Get the value from the cell.
1571 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001572 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001573
1574 // Check for deleted property if property can actually be deleted.
1575 if (!is_dont_delete) {
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001576 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001577 __ cmp(r4, ip);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001578 __ b(eq, &miss);
1579 }
1580
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001581 __ mov(r0, r4);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001582 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001583 __ Ret();
1584
1585 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001586 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1587 GenerateLoadMiss(masm(), Code::LOAD_IC);
1588
1589 // Return the generated code.
1590 return GetCode(NORMAL, name);
1591}
1592
1593
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1595 JSObject* receiver,
1596 JSObject* holder,
1597 int index) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001598 // ----------- S t a t e -------------
1599 // -- lr : return address
1600 // -- sp[0] : key
1601 // -- sp[4] : receiver
1602 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001603 Label miss;
1604
1605 __ ldr(r2, MemOperand(sp, 0));
1606 __ ldr(r0, MemOperand(sp, kPointerSize));
1607
1608 __ cmp(r2, Operand(Handle<String>(name)));
1609 __ b(ne, &miss);
1610
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001611 GenerateLoadField(receiver, holder, r0, r3, r1, index, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001612 __ bind(&miss);
1613 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1614
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001615 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001616}
1617
1618
1619Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1620 JSObject* receiver,
1621 JSObject* holder,
1622 AccessorInfo* callback) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001623 // ----------- S t a t e -------------
1624 // -- lr : return address
1625 // -- sp[0] : key
1626 // -- sp[4] : receiver
1627 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001628 Label miss;
1629
1630 __ ldr(r2, MemOperand(sp, 0));
1631 __ ldr(r0, MemOperand(sp, kPointerSize));
1632
1633 __ cmp(r2, Operand(Handle<String>(name)));
1634 __ b(ne, &miss);
1635
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001636 Failure* failure = Failure::InternalError();
1637 bool success = GenerateLoadCallback(receiver, holder, r0, r2, r3, r1,
1638 callback, name, &miss, &failure);
1639 if (!success) return failure;
1640
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001641 __ bind(&miss);
1642 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1643
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001644 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645}
1646
1647
1648Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1649 JSObject* receiver,
1650 JSObject* holder,
1651 Object* value) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001652 // ----------- S t a t e -------------
1653 // -- lr : return address
1654 // -- sp[0] : key
1655 // -- sp[4] : receiver
1656 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001657 Label miss;
1658
1659 // Check the key is the cached one
1660 __ ldr(r2, MemOperand(sp, 0));
1661 __ ldr(r0, MemOperand(sp, kPointerSize));
1662
1663 __ cmp(r2, Operand(Handle<String>(name)));
1664 __ b(ne, &miss);
1665
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001666 GenerateLoadConstant(receiver, holder, r0, r3, r1, value, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001667 __ bind(&miss);
1668 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1669
1670 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001671 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001672}
1673
1674
1675Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1676 JSObject* holder,
1677 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001678 // ----------- S t a t e -------------
1679 // -- lr : return address
1680 // -- sp[0] : key
1681 // -- sp[4] : receiver
1682 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001683 Label miss;
1684
1685 // Check the key is the cached one
1686 __ ldr(r2, MemOperand(sp, 0));
1687 __ ldr(r0, MemOperand(sp, kPointerSize));
1688
1689 __ cmp(r2, Operand(Handle<String>(name)));
1690 __ b(ne, &miss);
1691
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001692 LookupResult lookup;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001693 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001694 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001695 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001696 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001697 r0,
1698 r2,
1699 r3,
1700 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001701 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001702 &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001703 __ bind(&miss);
1704 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1705
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001706 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001707}
1708
1709
1710Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001711 // ----------- S t a t e -------------
1712 // -- lr : return address
1713 // -- sp[0] : key
1714 // -- sp[4] : receiver
1715 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001716 Label miss;
1717
1718 // Check the key is the cached one
1719 __ ldr(r2, MemOperand(sp, 0));
1720 __ ldr(r0, MemOperand(sp, kPointerSize));
1721
1722 __ cmp(r2, Operand(Handle<String>(name)));
1723 __ b(ne, &miss);
1724
1725 GenerateLoadArrayLength(masm(), r0, r3, &miss);
1726 __ bind(&miss);
1727 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1728
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001729 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001730}
1731
1732
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001733Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001734 // ----------- S t a t e -------------
1735 // -- lr : return address
1736 // -- sp[0] : key
1737 // -- sp[4] : receiver
1738 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001739 Label miss;
1740 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1741
1742 __ ldr(r2, MemOperand(sp));
1743 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver
1744
1745 __ cmp(r2, Operand(Handle<String>(name)));
1746 __ b(ne, &miss);
1747
ager@chromium.org5c838252010-02-19 08:53:10 +00001748 GenerateLoadStringLength(masm(), r0, r1, r3, &miss);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001749 __ bind(&miss);
1750 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1751
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001752 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1753
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001754 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001755}
1756
1757
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001758// TODO(1224671): implement the fast case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001759Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001760 // ----------- S t a t e -------------
1761 // -- lr : return address
1762 // -- sp[0] : key
1763 // -- sp[4] : receiver
1764 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001765 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1766
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001767 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768}
1769
1770
1771Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1772 int index,
1773 Map* transition,
1774 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001775 // ----------- S t a t e -------------
1776 // -- r0 : value
1777 // -- r2 : name
1778 // -- lr : return address
1779 // -- [sp] : receiver
1780 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001781 Label miss;
1782
1783 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1784
1785 // Check that the name has not changed.
1786 __ cmp(r2, Operand(Handle<String>(name)));
1787 __ b(ne, &miss);
1788
1789 // Load receiver from the stack.
1790 __ ldr(r3, MemOperand(sp));
1791 // r1 is used as scratch register, r3 and r2 might be clobbered.
1792 GenerateStoreField(masm(),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001793 object,
1794 index,
1795 transition,
1796 r3, r2, r1,
1797 &miss);
1798 __ bind(&miss);
1799
1800 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1801 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001802 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
1803 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001805 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001806 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001807}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001808
1809
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001810Object* ConstructStubCompiler::CompileConstructStub(
1811 SharedFunctionInfo* shared) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001812 // ----------- S t a t e -------------
1813 // -- r0 : argc
1814 // -- r1 : constructor
1815 // -- lr : return address
1816 // -- [sp] : last argument
1817 // -----------------------------------
1818 Label generic_stub_call;
1819
1820 // Use r7 for holding undefined which is used in several places below.
1821 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
1822
1823#ifdef ENABLE_DEBUGGER_SUPPORT
1824 // Check to see whether there are any break points in the function code. If
1825 // there are jump to the generic constructor stub which calls the actual
1826 // code for the function thereby hitting the break points.
1827 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1828 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
1829 __ cmp(r2, r7);
1830 __ b(ne, &generic_stub_call);
1831#endif
1832
1833 // Load the initial map and verify that it is in fact a map.
1834 // r1: constructor function
1835 // r7: undefined
1836 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
1837 __ tst(r2, Operand(kSmiTagMask));
1838 __ b(eq, &generic_stub_call);
1839 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
1840 __ b(ne, &generic_stub_call);
1841
1842#ifdef DEBUG
1843 // Cannot construct functions this way.
1844 // r0: argc
1845 // r1: constructor function
1846 // r2: initial map
1847 // r7: undefined
1848 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
1849 __ Check(ne, "Function constructed by construct stub.");
1850#endif
1851
1852 // Now allocate the JSObject in new space.
1853 // r0: argc
1854 // r1: constructor function
1855 // r2: initial map
1856 // r7: undefined
1857 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001858 __ AllocateInNewSpace(r3,
1859 r4,
1860 r5,
1861 r6,
1862 &generic_stub_call,
1863 NO_ALLOCATION_FLAGS);
ager@chromium.orga1645e22009-09-09 19:27:10 +00001864
1865 // Allocated the JSObject, now initialize the fields. Map is set to initial
1866 // map and properties and elements are set to empty fixed array.
1867 // r0: argc
1868 // r1: constructor function
1869 // r2: initial map
1870 // r3: object size (in words)
1871 // r4: JSObject (not tagged)
1872 // r7: undefined
1873 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
1874 __ mov(r5, r4);
1875 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
1876 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1877 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
1878 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1879 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
1880 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1881
1882 // Calculate the location of the first argument. The stack contains only the
1883 // argc arguments.
1884 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
1885
1886 // Fill all the in-object properties with undefined.
1887 // r0: argc
1888 // r1: first argument
1889 // r3: object size (in words)
1890 // r4: JSObject (not tagged)
1891 // r5: First in-object property of JSObject (not tagged)
1892 // r7: undefined
1893 // Fill the initialized properties with a constant value or a passed argument
1894 // depending on the this.x = ...; assignment in the function.
1895 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
1896 if (shared->IsThisPropertyAssignmentArgument(i)) {
1897 Label not_passed, next;
1898 // Check if the argument assigned to the property is actually passed.
1899 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
1900 __ cmp(r0, Operand(arg_number));
1901 __ b(le, &not_passed);
1902 // Argument passed - find it on the stack.
1903 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
1904 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1905 __ b(&next);
1906 __ bind(&not_passed);
1907 // Set the property to undefined.
1908 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1909 __ bind(&next);
1910 } else {
1911 // Set the property to the constant value.
1912 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
1913 __ mov(r2, Operand(constant));
1914 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1915 }
1916 }
1917
1918 // Fill the unused in-object property fields with undefined.
1919 for (int i = shared->this_property_assignments_count();
1920 i < shared->CalculateInObjectProperties();
1921 i++) {
1922 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1923 }
1924
1925 // r0: argc
1926 // r4: JSObject (not tagged)
1927 // Move argc to r1 and the JSObject to return to r0 and tag it.
1928 __ mov(r1, r0);
1929 __ mov(r0, r4);
1930 __ orr(r0, r0, Operand(kHeapObjectTag));
1931
1932 // r0: JSObject
1933 // r1: argc
1934 // Remove caller arguments and receiver from the stack and return.
1935 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
1936 __ add(sp, sp, Operand(kPointerSize));
1937 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
1938 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
1939 __ Jump(lr);
1940
1941 // Jump to the generic stub in case the specialized code cannot handle the
1942 // construction.
1943 __ bind(&generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001944 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1945 Handle<Code> generic_construct_stub(code);
1946 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
1947
1948 // Return the generated code.
1949 return GetCode();
1950}
1951
1952
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953#undef __
1954
1955} } // namespace v8::internal