blob: 958842d2c8645213cff47fb0bf340722d0981f56 [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
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000449bool StubCompiler::GenerateLoadCallback(JSObject* object,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000450 JSObject* holder,
451 Register receiver,
452 Register name_reg,
453 Register scratch1,
454 Register scratch2,
455 AccessorInfo* callback,
456 String* name,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000457 Label* miss,
458 Failure** failure) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000459 // Check that the receiver isn't a smi.
460 __ tst(receiver, Operand(kSmiTagMask));
461 __ b(eq, miss);
462
463 // Check that the maps haven't changed.
464 Register reg =
465 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
466
467 // Push the arguments on the JS stack of the caller.
468 __ push(receiver); // receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000469 __ push(reg); // holder
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000470 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
471 __ push(ip);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000472 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
473 __ push(reg);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000474 __ push(name_reg); // name
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000475
476 // Do tail-call to the runtime system.
477 ExternalReference load_callback_property =
478 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000479 __ TailCallRuntime(load_callback_property, 5, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000480
481 return true;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000482}
483
484
485void StubCompiler::GenerateLoadInterceptor(JSObject* object,
486 JSObject* holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000487 LookupResult* lookup,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000488 Register receiver,
489 Register name_reg,
490 Register scratch1,
491 Register scratch2,
492 String* name,
493 Label* miss) {
494 // Check that the receiver isn't a smi.
495 __ tst(receiver, Operand(kSmiTagMask));
496 __ b(eq, miss);
497
498 // Check that the maps haven't changed.
499 Register reg =
500 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
501
502 // Push the arguments on the JS stack of the caller.
503 __ push(receiver); // receiver
504 __ push(reg); // holder
505 __ push(name_reg); // name
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000506
507 InterceptorInfo* interceptor = holder->GetNamedInterceptor();
508 ASSERT(!Heap::InNewSpace(interceptor));
509 __ mov(scratch1, Operand(Handle<Object>(interceptor)));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000510 __ push(scratch1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000511 __ ldr(scratch2, FieldMemOperand(scratch1, InterceptorInfo::kDataOffset));
512 __ push(scratch2);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000513
514 // Do tail-call to the runtime system.
515 ExternalReference load_ic_property =
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000516 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000517 __ TailCallRuntime(load_ic_property, 5, 1);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000518}
519
520
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000521Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000522 // ----------- S t a t e -------------
523 // -- r1: function
524 // -- lr: return address
525 // -----------------------------------
526
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000527 // Enter an internal frame.
528 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000530 // Preserve the function.
531 __ push(r1);
532
533 // Push the function on the stack as the argument to the runtime function.
534 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535 __ CallRuntime(Runtime::kLazyCompile, 1);
536
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000537 // Calculate the entry point.
538 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000539
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000540 // Restore saved function.
541 __ pop(r1);
542
543 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000544 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545
546 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000547 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000549 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550}
551
552
553Object* CallStubCompiler::CompileCallField(Object* object,
554 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000555 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000556 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000558 // -- lr: return address
559 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560 Label miss;
561
mads.s.ager31e71382008-08-13 09:32:07 +0000562 const int argc = arguments().immediate();
563
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000564 // Get the receiver of the function from the stack into r0.
565 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 // Check that the receiver isn't a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000567 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 __ b(eq, &miss);
569
570 // Do the right check and compute the holder register.
571 Register reg =
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000572 CheckPrototypes(JSObject::cast(object), r0, holder, r3, r2, name, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000573 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574
575 // Check that the function really is a function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000576 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577 __ b(eq, &miss);
578 // Get the map.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000579 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580 __ b(ne, &miss);
581
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000582 // Patch the receiver on the stack with the global proxy if
583 // necessary.
584 if (object->IsGlobalObject()) {
585 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
586 __ str(r3, MemOperand(sp, argc * kPointerSize));
587 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000589 // Invoke the function.
590 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000591
592 // Handle call cache miss.
593 __ bind(&miss);
594 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000595 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596
597 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000598 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599}
600
601
602Object* CallStubCompiler::CompileCallConstant(Object* object,
603 JSObject* holder,
604 JSFunction* function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000605 String* name,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000606 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000607 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000608 // -- lr: return address
609 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000610 Label miss;
611
mads.s.ager31e71382008-08-13 09:32:07 +0000612 // Get the receiver from the stack
613 const int argc = arguments().immediate();
614 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616 // Check that the receiver isn't a smi.
617 if (check != NUMBER_CHECK) {
618 __ tst(r1, Operand(kSmiTagMask));
619 __ b(eq, &miss);
620 }
621
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000622 // Make sure that it's okay not to patch the on stack receiver
623 // unless we're doing a receiver map check.
624 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 switch (check) {
627 case RECEIVER_MAP_CHECK:
628 // Check that the maps haven't changed.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000629 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000630
631 // Patch the receiver on the stack with the global proxy if
632 // necessary.
633 if (object->IsGlobalObject()) {
634 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
635 __ str(r3, MemOperand(sp, argc * kPointerSize));
636 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637 break;
638
639 case STRING_CHECK:
640 // Check that the object is a two-byte string or a symbol.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000641 __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642 __ b(hs, &miss);
643 // Check that the maps starting from the prototype haven't changed.
644 GenerateLoadGlobalFunctionPrototype(masm(),
645 Context::STRING_FUNCTION_INDEX,
646 r2);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000647 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
648 r1, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 break;
650
651 case NUMBER_CHECK: {
652 Label fast;
653 // Check that the object is a smi or a heap number.
654 __ tst(r1, Operand(kSmiTagMask));
655 __ b(eq, &fast);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000656 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657 __ b(ne, &miss);
658 __ bind(&fast);
659 // Check that the maps starting from the prototype haven't changed.
660 GenerateLoadGlobalFunctionPrototype(masm(),
661 Context::NUMBER_FUNCTION_INDEX,
662 r2);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000663 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
664 r1, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665 break;
666 }
667
668 case BOOLEAN_CHECK: {
669 Label fast;
670 // Check that the object is a boolean.
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000671 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
672 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000673 __ b(eq, &fast);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000674 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
675 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000676 __ b(ne, &miss);
677 __ bind(&fast);
678 // Check that the maps starting from the prototype haven't changed.
679 GenerateLoadGlobalFunctionPrototype(masm(),
680 Context::BOOLEAN_FUNCTION_INDEX,
681 r2);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000682 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
683 r1, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000684 break;
685 }
686
687 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000688 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000689 // Make sure object->HasFastElements().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000690 // Get the elements array of the object.
691 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
692 // Check that the object is in fast mode (not dictionary).
693 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000694 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
695 __ cmp(r2, ip);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000696 __ b(ne, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697 break;
698
699 default:
700 UNREACHABLE();
701 }
702
703 // Get the function and setup the context.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000704 __ mov(r1, Operand(Handle<JSFunction>(function)));
705 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000706
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707 // Jump to the cached code (tail call).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000708 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000709 Handle<Code> code(function->code());
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000710 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000711 __ InvokeCode(code, expected, arguments(),
712 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000713
714 // Handle call cache miss.
715 __ bind(&miss);
716 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000717 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000718
719 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000720 String* function_name = NULL;
721 if (function->shared()->name()->IsString()) {
722 function_name = String::cast(function->shared()->name());
723 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000724 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000725}
726
727
728Object* CallStubCompiler::CompileCallInterceptor(Object* object,
729 JSObject* holder,
730 String* name) {
731 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000732 // -- lr: return address
733 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000734 Label miss;
735
736 // TODO(1224669): Implement.
737
738 // Handle call cache miss.
739 __ bind(&miss);
740 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000741 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000742
743 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000744 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745}
746
747
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000748Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
749 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000750 JSGlobalPropertyCell* cell,
751 JSFunction* function,
752 String* name) {
753 // ----------- S t a t e -------------
754 // -- lr: return address
755 // -----------------------------------
756 Label miss;
757
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000758 // Get the number of arguments.
759 const int argc = arguments().immediate();
760
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000761 // Get the receiver from the stack.
762 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
763
764 // If the object is the holder then we know that it's a global
765 // object which can only happen for contextual calls. In this case,
766 // the receiver cannot be a smi.
767 if (object != holder) {
768 __ tst(r0, Operand(kSmiTagMask));
769 __ b(eq, &miss);
770 }
771
772 // Check that the maps haven't changed.
773 CheckPrototypes(object, r0, holder, r3, r2, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000774
775 // Get the value from the cell.
776 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
777 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
778
779 // Check that the cell contains the same function.
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000780 if (Heap::InNewSpace(function)) {
781 // We can't embed a pointer to a function in new space so we have
782 // to verify that the shared function info is unchanged. This has
783 // the nice side effect that multiple closures based on the same
784 // function can all use this call IC. Before we load through the
785 // function, we have to verify that it still is a function.
786 __ tst(r1, Operand(kSmiTagMask));
787 __ b(eq, &miss);
788 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
789 __ b(ne, &miss);
790
791 // Check the shared function info. Make sure it hasn't changed.
792 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
793 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
794 __ cmp(r2, r3);
795 __ b(ne, &miss);
796 } else {
797 __ cmp(r1, Operand(Handle<JSFunction>(function)));
798 __ b(ne, &miss);
799 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000800
801 // Patch the receiver on the stack with the global proxy if
802 // necessary.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000803 if (object->IsGlobalObject()) {
804 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
805 __ str(r3, MemOperand(sp, argc * kPointerSize));
806 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000807
808 // Setup the context (function already in r1).
809 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
810
811 // Jump to the cached code (tail call).
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000812 __ IncrementCounter(&Counters::call_global_inline, 1, r2, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000813 ASSERT(function->is_compiled());
814 Handle<Code> code(function->code());
815 ParameterCount expected(function->shared()->formal_parameter_count());
816 __ InvokeCode(code, expected, arguments(),
817 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
818
819 // Handle call cache miss.
820 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000821 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
822 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
823 __ Jump(ic, RelocInfo::CODE_TARGET);
824
825 // Return the generated code.
826 return GetCode(NORMAL, name);
827}
828
829
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830Object* StoreStubCompiler::CompileStoreField(JSObject* object,
831 int index,
832 Map* transition,
833 String* name) {
834 // ----------- S t a t e -------------
835 // -- r0 : value
836 // -- r2 : name
837 // -- lr : return address
838 // -- [sp] : receiver
839 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000840 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841
842 // Get the receiver from the stack.
843 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
844
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000845 // name register might be clobbered.
846 GenerateStoreField(masm(),
847 Builtins::StoreIC_ExtendStorage,
848 object,
849 index,
850 transition,
851 r3, r2, r1,
852 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000853 __ bind(&miss);
854 __ mov(r2, Operand(Handle<String>(name))); // restore name
855 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000856 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000857
858 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000859 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000860}
861
862
863Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
864 AccessorInfo* callback,
865 String* name) {
866 // ----------- S t a t e -------------
867 // -- r0 : value
868 // -- r2 : name
869 // -- lr : return address
870 // -- [sp] : receiver
871 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 Label miss;
873
874 // Get the object from the stack.
875 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
876
877 // Check that the object isn't a smi.
878 __ tst(r3, Operand(kSmiTagMask));
879 __ b(eq, &miss);
880
881 // Check that the map of the object hasn't changed.
882 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
883 __ cmp(r1, Operand(Handle<Map>(object->map())));
884 __ b(ne, &miss);
885
886 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000887 if (object->IsJSGlobalProxy()) {
888 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 }
890
891 // Stub never generated for non-global objects that require access
892 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000893 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894
895 __ ldr(ip, MemOperand(sp)); // receiver
896 __ push(ip);
897 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
898 __ push(ip);
899 __ push(r2); // name
900 __ push(r0); // value
901
mads.s.ager31e71382008-08-13 09:32:07 +0000902 // Do tail-call to the runtime system.
903 ExternalReference store_callback_property =
904 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000905 __ TailCallRuntime(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906
907 // Handle store cache miss.
908 __ bind(&miss);
909 __ mov(r2, Operand(Handle<String>(name))); // restore name
910 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000911 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912
913 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000914 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000915}
916
917
918Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
919 String* name) {
920 // ----------- S t a t e -------------
921 // -- r0 : value
922 // -- r2 : name
923 // -- lr : return address
924 // -- [sp] : receiver
925 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 Label miss;
927
928 // Get the object from the stack.
929 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
930
931 // Check that the object isn't a smi.
932 __ tst(r3, Operand(kSmiTagMask));
933 __ b(eq, &miss);
934
935 // Check that the map of the object hasn't changed.
936 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
937 __ cmp(r1, Operand(Handle<Map>(receiver->map())));
938 __ b(ne, &miss);
939
940 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000941 if (receiver->IsJSGlobalProxy()) {
942 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000943 }
944
945 // Stub never generated for non-global objects that require access
946 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000947 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948
949 __ ldr(ip, MemOperand(sp)); // receiver
950 __ push(ip);
951 __ push(r2); // name
952 __ push(r0); // value
953
mads.s.ager31e71382008-08-13 09:32:07 +0000954 // Do tail-call to the runtime system.
955 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000957 __ TailCallRuntime(store_ic_property, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000958
959 // Handle store cache miss.
960 __ bind(&miss);
961 __ mov(r2, Operand(Handle<String>(name))); // restore name
962 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000963 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000964
965 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000966 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000967}
968
969
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000970Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
971 JSGlobalPropertyCell* cell,
972 String* name) {
973 // ----------- S t a t e -------------
974 // -- r0 : value
975 // -- r2 : name
976 // -- lr : return address
977 // -- [sp] : receiver
978 // -----------------------------------
979 Label miss;
980
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000981 // Check that the map of the global has not changed.
982 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
983 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
984 __ cmp(r3, Operand(Handle<Map>(object->map())));
985 __ b(ne, &miss);
986
987 // Store the value in the cell.
988 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
989 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000990
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000991 __ IncrementCounter(&Counters::named_store_global_inline, 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000992 __ Ret();
993
994 // Handle store cache miss.
995 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000996 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r1, r3);
997 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
998 __ Jump(ic, RelocInfo::CODE_TARGET);
999
1000 // Return the generated code.
1001 return GetCode(NORMAL, name);
1002}
1003
1004
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1006 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001007 int index,
1008 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 // -- r2 : name
1011 // -- lr : return address
1012 // -- [sp] : receiver
1013 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014 Label miss;
1015
mads.s.ager31e71382008-08-13 09:32:07 +00001016 __ ldr(r0, MemOperand(sp, 0));
1017
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001018 GenerateLoadField(object, holder, r0, r3, r1, index, 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(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001024}
1025
1026
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001027Object* LoadStubCompiler::CompileLoadCallback(String* name,
1028 JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029 JSObject* holder,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001030 AccessorInfo* callback) {
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));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001039 Failure* failure = Failure::InternalError();
1040 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
1041 callback, name, &miss, &failure);
1042 if (!success) return failure;
1043
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001045 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046
1047 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001048 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049}
1050
1051
1052Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1053 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001054 Object* value,
1055 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 // -- r2 : name
1058 // -- lr : return address
1059 // -- [sp] : receiver
1060 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061 Label miss;
1062
mads.s.ager31e71382008-08-13 09:32:07 +00001063 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001065 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001067 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068
1069 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001070 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071}
1072
1073
1074Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1075 JSObject* holder,
1076 String* name) {
1077 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078 // -- r2 : name
1079 // -- lr : return address
1080 // -- [sp] : receiver
1081 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082 Label miss;
1083
mads.s.ager31e71382008-08-13 09:32:07 +00001084 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001086 LookupResult lookup;
1087 holder->LocalLookupRealNamedProperty(name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001088 GenerateLoadInterceptor(object,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001089 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001090 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001091 r0,
1092 r2,
1093 r3,
1094 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001095 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001096 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001097 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001098 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099
1100 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001101 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102}
1103
1104
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001105Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1106 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001107 JSGlobalPropertyCell* cell,
1108 String* name,
1109 bool is_dont_delete) {
1110 // ----------- S t a t e -------------
1111 // -- r2 : name
1112 // -- lr : return address
1113 // -- [sp] : receiver
1114 // -----------------------------------
1115 Label miss;
1116
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001117 // Get the receiver from the stack.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001118 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001119
1120 // If the object is the holder then we know that it's a global
1121 // object which can only happen for contextual calls. In this case,
1122 // the receiver cannot be a smi.
1123 if (object != holder) {
1124 __ tst(r1, Operand(kSmiTagMask));
1125 __ b(eq, &miss);
1126 }
1127
1128 // Check that the map of the global has not changed.
1129 CheckPrototypes(object, r1, holder, r3, r0, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001130
1131 // Get the value from the cell.
1132 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1133 __ ldr(r0, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1134
1135 // Check for deleted property if property can actually be deleted.
1136 if (!is_dont_delete) {
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001137 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1138 __ cmp(r0, ip);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001139 __ b(eq, &miss);
1140 }
1141
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001142 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001143 __ Ret();
1144
1145 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001146 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1147 GenerateLoadMiss(masm(), Code::LOAD_IC);
1148
1149 // Return the generated code.
1150 return GetCode(NORMAL, name);
1151}
1152
1153
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001154Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1155 JSObject* receiver,
1156 JSObject* holder,
1157 int index) {
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 GenerateLoadField(receiver, holder, r0, r3, r1, index, 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(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176}
1177
1178
1179Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1180 JSObject* receiver,
1181 JSObject* holder,
1182 AccessorInfo* callback) {
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 __ ldr(r2, MemOperand(sp, 0));
1191 __ ldr(r0, MemOperand(sp, kPointerSize));
1192
1193 __ cmp(r2, Operand(Handle<String>(name)));
1194 __ b(ne, &miss);
1195
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001196 Failure* failure = Failure::InternalError();
1197 bool success = GenerateLoadCallback(receiver, holder, r0, r2, r3, r1,
1198 callback, name, &miss, &failure);
1199 if (!success) return failure;
1200
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001201 __ bind(&miss);
1202 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1203
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001204 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205}
1206
1207
1208Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1209 JSObject* receiver,
1210 JSObject* holder,
1211 Object* value) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001212 // ----------- S t a t e -------------
1213 // -- lr : return address
1214 // -- sp[0] : key
1215 // -- sp[4] : receiver
1216 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001217 Label miss;
1218
1219 // Check the key is the cached one
1220 __ ldr(r2, MemOperand(sp, 0));
1221 __ ldr(r0, MemOperand(sp, kPointerSize));
1222
1223 __ cmp(r2, Operand(Handle<String>(name)));
1224 __ b(ne, &miss);
1225
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001226 GenerateLoadConstant(receiver, holder, r0, r3, r1, value, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001227 __ bind(&miss);
1228 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1229
1230 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001231 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232}
1233
1234
1235Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1236 JSObject* holder,
1237 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001238 // ----------- S t a t e -------------
1239 // -- lr : return address
1240 // -- sp[0] : key
1241 // -- sp[4] : receiver
1242 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001243 Label miss;
1244
1245 // Check the key is the cached one
1246 __ ldr(r2, MemOperand(sp, 0));
1247 __ ldr(r0, MemOperand(sp, kPointerSize));
1248
1249 __ cmp(r2, Operand(Handle<String>(name)));
1250 __ b(ne, &miss);
1251
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001252 LookupResult lookup;
1253 holder->LocalLookupRealNamedProperty(name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001254 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001255 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001256 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001257 r0,
1258 r2,
1259 r3,
1260 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001261 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001262 &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001263 __ bind(&miss);
1264 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1265
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001266 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267}
1268
1269
1270Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001271 // ----------- S t a t e -------------
1272 // -- lr : return address
1273 // -- sp[0] : key
1274 // -- sp[4] : receiver
1275 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001276 Label miss;
1277
1278 // Check the key is the cached one
1279 __ ldr(r2, MemOperand(sp, 0));
1280 __ ldr(r0, MemOperand(sp, kPointerSize));
1281
1282 __ cmp(r2, Operand(Handle<String>(name)));
1283 __ b(ne, &miss);
1284
1285 GenerateLoadArrayLength(masm(), r0, r3, &miss);
1286 __ bind(&miss);
1287 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1288
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001289 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290}
1291
1292
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001293Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001294 // ----------- S t a t e -------------
1295 // -- lr : return address
1296 // -- sp[0] : key
1297 // -- sp[4] : receiver
1298 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001299 Label miss;
1300 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1301
1302 __ ldr(r2, MemOperand(sp));
1303 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver
1304
1305 __ cmp(r2, Operand(Handle<String>(name)));
1306 __ b(ne, &miss);
1307
1308 GenerateLoadStringLength2(masm(), r0, r1, r3, &miss);
1309 __ bind(&miss);
1310 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1311
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001312 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1313
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001314 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315}
1316
1317
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001318// TODO(1224671): implement the fast case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001320 // ----------- S t a t e -------------
1321 // -- lr : return address
1322 // -- sp[0] : key
1323 // -- sp[4] : receiver
1324 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001325 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1326
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001327 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001328}
1329
1330
1331Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1332 int index,
1333 Map* transition,
1334 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001335 // ----------- S t a t e -------------
1336 // -- r0 : value
1337 // -- r2 : name
1338 // -- lr : return address
1339 // -- [sp] : receiver
1340 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001341 Label miss;
1342
1343 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1344
1345 // Check that the name has not changed.
1346 __ cmp(r2, Operand(Handle<String>(name)));
1347 __ b(ne, &miss);
1348
1349 // Load receiver from the stack.
1350 __ ldr(r3, MemOperand(sp));
1351 // r1 is used as scratch register, r3 and r2 might be clobbered.
1352 GenerateStoreField(masm(),
1353 Builtins::StoreIC_ExtendStorage,
1354 object,
1355 index,
1356 transition,
1357 r3, r2, r1,
1358 &miss);
1359 __ bind(&miss);
1360
1361 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1362 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001363 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
1364 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001366 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001367 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001368}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369
1370
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001371Object* ConstructStubCompiler::CompileConstructStub(
1372 SharedFunctionInfo* shared) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001373 // ----------- S t a t e -------------
1374 // -- r0 : argc
1375 // -- r1 : constructor
1376 // -- lr : return address
1377 // -- [sp] : last argument
1378 // -----------------------------------
1379 Label generic_stub_call;
1380
1381 // Use r7 for holding undefined which is used in several places below.
1382 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
1383
1384#ifdef ENABLE_DEBUGGER_SUPPORT
1385 // Check to see whether there are any break points in the function code. If
1386 // there are jump to the generic constructor stub which calls the actual
1387 // code for the function thereby hitting the break points.
1388 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1389 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
1390 __ cmp(r2, r7);
1391 __ b(ne, &generic_stub_call);
1392#endif
1393
1394 // Load the initial map and verify that it is in fact a map.
1395 // r1: constructor function
1396 // r7: undefined
1397 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
1398 __ tst(r2, Operand(kSmiTagMask));
1399 __ b(eq, &generic_stub_call);
1400 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
1401 __ b(ne, &generic_stub_call);
1402
1403#ifdef DEBUG
1404 // Cannot construct functions this way.
1405 // r0: argc
1406 // r1: constructor function
1407 // r2: initial map
1408 // r7: undefined
1409 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
1410 __ Check(ne, "Function constructed by construct stub.");
1411#endif
1412
1413 // Now allocate the JSObject in new space.
1414 // r0: argc
1415 // r1: constructor function
1416 // r2: initial map
1417 // r7: undefined
1418 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001419 __ AllocateInNewSpace(r3,
1420 r4,
1421 r5,
1422 r6,
1423 &generic_stub_call,
1424 NO_ALLOCATION_FLAGS);
ager@chromium.orga1645e22009-09-09 19:27:10 +00001425
1426 // Allocated the JSObject, now initialize the fields. Map is set to initial
1427 // map and properties and elements are set to empty fixed array.
1428 // r0: argc
1429 // r1: constructor function
1430 // r2: initial map
1431 // r3: object size (in words)
1432 // r4: JSObject (not tagged)
1433 // r7: undefined
1434 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
1435 __ mov(r5, r4);
1436 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
1437 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1438 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
1439 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1440 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
1441 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1442
1443 // Calculate the location of the first argument. The stack contains only the
1444 // argc arguments.
1445 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
1446
1447 // Fill all the in-object properties with undefined.
1448 // r0: argc
1449 // r1: first argument
1450 // r3: object size (in words)
1451 // r4: JSObject (not tagged)
1452 // r5: First in-object property of JSObject (not tagged)
1453 // r7: undefined
1454 // Fill the initialized properties with a constant value or a passed argument
1455 // depending on the this.x = ...; assignment in the function.
1456 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
1457 if (shared->IsThisPropertyAssignmentArgument(i)) {
1458 Label not_passed, next;
1459 // Check if the argument assigned to the property is actually passed.
1460 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
1461 __ cmp(r0, Operand(arg_number));
1462 __ b(le, &not_passed);
1463 // Argument passed - find it on the stack.
1464 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
1465 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1466 __ b(&next);
1467 __ bind(&not_passed);
1468 // Set the property to undefined.
1469 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1470 __ bind(&next);
1471 } else {
1472 // Set the property to the constant value.
1473 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
1474 __ mov(r2, Operand(constant));
1475 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1476 }
1477 }
1478
1479 // Fill the unused in-object property fields with undefined.
1480 for (int i = shared->this_property_assignments_count();
1481 i < shared->CalculateInObjectProperties();
1482 i++) {
1483 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1484 }
1485
1486 // r0: argc
1487 // r4: JSObject (not tagged)
1488 // Move argc to r1 and the JSObject to return to r0 and tag it.
1489 __ mov(r1, r0);
1490 __ mov(r0, r4);
1491 __ orr(r0, r0, Operand(kHeapObjectTag));
1492
1493 // r0: JSObject
1494 // r1: argc
1495 // Remove caller arguments and receiver from the stack and return.
1496 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
1497 __ add(sp, sp, Operand(kPointerSize));
1498 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
1499 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
1500 __ Jump(lr);
1501
1502 // Jump to the generic stub in case the specialized code cannot handle the
1503 // construction.
1504 __ bind(&generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001505 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1506 Handle<Code> generic_construct_stub(code);
1507 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
1508
1509 // Return the generated code.
1510 return GetCode();
1511}
1512
1513
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514#undef __
1515
1516} } // namespace v8::internal