blob: efccaf4960127c91dd667d9d3eba6d439813ebe6 [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.orga74f0da2008-12-03 16:05:52 +0000192// Generate code to check if an object is a string. If the object is
193// a string, the map's instance type is left in the scratch1 register.
194static void GenerateStringCheck(MacroAssembler* masm,
195 Register receiver,
196 Register scratch1,
197 Register scratch2,
198 Label* smi,
199 Label* non_string_object) {
200 // Check that the receiver isn't a smi.
201 __ tst(receiver, Operand(kSmiTagMask));
202 __ b(eq, smi);
203
204 // Check that the object is a string.
205 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
206 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
207 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
208 // The cast is to resolve the overload for the argument of 0x0.
209 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
210 __ b(ne, non_string_object);
211}
212
213
ager@chromium.org32912102009-01-16 10:38:43 +0000214// Generate code to load the length from a string object and return the length.
215// If the receiver object is not a string or a wrapped string object the
216// execution continues at the miss label. The register containing the
217// receiver is potentially clobbered.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000218void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm,
219 Register receiver,
220 Register scratch1,
221 Register scratch2,
222 Label* miss) {
ager@chromium.org32912102009-01-16 10:38:43 +0000223 Label check_string, check_wrapper;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000224
ager@chromium.org32912102009-01-16 10:38:43 +0000225 __ bind(&check_string);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000226 // Check if the object is a string leaving the instance type in the
227 // scratch1 register.
228 GenerateStringCheck(masm, receiver, scratch1, scratch2,
229 miss, &check_wrapper);
230
231 // Load length directly from the string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000232 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000233 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
234 __ Ret();
235
236 // Check if the object is a JSValue wrapper.
237 __ bind(&check_wrapper);
238 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
239 __ b(ne, miss);
240
ager@chromium.org32912102009-01-16 10:38:43 +0000241 // Unwrap the value in place and check if the wrapped value is a string.
242 __ ldr(receiver, FieldMemOperand(receiver, JSValue::kValueOffset));
243 __ b(&check_string);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000244}
245
246
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000247void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
248 Register receiver,
249 Register scratch1,
250 Register scratch2,
251 Label* miss_label) {
252 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
253 __ mov(r0, scratch1);
254 __ Ret();
255}
256
257
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000258// Generate StoreField code, value is passed in r0 register.
259// After executing generated code, the receiver_reg and name_reg
260// may be clobbered.
261void StubCompiler::GenerateStoreField(MacroAssembler* masm,
262 Builtins::Name storage_extend,
263 JSObject* object,
264 int index,
265 Map* transition,
266 Register receiver_reg,
267 Register name_reg,
268 Register scratch,
269 Label* miss_label) {
270 // r0 : value
271 Label exit;
272
273 // Check that the receiver isn't a smi.
274 __ tst(receiver_reg, Operand(kSmiTagMask));
275 __ b(eq, miss_label);
276
277 // Check that the map of the receiver hasn't changed.
278 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
279 __ cmp(scratch, Operand(Handle<Map>(object->map())));
280 __ b(ne, miss_label);
281
282 // Perform global security token check if needed.
283 if (object->IsJSGlobalProxy()) {
284 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
285 }
286
287 // Stub never generated for non-global objects that require access
288 // checks.
289 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
290
291 // Perform map transition for the receiver if necessary.
292 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
293 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000294 // We jump to a runtime call that extends the properties array.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000295 __ mov(r2, Operand(Handle<Map>(transition)));
296 // Please note, if we implement keyed store for arm we need
297 // to call the Builtins::KeyedStoreIC_ExtendStorage.
298 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
299 __ Jump(ic, RelocInfo::CODE_TARGET);
300 return;
301 }
302
303 if (transition != NULL) {
304 // Update the map of the object; no write barrier updating is
305 // needed because the map is never in new space.
306 __ mov(ip, Operand(Handle<Map>(transition)));
307 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
308 }
309
310 // Adjust for the number of properties stored in the object. Even in the
311 // face of a transition we can use the old map here because the size of the
312 // object and the number of in-object properties is not going to change.
313 index -= object->map()->inobject_properties();
314
315 if (index < 0) {
316 // Set the property straight into the object.
317 int offset = object->map()->instance_size() + (index * kPointerSize);
318 __ str(r0, FieldMemOperand(receiver_reg, offset));
319
320 // Skip updating write barrier if storing a smi.
321 __ tst(r0, Operand(kSmiTagMask));
322 __ b(eq, &exit);
323
324 // Update the write barrier for the array address.
325 // Pass the value being stored in the now unused name_reg.
326 __ mov(name_reg, Operand(offset));
327 __ RecordWrite(receiver_reg, name_reg, scratch);
328 } else {
329 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000330 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000331 // Get the properties array
332 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
333 __ str(r0, FieldMemOperand(scratch, offset));
334
335 // Skip updating write barrier if storing a smi.
336 __ tst(r0, Operand(kSmiTagMask));
337 __ b(eq, &exit);
338
339 // Update the write barrier for the array address.
340 // Ok to clobber receiver_reg and name_reg, since we return.
341 __ mov(name_reg, Operand(offset));
342 __ RecordWrite(scratch, name_reg, receiver_reg);
343 }
344
345 // Return the value (register r0).
346 __ bind(&exit);
347 __ Ret();
348}
349
350
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000351void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
352 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
353 Code* code = NULL;
354 if (kind == Code::LOAD_IC) {
355 code = Builtins::builtin(Builtins::LoadIC_Miss);
356 } else {
357 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
358 }
359
360 Handle<Code> ic(code);
361 __ Jump(ic, RelocInfo::CODE_TARGET);
362}
363
364
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000366#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367
368
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000369Register StubCompiler::CheckPrototypes(JSObject* object,
370 Register object_reg,
371 JSObject* holder,
372 Register holder_reg,
373 Register scratch,
374 String* name,
375 Label* miss) {
376 // Check that the maps haven't changed.
377 Register result =
378 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
379
380 // If we've skipped any global objects, it's not enough to verify
381 // that their maps haven't changed.
382 while (object != holder) {
383 if (object->IsGlobalObject()) {
384 GlobalObject* global = GlobalObject::cast(object);
385 Object* probe = global->EnsurePropertyCell(name);
386 if (probe->IsFailure()) {
387 set_failure(Failure::cast(probe));
388 return result;
389 }
390 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
391 ASSERT(cell->value()->IsTheHole());
392 __ mov(scratch, Operand(Handle<Object>(cell)));
393 __ ldr(scratch,
394 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000395 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
396 __ cmp(scratch, ip);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000397 __ b(ne, miss);
398 }
399 object = JSObject::cast(object->GetPrototype());
400 }
401
402 // Return the register containin the holder.
403 return result;
404}
405
406
407void StubCompiler::GenerateLoadField(JSObject* object,
408 JSObject* holder,
409 Register receiver,
410 Register scratch1,
411 Register scratch2,
412 int index,
413 String* name,
414 Label* miss) {
415 // Check that the receiver isn't a smi.
416 __ tst(receiver, Operand(kSmiTagMask));
417 __ b(eq, miss);
418
419 // Check that the maps haven't changed.
420 Register reg =
421 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
422 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
423 __ Ret();
424}
425
426
427void StubCompiler::GenerateLoadConstant(JSObject* object,
428 JSObject* holder,
429 Register receiver,
430 Register scratch1,
431 Register scratch2,
432 Object* value,
433 String* name,
434 Label* miss) {
435 // Check that the receiver isn't a smi.
436 __ tst(receiver, Operand(kSmiTagMask));
437 __ b(eq, miss);
438
439 // Check that the maps haven't changed.
440 Register reg =
441 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
442
443 // Return the constant value.
444 __ mov(r0, Operand(Handle<Object>(value)));
445 __ Ret();
446}
447
448
449void StubCompiler::GenerateLoadCallback(JSObject* object,
450 JSObject* holder,
451 Register receiver,
452 Register name_reg,
453 Register scratch1,
454 Register scratch2,
455 AccessorInfo* callback,
456 String* name,
457 Label* miss) {
458 // Check that the receiver isn't a smi.
459 __ tst(receiver, Operand(kSmiTagMask));
460 __ b(eq, miss);
461
462 // Check that the maps haven't changed.
463 Register reg =
464 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
465
466 // Push the arguments on the JS stack of the caller.
467 __ push(receiver); // receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000468 __ push(reg); // holder
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000469 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
470 __ push(ip);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000471 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
472 __ push(reg);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000473 __ push(name_reg); // name
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000474
475 // Do tail-call to the runtime system.
476 ExternalReference load_callback_property =
477 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000478 __ TailCallRuntime(load_callback_property, 5, 1);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000479}
480
481
482void StubCompiler::GenerateLoadInterceptor(JSObject* object,
483 JSObject* holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000484 LookupResult* lookup,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000485 Register receiver,
486 Register name_reg,
487 Register scratch1,
488 Register scratch2,
489 String* name,
490 Label* miss) {
491 // Check that the receiver isn't a smi.
492 __ tst(receiver, Operand(kSmiTagMask));
493 __ b(eq, miss);
494
495 // Check that the maps haven't changed.
496 Register reg =
497 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
498
499 // Push the arguments on the JS stack of the caller.
500 __ push(receiver); // receiver
501 __ push(reg); // holder
502 __ push(name_reg); // name
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000503
504 InterceptorInfo* interceptor = holder->GetNamedInterceptor();
505 ASSERT(!Heap::InNewSpace(interceptor));
506 __ mov(scratch1, Operand(Handle<Object>(interceptor)));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000507 __ push(scratch1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000508 __ ldr(scratch2, FieldMemOperand(scratch1, InterceptorInfo::kDataOffset));
509 __ push(scratch2);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000510
511 // Do tail-call to the runtime system.
512 ExternalReference load_ic_property =
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000513 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000514 __ TailCallRuntime(load_ic_property, 5, 1);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000515}
516
517
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000519 // ----------- S t a t e -------------
520 // -- r1: function
521 // -- lr: return address
522 // -----------------------------------
523
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000524 // Enter an internal frame.
525 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000527 // Preserve the function.
528 __ push(r1);
529
530 // Push the function on the stack as the argument to the runtime function.
531 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532 __ CallRuntime(Runtime::kLazyCompile, 1);
533
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000534 // Calculate the entry point.
535 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000537 // Restore saved function.
538 __ pop(r1);
539
540 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000541 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542
543 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000544 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000546 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547}
548
549
550Object* CallStubCompiler::CompileCallField(Object* object,
551 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000552 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000553 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000554 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000555 // -- lr: return address
556 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 Label miss;
558
mads.s.ager31e71382008-08-13 09:32:07 +0000559 const int argc = arguments().immediate();
560
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000561 // Get the receiver of the function from the stack into r0.
562 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563 // Check that the receiver isn't a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000564 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565 __ b(eq, &miss);
566
567 // Do the right check and compute the holder register.
568 Register reg =
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000569 CheckPrototypes(JSObject::cast(object), r0, holder, r3, r2, name, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000570 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000571
572 // Check that the function really is a function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000573 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574 __ b(eq, &miss);
575 // Get the map.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000576 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577 __ b(ne, &miss);
578
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000579 // Patch the receiver on the stack with the global proxy if
580 // necessary.
581 if (object->IsGlobalObject()) {
582 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
583 __ str(r3, MemOperand(sp, argc * kPointerSize));
584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000586 // Invoke the function.
587 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588
589 // Handle call cache miss.
590 __ bind(&miss);
591 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000592 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000593
594 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000595 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596}
597
598
599Object* CallStubCompiler::CompileCallConstant(Object* object,
600 JSObject* holder,
601 JSFunction* function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000602 String* name,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000603 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000604 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000605 // -- lr: return address
606 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000607 Label miss;
608
mads.s.ager31e71382008-08-13 09:32:07 +0000609 // Get the receiver from the stack
610 const int argc = arguments().immediate();
611 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
612
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000613 // Check that the receiver isn't a smi.
614 if (check != NUMBER_CHECK) {
615 __ tst(r1, Operand(kSmiTagMask));
616 __ b(eq, &miss);
617 }
618
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000619 // Make sure that it's okay not to patch the on stack receiver
620 // unless we're doing a receiver map check.
621 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
622
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 switch (check) {
624 case RECEIVER_MAP_CHECK:
625 // Check that the maps haven't changed.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000626 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000627
628 // Patch the receiver on the stack with the global proxy if
629 // necessary.
630 if (object->IsGlobalObject()) {
631 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
632 __ str(r3, MemOperand(sp, argc * kPointerSize));
633 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 break;
635
636 case STRING_CHECK:
637 // Check that the object is a two-byte string or a symbol.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000638 __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639 __ b(hs, &miss);
640 // Check that the maps starting from the prototype haven't changed.
641 GenerateLoadGlobalFunctionPrototype(masm(),
642 Context::STRING_FUNCTION_INDEX,
643 r2);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000644 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
645 r1, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646 break;
647
648 case NUMBER_CHECK: {
649 Label fast;
650 // Check that the object is a smi or a heap number.
651 __ tst(r1, Operand(kSmiTagMask));
652 __ b(eq, &fast);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000653 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000654 __ b(ne, &miss);
655 __ bind(&fast);
656 // Check that the maps starting from the prototype haven't changed.
657 GenerateLoadGlobalFunctionPrototype(masm(),
658 Context::NUMBER_FUNCTION_INDEX,
659 r2);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000660 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
661 r1, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000662 break;
663 }
664
665 case BOOLEAN_CHECK: {
666 Label fast;
667 // Check that the object is a boolean.
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000668 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
669 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670 __ b(eq, &fast);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000671 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
672 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000673 __ b(ne, &miss);
674 __ bind(&fast);
675 // Check that the maps starting from the prototype haven't changed.
676 GenerateLoadGlobalFunctionPrototype(masm(),
677 Context::BOOLEAN_FUNCTION_INDEX,
678 r2);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000679 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
680 r1, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000681 break;
682 }
683
684 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000685 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000686 // Make sure object->HasFastElements().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687 // Get the elements array of the object.
688 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
689 // Check that the object is in fast mode (not dictionary).
690 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000691 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
692 __ cmp(r2, ip);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000693 __ b(ne, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000694 break;
695
696 default:
697 UNREACHABLE();
698 }
699
700 // Get the function and setup the context.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000701 __ mov(r1, Operand(Handle<JSFunction>(function)));
702 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000703
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704 // Jump to the cached code (tail call).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000705 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000706 Handle<Code> code(function->code());
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000707 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000708 __ InvokeCode(code, expected, arguments(),
709 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000710
711 // Handle call cache miss.
712 __ bind(&miss);
713 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000714 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000715
716 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000717 String* function_name = NULL;
718 if (function->shared()->name()->IsString()) {
719 function_name = String::cast(function->shared()->name());
720 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000721 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000722}
723
724
725Object* CallStubCompiler::CompileCallInterceptor(Object* object,
726 JSObject* holder,
727 String* name) {
728 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000729 // -- lr: return address
730 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000731 Label miss;
732
733 // TODO(1224669): Implement.
734
735 // Handle call cache miss.
736 __ bind(&miss);
737 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000738 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739
740 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000741 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000742}
743
744
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000745Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
746 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000747 JSGlobalPropertyCell* cell,
748 JSFunction* function,
749 String* name) {
750 // ----------- S t a t e -------------
751 // -- lr: return address
752 // -----------------------------------
753 Label miss;
754
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000755 // Get the number of arguments.
756 const int argc = arguments().immediate();
757
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000758 // Get the receiver from the stack.
759 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
760
761 // If the object is the holder then we know that it's a global
762 // object which can only happen for contextual calls. In this case,
763 // the receiver cannot be a smi.
764 if (object != holder) {
765 __ tst(r0, Operand(kSmiTagMask));
766 __ b(eq, &miss);
767 }
768
769 // Check that the maps haven't changed.
770 CheckPrototypes(object, r0, holder, r3, r2, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000771
772 // Get the value from the cell.
773 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
774 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
775
776 // Check that the cell contains the same function.
777 __ cmp(r1, Operand(Handle<JSFunction>(function)));
778 __ b(ne, &miss);
779
780 // Patch the receiver on the stack with the global proxy if
781 // necessary.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000782 if (object->IsGlobalObject()) {
783 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
784 __ str(r3, MemOperand(sp, argc * kPointerSize));
785 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000786
787 // Setup the context (function already in r1).
788 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
789
790 // Jump to the cached code (tail call).
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000791 __ IncrementCounter(&Counters::call_global_inline, 1, r2, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000792 ASSERT(function->is_compiled());
793 Handle<Code> code(function->code());
794 ParameterCount expected(function->shared()->formal_parameter_count());
795 __ InvokeCode(code, expected, arguments(),
796 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
797
798 // Handle call cache miss.
799 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000800 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
801 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
802 __ Jump(ic, RelocInfo::CODE_TARGET);
803
804 // Return the generated code.
805 return GetCode(NORMAL, name);
806}
807
808
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000809Object* StoreStubCompiler::CompileStoreField(JSObject* object,
810 int index,
811 Map* transition,
812 String* name) {
813 // ----------- S t a t e -------------
814 // -- r0 : value
815 // -- r2 : name
816 // -- lr : return address
817 // -- [sp] : receiver
818 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000819 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000820
821 // Get the receiver from the stack.
822 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
823
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000824 // name register might be clobbered.
825 GenerateStoreField(masm(),
826 Builtins::StoreIC_ExtendStorage,
827 object,
828 index,
829 transition,
830 r3, r2, r1,
831 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832 __ bind(&miss);
833 __ mov(r2, Operand(Handle<String>(name))); // restore name
834 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000835 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000836
837 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000838 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839}
840
841
842Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
843 AccessorInfo* callback,
844 String* name) {
845 // ----------- S t a t e -------------
846 // -- r0 : value
847 // -- r2 : name
848 // -- lr : return address
849 // -- [sp] : receiver
850 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851 Label miss;
852
853 // Get the object from the stack.
854 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
855
856 // Check that the object isn't a smi.
857 __ tst(r3, Operand(kSmiTagMask));
858 __ b(eq, &miss);
859
860 // Check that the map of the object hasn't changed.
861 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
862 __ cmp(r1, Operand(Handle<Map>(object->map())));
863 __ b(ne, &miss);
864
865 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000866 if (object->IsJSGlobalProxy()) {
867 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868 }
869
870 // Stub never generated for non-global objects that require access
871 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000872 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873
874 __ ldr(ip, MemOperand(sp)); // receiver
875 __ push(ip);
876 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
877 __ push(ip);
878 __ push(r2); // name
879 __ push(r0); // value
880
mads.s.ager31e71382008-08-13 09:32:07 +0000881 // Do tail-call to the runtime system.
882 ExternalReference store_callback_property =
883 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000884 __ TailCallRuntime(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885
886 // Handle store cache miss.
887 __ bind(&miss);
888 __ mov(r2, Operand(Handle<String>(name))); // restore name
889 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000890 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891
892 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000893 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894}
895
896
897Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
898 String* name) {
899 // ----------- S t a t e -------------
900 // -- r0 : value
901 // -- r2 : name
902 // -- lr : return address
903 // -- [sp] : receiver
904 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000905 Label miss;
906
907 // Get the object from the stack.
908 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
909
910 // Check that the object isn't a smi.
911 __ tst(r3, Operand(kSmiTagMask));
912 __ b(eq, &miss);
913
914 // Check that the map of the object hasn't changed.
915 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
916 __ cmp(r1, Operand(Handle<Map>(receiver->map())));
917 __ b(ne, &miss);
918
919 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000920 if (receiver->IsJSGlobalProxy()) {
921 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000922 }
923
924 // Stub never generated for non-global objects that require access
925 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000926 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927
928 __ ldr(ip, MemOperand(sp)); // receiver
929 __ push(ip);
930 __ push(r2); // name
931 __ push(r0); // value
932
mads.s.ager31e71382008-08-13 09:32:07 +0000933 // Do tail-call to the runtime system.
934 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000935 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000936 __ TailCallRuntime(store_ic_property, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937
938 // Handle store cache miss.
939 __ bind(&miss);
940 __ mov(r2, Operand(Handle<String>(name))); // restore name
941 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000942 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000943
944 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000945 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000946}
947
948
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000949Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
950 JSGlobalPropertyCell* cell,
951 String* name) {
952 // ----------- S t a t e -------------
953 // -- r0 : value
954 // -- r2 : name
955 // -- lr : return address
956 // -- [sp] : receiver
957 // -----------------------------------
958 Label miss;
959
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000960 // Check that the map of the global has not changed.
961 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
962 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
963 __ cmp(r3, Operand(Handle<Map>(object->map())));
964 __ b(ne, &miss);
965
966 // Store the value in the cell.
967 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
968 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000969
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000970 __ IncrementCounter(&Counters::named_store_global_inline, 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000971 __ Ret();
972
973 // Handle store cache miss.
974 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000975 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r1, r3);
976 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
977 __ Jump(ic, RelocInfo::CODE_TARGET);
978
979 // Return the generated code.
980 return GetCode(NORMAL, name);
981}
982
983
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984Object* LoadStubCompiler::CompileLoadField(JSObject* object,
985 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000986 int index,
987 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989 // -- r2 : name
990 // -- lr : return address
991 // -- [sp] : receiver
992 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993 Label miss;
994
mads.s.ager31e71382008-08-13 09:32:07 +0000995 __ ldr(r0, MemOperand(sp, 0));
996
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000997 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000999 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001000
1001 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001002 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003}
1004
1005
1006Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
1007 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001008 AccessorInfo* callback,
1009 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 // -- r2 : name
1012 // -- lr : return address
1013 // -- [sp] : receiver
1014 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015 Label miss;
1016
mads.s.ager31e71382008-08-13 09:32:07 +00001017 __ ldr(r0, MemOperand(sp, 0));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001018 GenerateLoadCallback(object, holder, r0, r2, r3, r1, callback, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001020 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021
1022 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001023 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001024}
1025
1026
1027Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1028 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001029 Object* value,
1030 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001031 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001032 // -- r2 : name
1033 // -- lr : return address
1034 // -- [sp] : receiver
1035 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001036 Label miss;
1037
mads.s.ager31e71382008-08-13 09:32:07 +00001038 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001039
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001040 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001042 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043
1044 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001045 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046}
1047
1048
1049Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1050 JSObject* holder,
1051 String* name) {
1052 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053 // -- r2 : name
1054 // -- lr : return address
1055 // -- [sp] : receiver
1056 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 Label miss;
1058
mads.s.ager31e71382008-08-13 09:32:07 +00001059 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001061 LookupResult lookup;
1062 holder->LocalLookupRealNamedProperty(name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001063 GenerateLoadInterceptor(object,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001064 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001065 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001066 r0,
1067 r2,
1068 r3,
1069 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001070 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001071 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001073 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074
1075 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001076 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077}
1078
1079
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001080Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1081 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001082 JSGlobalPropertyCell* cell,
1083 String* name,
1084 bool is_dont_delete) {
1085 // ----------- S t a t e -------------
1086 // -- r2 : name
1087 // -- lr : return address
1088 // -- [sp] : receiver
1089 // -----------------------------------
1090 Label miss;
1091
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001092 // Get the receiver from the stack.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001093 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001094
1095 // If the object is the holder then we know that it's a global
1096 // object which can only happen for contextual calls. In this case,
1097 // the receiver cannot be a smi.
1098 if (object != holder) {
1099 __ tst(r1, Operand(kSmiTagMask));
1100 __ b(eq, &miss);
1101 }
1102
1103 // Check that the map of the global has not changed.
1104 CheckPrototypes(object, r1, holder, r3, r0, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001105
1106 // Get the value from the cell.
1107 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1108 __ ldr(r0, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1109
1110 // Check for deleted property if property can actually be deleted.
1111 if (!is_dont_delete) {
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001112 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1113 __ cmp(r0, ip);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001114 __ b(eq, &miss);
1115 }
1116
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001117 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001118 __ Ret();
1119
1120 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001121 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1122 GenerateLoadMiss(masm(), Code::LOAD_IC);
1123
1124 // Return the generated code.
1125 return GetCode(NORMAL, name);
1126}
1127
1128
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1130 JSObject* receiver,
1131 JSObject* holder,
1132 int index) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001133 // ----------- S t a t e -------------
1134 // -- lr : return address
1135 // -- sp[0] : key
1136 // -- sp[4] : receiver
1137 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001138 Label miss;
1139
1140 __ ldr(r2, MemOperand(sp, 0));
1141 __ ldr(r0, MemOperand(sp, kPointerSize));
1142
1143 __ cmp(r2, Operand(Handle<String>(name)));
1144 __ b(ne, &miss);
1145
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001146 GenerateLoadField(receiver, holder, r0, r3, r1, index, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001147 __ bind(&miss);
1148 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1149
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001150 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151}
1152
1153
1154Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1155 JSObject* receiver,
1156 JSObject* holder,
1157 AccessorInfo* callback) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001158 // ----------- S t a t e -------------
1159 // -- lr : return address
1160 // -- sp[0] : key
1161 // -- sp[4] : receiver
1162 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001163 Label miss;
1164
1165 __ ldr(r2, MemOperand(sp, 0));
1166 __ ldr(r0, MemOperand(sp, kPointerSize));
1167
1168 __ cmp(r2, Operand(Handle<String>(name)));
1169 __ b(ne, &miss);
1170
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001171 GenerateLoadCallback(receiver, holder, r0, r2, r3, r1, callback, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001172 __ bind(&miss);
1173 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1174
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001175 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176}
1177
1178
1179Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1180 JSObject* receiver,
1181 JSObject* holder,
1182 Object* value) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001183 // ----------- S t a t e -------------
1184 // -- lr : return address
1185 // -- sp[0] : key
1186 // -- sp[4] : receiver
1187 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001188 Label miss;
1189
1190 // Check the key is the cached one
1191 __ ldr(r2, MemOperand(sp, 0));
1192 __ ldr(r0, MemOperand(sp, kPointerSize));
1193
1194 __ cmp(r2, Operand(Handle<String>(name)));
1195 __ b(ne, &miss);
1196
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001197 GenerateLoadConstant(receiver, holder, r0, r3, r1, value, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001198 __ bind(&miss);
1199 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1200
1201 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001202 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203}
1204
1205
1206Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1207 JSObject* holder,
1208 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001209 // ----------- S t a t e -------------
1210 // -- lr : return address
1211 // -- sp[0] : key
1212 // -- sp[4] : receiver
1213 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001214 Label miss;
1215
1216 // Check the key is the cached one
1217 __ ldr(r2, MemOperand(sp, 0));
1218 __ ldr(r0, MemOperand(sp, kPointerSize));
1219
1220 __ cmp(r2, Operand(Handle<String>(name)));
1221 __ b(ne, &miss);
1222
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001223 LookupResult lookup;
1224 holder->LocalLookupRealNamedProperty(name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001225 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001226 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001227 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001228 r0,
1229 r2,
1230 r3,
1231 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001232 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001233 &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001234 __ bind(&miss);
1235 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1236
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001237 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001238}
1239
1240
1241Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001242 // ----------- S t a t e -------------
1243 // -- lr : return address
1244 // -- sp[0] : key
1245 // -- sp[4] : receiver
1246 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001247 Label miss;
1248
1249 // Check the key is the cached one
1250 __ ldr(r2, MemOperand(sp, 0));
1251 __ ldr(r0, MemOperand(sp, kPointerSize));
1252
1253 __ cmp(r2, Operand(Handle<String>(name)));
1254 __ b(ne, &miss);
1255
1256 GenerateLoadArrayLength(masm(), r0, r3, &miss);
1257 __ bind(&miss);
1258 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1259
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001260 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261}
1262
1263
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001264Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001265 // ----------- S t a t e -------------
1266 // -- lr : return address
1267 // -- sp[0] : key
1268 // -- sp[4] : receiver
1269 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001270 Label miss;
1271 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1272
1273 __ ldr(r2, MemOperand(sp));
1274 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver
1275
1276 __ cmp(r2, Operand(Handle<String>(name)));
1277 __ b(ne, &miss);
1278
1279 GenerateLoadStringLength2(masm(), r0, r1, r3, &miss);
1280 __ bind(&miss);
1281 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1282
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001283 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1284
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001285 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286}
1287
1288
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001289// TODO(1224671): implement the fast case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001291 // ----------- S t a t e -------------
1292 // -- lr : return address
1293 // -- sp[0] : key
1294 // -- sp[4] : receiver
1295 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001296 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1297
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001298 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299}
1300
1301
1302Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1303 int index,
1304 Map* transition,
1305 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001306 // ----------- S t a t e -------------
1307 // -- r0 : value
1308 // -- r2 : name
1309 // -- lr : return address
1310 // -- [sp] : receiver
1311 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001312 Label miss;
1313
1314 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1315
1316 // Check that the name has not changed.
1317 __ cmp(r2, Operand(Handle<String>(name)));
1318 __ b(ne, &miss);
1319
1320 // Load receiver from the stack.
1321 __ ldr(r3, MemOperand(sp));
1322 // r1 is used as scratch register, r3 and r2 might be clobbered.
1323 GenerateStoreField(masm(),
1324 Builtins::StoreIC_ExtendStorage,
1325 object,
1326 index,
1327 transition,
1328 r3, r2, r1,
1329 &miss);
1330 __ bind(&miss);
1331
1332 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1333 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001334 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
1335 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001337 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001338 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001339}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340
1341
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001342Object* ConstructStubCompiler::CompileConstructStub(
1343 SharedFunctionInfo* shared) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001344 // ----------- S t a t e -------------
1345 // -- r0 : argc
1346 // -- r1 : constructor
1347 // -- lr : return address
1348 // -- [sp] : last argument
1349 // -----------------------------------
1350 Label generic_stub_call;
1351
1352 // Use r7 for holding undefined which is used in several places below.
1353 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
1354
1355#ifdef ENABLE_DEBUGGER_SUPPORT
1356 // Check to see whether there are any break points in the function code. If
1357 // there are jump to the generic constructor stub which calls the actual
1358 // code for the function thereby hitting the break points.
1359 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1360 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
1361 __ cmp(r2, r7);
1362 __ b(ne, &generic_stub_call);
1363#endif
1364
1365 // Load the initial map and verify that it is in fact a map.
1366 // r1: constructor function
1367 // r7: undefined
1368 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
1369 __ tst(r2, Operand(kSmiTagMask));
1370 __ b(eq, &generic_stub_call);
1371 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
1372 __ b(ne, &generic_stub_call);
1373
1374#ifdef DEBUG
1375 // Cannot construct functions this way.
1376 // r0: argc
1377 // r1: constructor function
1378 // r2: initial map
1379 // r7: undefined
1380 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
1381 __ Check(ne, "Function constructed by construct stub.");
1382#endif
1383
1384 // Now allocate the JSObject in new space.
1385 // r0: argc
1386 // r1: constructor function
1387 // r2: initial map
1388 // r7: undefined
1389 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001390 __ AllocateInNewSpace(r3,
1391 r4,
1392 r5,
1393 r6,
1394 &generic_stub_call,
1395 NO_ALLOCATION_FLAGS);
ager@chromium.orga1645e22009-09-09 19:27:10 +00001396
1397 // Allocated the JSObject, now initialize the fields. Map is set to initial
1398 // map and properties and elements are set to empty fixed array.
1399 // r0: argc
1400 // r1: constructor function
1401 // r2: initial map
1402 // r3: object size (in words)
1403 // r4: JSObject (not tagged)
1404 // r7: undefined
1405 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
1406 __ mov(r5, r4);
1407 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
1408 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1409 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
1410 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1411 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
1412 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1413
1414 // Calculate the location of the first argument. The stack contains only the
1415 // argc arguments.
1416 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
1417
1418 // Fill all the in-object properties with undefined.
1419 // r0: argc
1420 // r1: first argument
1421 // r3: object size (in words)
1422 // r4: JSObject (not tagged)
1423 // r5: First in-object property of JSObject (not tagged)
1424 // r7: undefined
1425 // Fill the initialized properties with a constant value or a passed argument
1426 // depending on the this.x = ...; assignment in the function.
1427 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
1428 if (shared->IsThisPropertyAssignmentArgument(i)) {
1429 Label not_passed, next;
1430 // Check if the argument assigned to the property is actually passed.
1431 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
1432 __ cmp(r0, Operand(arg_number));
1433 __ b(le, &not_passed);
1434 // Argument passed - find it on the stack.
1435 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
1436 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1437 __ b(&next);
1438 __ bind(&not_passed);
1439 // Set the property to undefined.
1440 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1441 __ bind(&next);
1442 } else {
1443 // Set the property to the constant value.
1444 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
1445 __ mov(r2, Operand(constant));
1446 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1447 }
1448 }
1449
1450 // Fill the unused in-object property fields with undefined.
1451 for (int i = shared->this_property_assignments_count();
1452 i < shared->CalculateInObjectProperties();
1453 i++) {
1454 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1455 }
1456
1457 // r0: argc
1458 // r4: JSObject (not tagged)
1459 // Move argc to r1 and the JSObject to return to r0 and tag it.
1460 __ mov(r1, r0);
1461 __ mov(r0, r4);
1462 __ orr(r0, r0, Operand(kHeapObjectTag));
1463
1464 // r0: JSObject
1465 // r1: argc
1466 // Remove caller arguments and receiver from the stack and return.
1467 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
1468 __ add(sp, sp, Operand(kPointerSize));
1469 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
1470 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
1471 __ Jump(lr);
1472
1473 // Jump to the generic stub in case the specialized code cannot handle the
1474 // construction.
1475 __ bind(&generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001476 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1477 Handle<Code> generic_construct_stub(code);
1478 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
1479
1480 // Return the generated code.
1481 return GetCode();
1482}
1483
1484
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485#undef __
1486
1487} } // namespace v8::internal