blob: fd0d24859d79eeb0e1e1c89b6167b52be0730bcb [file] [log] [blame]
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "ic-inl.h"
31#include "codegen-inl.h"
32#include "stub-cache.h"
33
kasperl@chromium.org71affb52009-05-26 05:44:31 +000034namespace v8 {
35namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
ager@chromium.org65dad4b2009-04-23 08:48:43 +000037#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
39
40static void ProbeTable(MacroAssembler* masm,
41 Code::Flags flags,
42 StubCache::Table table,
43 Register name,
44 Register offset) {
45 ExternalReference key_offset(SCTableReference::keyReference(table));
46 ExternalReference value_offset(SCTableReference::valueReference(table));
47
48 Label miss;
49
50 // Save the offset on the stack.
51 __ push(offset);
52
53 // Check that the key in the entry matches the name.
54 __ mov(ip, Operand(key_offset));
55 __ ldr(ip, MemOperand(ip, offset, LSL, 1));
fschneider@chromium.org013f3e12010-04-26 13:27:52 +000056 __ cmp(name, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057 __ b(ne, &miss);
58
59 // Get the code entry from the cache.
60 __ mov(ip, Operand(value_offset));
61 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
62
63 // Check that the flags match what we're looking for.
64 __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
kasperl@chromium.org71affb52009-05-26 05:44:31 +000065 __ and_(offset, offset, Operand(~Code::kFlagsNotUsedInLookup));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066 __ cmp(offset, Operand(flags));
67 __ b(ne, &miss);
68
69 // Restore offset and re-load code entry from cache.
70 __ pop(offset);
71 __ mov(ip, Operand(value_offset));
72 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
73
74 // Jump to the first instruction in the code stub.
75 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
76 __ Jump(offset);
77
78 // Miss: Restore offset and fall through.
79 __ bind(&miss);
80 __ pop(offset);
81}
82
83
84void StubCache::GenerateProbe(MacroAssembler* masm,
85 Code::Flags flags,
86 Register receiver,
87 Register name,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000088 Register scratch,
89 Register extra) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090 Label miss;
91
92 // Make sure that code is valid. The shifting code relies on the
93 // entry size being 8.
94 ASSERT(sizeof(Entry) == 8);
95
96 // Make sure the flags does not name a specific type.
97 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
98
99 // Make sure that there are no register conflicts.
100 ASSERT(!scratch.is(receiver));
101 ASSERT(!scratch.is(name));
102
103 // Check that the receiver isn't a smi.
104 __ tst(receiver, Operand(kSmiTagMask));
105 __ b(eq, &miss);
106
107 // Get the map of the receiver and compute the hash.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000108 __ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000109 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 __ add(scratch, scratch, Operand(ip));
111 __ eor(scratch, scratch, Operand(flags));
112 __ and_(scratch,
113 scratch,
114 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
115
116 // Probe the primary table.
117 ProbeTable(masm, flags, kPrimary, name, scratch);
118
119 // Primary miss: Compute hash for secondary probe.
120 __ sub(scratch, scratch, Operand(name));
121 __ add(scratch, scratch, Operand(flags));
122 __ and_(scratch,
123 scratch,
124 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
125
126 // Probe the secondary table.
127 ProbeTable(masm, flags, kSecondary, name, scratch);
128
129 // Cache miss: Fall-through and let caller handle the miss by
130 // entering the runtime system.
131 __ bind(&miss);
132}
133
134
135void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
136 int index,
137 Register prototype) {
138 // Load the global or builtins object from the current context.
139 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
140 // Load the global context from the global or builtins object.
141 __ ldr(prototype,
142 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
143 // Load the function from the global context.
144 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
145 // Load the initial map. The global functions all have initial maps.
146 __ ldr(prototype,
147 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
148 // Load the prototype from the initial map.
149 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
150}
151
152
ager@chromium.org7c537e22008-10-16 08:43:32 +0000153// Load a fast property out of a holder object (src). In-object properties
154// are loaded directly otherwise the property is loaded from the properties
155// fixed array.
156void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
157 Register dst, Register src,
158 JSObject* holder, int index) {
159 // Adjust for the number of properties stored in the holder.
160 index -= holder->map()->inobject_properties();
161 if (index < 0) {
162 // Get the property straight out of the holder.
163 int offset = holder->map()->instance_size() + (index * kPointerSize);
164 __ ldr(dst, FieldMemOperand(src, offset));
165 } else {
166 // Calculate the offset into the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000167 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000168 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
169 __ ldr(dst, FieldMemOperand(dst, offset));
170 }
171}
172
173
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000174void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
175 Register receiver,
176 Register scratch,
177 Label* miss_label) {
178 // Check that the receiver isn't a smi.
179 __ tst(receiver, Operand(kSmiTagMask));
180 __ b(eq, miss_label);
181
182 // Check that the object is a JS array.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000183 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000184 __ b(ne, miss_label);
185
186 // Load length directly from the JS array.
187 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
188 __ Ret();
189}
190
191
ager@chromium.org5c838252010-02-19 08:53:10 +0000192// Generate code to check if an object is a string. If the object is a
193// heap object, its map's instance type is left in the scratch1 register.
194// If this is not needed, scratch1 and scratch2 may be the same register.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000195static void GenerateStringCheck(MacroAssembler* masm,
196 Register receiver,
197 Register scratch1,
198 Register scratch2,
199 Label* smi,
200 Label* non_string_object) {
201 // Check that the receiver isn't a smi.
202 __ tst(receiver, Operand(kSmiTagMask));
203 __ b(eq, smi);
204
205 // Check that the object is a string.
206 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
207 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
208 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
209 // The cast is to resolve the overload for the argument of 0x0.
210 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
211 __ b(ne, non_string_object);
212}
213
214
ager@chromium.org32912102009-01-16 10:38:43 +0000215// Generate code to load the length from a string object and return the length.
216// If the receiver object is not a string or a wrapped string object the
217// execution continues at the miss label. The register containing the
218// receiver is potentially clobbered.
ager@chromium.org5c838252010-02-19 08:53:10 +0000219void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
220 Register receiver,
221 Register scratch1,
222 Register scratch2,
223 Label* miss) {
224 Label check_wrapper;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000225
226 // Check if the object is a string leaving the instance type in the
227 // scratch1 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000228 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000229
230 // Load length directly from the string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000231 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
kmillikin@chromium.orgf8253d72010-05-03 09:56:08 +0000232 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000233 __ Ret();
234
235 // Check if the object is a JSValue wrapper.
236 __ bind(&check_wrapper);
237 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
238 __ b(ne, miss);
239
ager@chromium.org5c838252010-02-19 08:53:10 +0000240 // Unwrap the value and check if the wrapped value is a string.
241 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
242 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
243 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
kmillikin@chromium.orgf8253d72010-05-03 09:56:08 +0000244 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
ager@chromium.org5c838252010-02-19 08:53:10 +0000245 __ Ret();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000246}
247
248
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000249void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
250 Register receiver,
251 Register scratch1,
252 Register scratch2,
253 Label* miss_label) {
254 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
255 __ mov(r0, scratch1);
256 __ Ret();
257}
258
259
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000260// Generate StoreField code, value is passed in r0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000261// When leaving generated code after success, the receiver_reg and name_reg
262// may be clobbered. Upon branch to miss_label, the receiver and name
263// registers have their original values.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000264void StubCompiler::GenerateStoreField(MacroAssembler* masm,
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000265 JSObject* object,
266 int index,
267 Map* transition,
268 Register receiver_reg,
269 Register name_reg,
270 Register scratch,
271 Label* miss_label) {
272 // r0 : value
273 Label exit;
274
275 // Check that the receiver isn't a smi.
276 __ tst(receiver_reg, Operand(kSmiTagMask));
277 __ b(eq, miss_label);
278
279 // Check that the map of the receiver hasn't changed.
280 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
281 __ cmp(scratch, Operand(Handle<Map>(object->map())));
282 __ b(ne, miss_label);
283
284 // Perform global security token check if needed.
285 if (object->IsJSGlobalProxy()) {
286 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
287 }
288
289 // Stub never generated for non-global objects that require access
290 // checks.
291 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
292
293 // Perform map transition for the receiver if necessary.
294 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
295 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000296 // We jump to a runtime call that extends the properties array.
ager@chromium.org5c838252010-02-19 08:53:10 +0000297 __ push(receiver_reg);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000298 __ mov(r2, Operand(Handle<Map>(transition)));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000299 __ Push(r2, r0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000300 __ TailCallExternalReference(
ager@chromium.org5c838252010-02-19 08:53:10 +0000301 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)),
302 3, 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000303 return;
304 }
305
306 if (transition != NULL) {
307 // Update the map of the object; no write barrier updating is
308 // needed because the map is never in new space.
309 __ mov(ip, Operand(Handle<Map>(transition)));
310 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
311 }
312
313 // Adjust for the number of properties stored in the object. Even in the
314 // face of a transition we can use the old map here because the size of the
315 // object and the number of in-object properties is not going to change.
316 index -= object->map()->inobject_properties();
317
318 if (index < 0) {
319 // Set the property straight into the object.
320 int offset = object->map()->instance_size() + (index * kPointerSize);
321 __ str(r0, FieldMemOperand(receiver_reg, offset));
322
323 // Skip updating write barrier if storing a smi.
324 __ tst(r0, Operand(kSmiTagMask));
325 __ b(eq, &exit);
326
327 // Update the write barrier for the array address.
328 // Pass the value being stored in the now unused name_reg.
329 __ mov(name_reg, Operand(offset));
330 __ RecordWrite(receiver_reg, name_reg, scratch);
331 } else {
332 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000333 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000334 // Get the properties array
335 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
336 __ str(r0, FieldMemOperand(scratch, offset));
337
338 // Skip updating write barrier if storing a smi.
339 __ tst(r0, Operand(kSmiTagMask));
340 __ b(eq, &exit);
341
342 // Update the write barrier for the array address.
343 // Ok to clobber receiver_reg and name_reg, since we return.
344 __ mov(name_reg, Operand(offset));
345 __ RecordWrite(scratch, name_reg, receiver_reg);
346 }
347
348 // Return the value (register r0).
349 __ bind(&exit);
350 __ Ret();
351}
352
353
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000354void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
355 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
356 Code* code = NULL;
357 if (kind == Code::LOAD_IC) {
358 code = Builtins::builtin(Builtins::LoadIC_Miss);
359 } else {
360 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
361 }
362
363 Handle<Code> ic(code);
364 __ Jump(ic, RelocInfo::CODE_TARGET);
365}
366
367
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000368static void GenerateCallFunction(MacroAssembler* masm,
369 Object* object,
370 const ParameterCount& arguments,
371 Label* miss) {
372 // ----------- S t a t e -------------
373 // -- r0: receiver
374 // -- r1: function to call
375 // -----------------------------------
376
377 // Check that the function really is a function.
378 __ BranchOnSmi(r1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000379 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000380 __ b(ne, miss);
381
382 // Patch the receiver on the stack with the global proxy if
383 // necessary.
384 if (object->IsGlobalObject()) {
385 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
386 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
387 }
388
389 // Invoke the function.
390 __ InvokeFunction(r1, arguments, JUMP_FUNCTION);
391}
392
393
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000394static void PushInterceptorArguments(MacroAssembler* masm,
395 Register receiver,
396 Register holder,
397 Register name,
398 JSObject* holder_obj) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000399 __ push(name);
400 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
401 ASSERT(!Heap::InNewSpace(interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000402 Register scratch = name;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000403 __ mov(scratch, Operand(Handle<Object>(interceptor)));
404 __ push(scratch);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000405 __ push(receiver);
406 __ push(holder);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000407 __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
408 __ push(scratch);
409}
410
411
412static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
413 Register receiver,
414 Register holder,
415 Register name,
416 JSObject* holder_obj) {
417 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
418
419 ExternalReference ref =
420 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
421 __ mov(r0, Operand(5));
422 __ mov(r1, Operand(ref));
423
424 CEntryStub stub(1);
425 __ CallStub(&stub);
426}
427
428
429class LoadInterceptorCompiler BASE_EMBEDDED {
430 public:
431 explicit LoadInterceptorCompiler(Register name) : name_(name) {}
432
433 void CompileCacheable(MacroAssembler* masm,
434 StubCompiler* stub_compiler,
435 Register receiver,
436 Register holder,
437 Register scratch1,
438 Register scratch2,
439 JSObject* holder_obj,
440 LookupResult* lookup,
441 String* name,
442 Label* miss_label) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000443 AccessorInfo* callback = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000444 bool optimize = false;
445 // So far the most popular follow ups for interceptor loads are FIELD
446 // and CALLBACKS, so inline only them, other cases may be added
447 // later.
448 if (lookup->type() == FIELD) {
449 optimize = true;
450 } else if (lookup->type() == CALLBACKS) {
451 Object* callback_object = lookup->GetCallbackObject();
452 if (callback_object->IsAccessorInfo()) {
453 callback = AccessorInfo::cast(callback_object);
454 optimize = callback->getter() != NULL;
455 }
456 }
457
458 if (!optimize) {
459 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label);
460 return;
461 }
462
463 // Note: starting a frame here makes GC aware of pointers pushed below.
464 __ EnterInternalFrame();
465
ager@chromium.org5c838252010-02-19 08:53:10 +0000466 __ push(receiver);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000467 __ Push(holder, name_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000468
469 CompileCallLoadPropertyWithInterceptor(masm,
470 receiver,
471 holder,
472 name_,
473 holder_obj);
474
475 Label interceptor_failed;
476 // Compare with no_interceptor_result_sentinel.
477 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
478 __ cmp(r0, scratch1);
479 __ b(eq, &interceptor_failed);
480 __ LeaveInternalFrame();
481 __ Ret();
482
483 __ bind(&interceptor_failed);
484 __ pop(name_);
485 __ pop(holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000486 __ pop(receiver);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000487
488 __ LeaveInternalFrame();
489
490 if (lookup->type() == FIELD) {
491 holder = stub_compiler->CheckPrototypes(holder_obj,
492 holder,
493 lookup->holder(),
494 scratch1,
495 scratch2,
496 name,
497 miss_label);
498 stub_compiler->GenerateFastPropertyLoad(masm,
499 r0,
500 holder,
501 lookup->holder(),
502 lookup->GetFieldIndex());
503 __ Ret();
504 } else {
505 ASSERT(lookup->type() == CALLBACKS);
506 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
507 ASSERT(callback != NULL);
508 ASSERT(callback->getter() != NULL);
509
510 Label cleanup;
511 __ pop(scratch2);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000512 __ Push(receiver, scratch2);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000513
514 holder = stub_compiler->CheckPrototypes(holder_obj, holder,
515 lookup->holder(), scratch1,
516 scratch2,
517 name,
518 &cleanup);
519
520 __ push(holder);
521 __ Move(holder, Handle<AccessorInfo>(callback));
522 __ push(holder);
523 __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000524 __ Push(scratch1, name_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000525
526 ExternalReference ref =
527 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000528 __ TailCallExternalReference(ref, 5, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000529
530 __ bind(&cleanup);
531 __ pop(scratch1);
532 __ pop(scratch2);
533 __ push(scratch1);
534 }
535 }
536
537
538 void CompileRegular(MacroAssembler* masm,
539 Register receiver,
540 Register holder,
541 Register scratch,
542 JSObject* holder_obj,
543 Label* miss_label) {
544 PushInterceptorArguments(masm, receiver, holder, name_, holder_obj);
545
546 ExternalReference ref = ExternalReference(
547 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000548 __ TailCallExternalReference(ref, 5, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000549 }
550
551 private:
552 Register name_;
553};
554
555
ager@chromium.org5c838252010-02-19 08:53:10 +0000556static void CompileLoadInterceptor(LoadInterceptorCompiler* compiler,
557 StubCompiler* stub_compiler,
558 MacroAssembler* masm,
559 JSObject* object,
560 JSObject* holder,
561 String* name,
562 LookupResult* lookup,
563 Register receiver,
564 Register scratch1,
565 Register scratch2,
566 Label* miss) {
567 ASSERT(holder->HasNamedInterceptor());
568 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000569
ager@chromium.org5c838252010-02-19 08:53:10 +0000570 // Check that the receiver isn't a smi.
571 __ BranchOnSmi(receiver, miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000572
ager@chromium.org5c838252010-02-19 08:53:10 +0000573 // Check that the maps haven't changed.
574 Register reg =
575 stub_compiler->CheckPrototypes(object, receiver, holder,
576 scratch1, scratch2, name, miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000577
ager@chromium.org5c838252010-02-19 08:53:10 +0000578 if (lookup->IsProperty() && lookup->IsCacheable()) {
579 compiler->CompileCacheable(masm,
580 stub_compiler,
581 receiver,
582 reg,
583 scratch1,
584 scratch2,
585 holder,
586 lookup,
587 name,
588 miss);
589 } else {
590 compiler->CompileRegular(masm,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000591 receiver,
ager@chromium.org5c838252010-02-19 08:53:10 +0000592 reg,
593 scratch2,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000594 holder,
ager@chromium.org5c838252010-02-19 08:53:10 +0000595 miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000596 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000597}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000598
599
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000600// Reserves space for the extra arguments to FastHandleApiCall in the
601// caller's frame.
602//
603// These arguments are set by CheckPrototypes and GenerateFastApiCall.
604static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
605 Register scratch) {
606 __ mov(scratch, Operand(Smi::FromInt(0)));
607 __ push(scratch);
608 __ push(scratch);
609 __ push(scratch);
610 __ push(scratch);
611}
612
613
614// Undoes the effects of ReserveSpaceForFastApiCall.
615static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
616 __ Drop(4);
617}
618
619
620// Generates call to FastHandleApiCall builtin.
621static void GenerateFastApiCall(MacroAssembler* masm,
622 const CallOptimization& optimization,
623 int argc) {
624 // Get the function and setup the context.
625 JSFunction* function = optimization.constant_function();
626 __ mov(r7, Operand(Handle<JSFunction>(function)));
627 __ ldr(cp, FieldMemOperand(r7, JSFunction::kContextOffset));
628
629 // Pass the additional arguments FastHandleApiCall expects.
630 bool info_loaded = false;
631 Object* callback = optimization.api_call_info()->callback();
632 if (Heap::InNewSpace(callback)) {
633 info_loaded = true;
634 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
635 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
636 } else {
637 __ Move(r6, Handle<Object>(callback));
638 }
639 Object* call_data = optimization.api_call_info()->data();
640 if (Heap::InNewSpace(call_data)) {
641 if (!info_loaded) {
642 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
643 }
644 __ ldr(r5, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
645 } else {
646 __ Move(r5, Handle<Object>(call_data));
647 }
648
649 __ add(sp, sp, Operand(1 * kPointerSize));
650 __ stm(ia, sp, r5.bit() | r6.bit() | r7.bit());
651 __ sub(sp, sp, Operand(1 * kPointerSize));
652
653 // Set the number of arguments.
654 __ mov(r0, Operand(argc + 4));
655
656 // Jump to the fast api call builtin (tail call).
657 Handle<Code> code = Handle<Code>(
658 Builtins::builtin(Builtins::FastHandleApiCall));
659 ParameterCount expected(0);
660 __ InvokeCode(code, expected, expected,
661 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
662}
663
664
665class CallInterceptorCompiler BASE_EMBEDDED {
666 public:
667 CallInterceptorCompiler(StubCompiler* stub_compiler,
668 const ParameterCount& arguments,
669 Register name)
670 : stub_compiler_(stub_compiler),
671 arguments_(arguments),
672 name_(name) {}
673
674 void Compile(MacroAssembler* masm,
675 JSObject* object,
676 JSObject* holder,
677 String* name,
678 LookupResult* lookup,
679 Register receiver,
680 Register scratch1,
681 Register scratch2,
682 Label* miss) {
683 ASSERT(holder->HasNamedInterceptor());
684 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
685
686 // Check that the receiver isn't a smi.
687 __ BranchOnSmi(receiver, miss);
688
689 CallOptimization optimization(lookup);
690
691 if (optimization.is_constant_call()) {
692 CompileCacheable(masm,
693 object,
694 receiver,
695 scratch1,
696 scratch2,
697 holder,
698 lookup,
699 name,
700 optimization,
701 miss);
702 } else {
703 CompileRegular(masm,
704 object,
705 receiver,
706 scratch1,
707 scratch2,
708 name,
709 holder,
710 miss);
711 }
712 }
713
714 private:
715 void CompileCacheable(MacroAssembler* masm,
716 JSObject* object,
717 Register receiver,
718 Register scratch1,
719 Register scratch2,
720 JSObject* holder_obj,
721 LookupResult* lookup,
722 String* name,
723 const CallOptimization& optimization,
724 Label* miss_label) {
725 ASSERT(optimization.is_constant_call());
726 ASSERT(!lookup->holder()->IsGlobalObject());
727
728 int depth1 = kInvalidProtoDepth;
729 int depth2 = kInvalidProtoDepth;
730 bool can_do_fast_api_call = false;
731 if (optimization.is_simple_api_call() &&
732 !lookup->holder()->IsGlobalObject()) {
733 depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj);
734 if (depth1 == kInvalidProtoDepth) {
735 depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj,
736 lookup->holder());
737 }
738 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
739 (depth2 != kInvalidProtoDepth);
740 }
741
742 __ IncrementCounter(&Counters::call_const_interceptor, 1,
743 scratch1, scratch2);
744
745 if (can_do_fast_api_call) {
746 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1,
747 scratch1, scratch2);
748 ReserveSpaceForFastApiCall(masm, scratch1);
749 }
750
751 Label miss_cleanup;
752 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
753 Register holder =
754 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, scratch1,
755 scratch2, name, depth1, miss);
756
757 Label regular_invoke;
758 LoadWithInterceptor(masm, receiver, holder, holder_obj, scratch2,
759 &regular_invoke);
760
761 // Generate code for the failed interceptor case.
762
763 // Check the lookup is still valid.
764 stub_compiler_->CheckPrototypes(holder_obj, receiver,
765 lookup->holder(), scratch1,
766 scratch2, name, depth2, miss);
767
768 if (can_do_fast_api_call) {
769 GenerateFastApiCall(masm, optimization, arguments_.immediate());
770 } else {
771 __ InvokeFunction(optimization.constant_function(), arguments_,
772 JUMP_FUNCTION);
773 }
774
775 if (can_do_fast_api_call) {
776 __ bind(&miss_cleanup);
777 FreeSpaceForFastApiCall(masm);
778 __ b(miss_label);
779 }
780
781 __ bind(&regular_invoke);
782 if (can_do_fast_api_call) {
783 FreeSpaceForFastApiCall(masm);
784 }
785 }
786
787 void CompileRegular(MacroAssembler* masm,
788 JSObject* object,
789 Register receiver,
790 Register scratch1,
791 Register scratch2,
792 String* name,
793 JSObject* holder_obj,
794 Label* miss_label) {
795 Register holder =
796 stub_compiler_->CheckPrototypes(object, receiver, holder_obj,
797 scratch1, scratch2, name,
798 miss_label);
799
800 // Call a runtime function to load the interceptor property.
801 __ EnterInternalFrame();
802 // Save the name_ register across the call.
803 __ push(name_);
804
805 PushInterceptorArguments(masm,
806 receiver,
807 holder,
808 name_,
809 holder_obj);
810
811 __ CallExternalReference(
812 ExternalReference(
813 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
814 5);
815
816 // Restore the name_ register.
817 __ pop(name_);
818 __ LeaveInternalFrame();
819 }
820
821 void LoadWithInterceptor(MacroAssembler* masm,
822 Register receiver,
823 Register holder,
824 JSObject* holder_obj,
825 Register scratch,
826 Label* interceptor_succeeded) {
827 __ EnterInternalFrame();
828 __ Push(holder, name_);
829
830 CompileCallLoadPropertyWithInterceptor(masm,
831 receiver,
832 holder,
833 name_,
834 holder_obj);
835
836 __ pop(name_); // Restore the name.
837 __ pop(receiver); // Restore the holder.
838 __ LeaveInternalFrame();
839
840 // If interceptor returns no-result sentinel, call the constant function.
841 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
842 __ cmp(r0, scratch);
843 __ b(ne, interceptor_succeeded);
844 }
845
846 StubCompiler* stub_compiler_;
847 const ParameterCount& arguments_;
848 Register name_;
849};
850
851
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000852// Generate code to check that a global property cell is empty. Create
853// the property cell at compilation time if no cell exists for the
854// property.
855static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
856 GlobalObject* global,
857 String* name,
858 Register scratch,
859 Label* miss) {
860 Object* probe = global->EnsurePropertyCell(name);
861 if (probe->IsFailure()) return probe;
862 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
863 ASSERT(cell->value()->IsTheHole());
864 __ mov(scratch, Operand(Handle<Object>(cell)));
865 __ ldr(scratch,
866 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
867 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
868 __ cmp(scratch, ip);
869 __ b(ne, miss);
870 return cell;
871}
872
873
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000874#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000875#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000876
877
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000878Register StubCompiler::CheckPrototypes(JSObject* object,
879 Register object_reg,
880 JSObject* holder,
881 Register holder_reg,
882 Register scratch,
883 String* name,
ager@chromium.org5c838252010-02-19 08:53:10 +0000884 int save_at_depth,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000885 Label* miss) {
886 // Check that the maps haven't changed.
887 Register result =
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000888 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch,
889 save_at_depth, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000890
891 // If we've skipped any global objects, it's not enough to verify
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000892 // that their maps haven't changed. We also need to check that the
893 // property cell for the property is still empty.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000894 while (object != holder) {
895 if (object->IsGlobalObject()) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000896 Object* cell = GenerateCheckPropertyCell(masm(),
897 GlobalObject::cast(object),
898 name,
899 scratch,
900 miss);
901 if (cell->IsFailure()) {
902 set_failure(Failure::cast(cell));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000903 return result;
904 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000905 }
906 object = JSObject::cast(object->GetPrototype());
907 }
908
ager@chromium.org5c838252010-02-19 08:53:10 +0000909 // Return the register containing the holder.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000910 return result;
911}
912
913
914void StubCompiler::GenerateLoadField(JSObject* object,
915 JSObject* holder,
916 Register receiver,
917 Register scratch1,
918 Register scratch2,
919 int index,
920 String* name,
921 Label* miss) {
922 // Check that the receiver isn't a smi.
923 __ tst(receiver, Operand(kSmiTagMask));
924 __ b(eq, miss);
925
926 // Check that the maps haven't changed.
927 Register reg =
928 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
929 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
930 __ Ret();
931}
932
933
934void StubCompiler::GenerateLoadConstant(JSObject* object,
935 JSObject* holder,
936 Register receiver,
937 Register scratch1,
938 Register scratch2,
939 Object* value,
940 String* name,
941 Label* miss) {
942 // Check that the receiver isn't a smi.
943 __ tst(receiver, Operand(kSmiTagMask));
944 __ b(eq, miss);
945
946 // Check that the maps haven't changed.
947 Register reg =
948 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
949
950 // Return the constant value.
951 __ mov(r0, Operand(Handle<Object>(value)));
952 __ Ret();
953}
954
955
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000956bool StubCompiler::GenerateLoadCallback(JSObject* object,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000957 JSObject* holder,
958 Register receiver,
959 Register name_reg,
960 Register scratch1,
961 Register scratch2,
962 AccessorInfo* callback,
963 String* name,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000964 Label* miss,
965 Failure** failure) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000966 // Check that the receiver isn't a smi.
967 __ tst(receiver, Operand(kSmiTagMask));
968 __ b(eq, miss);
969
970 // Check that the maps haven't changed.
971 Register reg =
972 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
973
974 // Push the arguments on the JS stack of the caller.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000975 __ push(receiver); // Receiver.
976 __ push(reg); // Holder.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000977 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000978 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000979 __ Push(ip, reg, name_reg);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000980
981 // Do tail-call to the runtime system.
982 ExternalReference load_callback_property =
983 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000984 __ TailCallExternalReference(load_callback_property, 5, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000985
986 return true;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000987}
988
989
990void StubCompiler::GenerateLoadInterceptor(JSObject* object,
991 JSObject* holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000992 LookupResult* lookup,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000993 Register receiver,
994 Register name_reg,
995 Register scratch1,
996 Register scratch2,
997 String* name,
998 Label* miss) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000999 LoadInterceptorCompiler compiler(name_reg);
1000 CompileLoadInterceptor(&compiler,
1001 this,
1002 masm(),
1003 object,
1004 holder,
1005 name,
1006 lookup,
1007 receiver,
1008 scratch1,
1009 scratch2,
1010 miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001011}
1012
1013
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001015 // ----------- S t a t e -------------
1016 // -- r1: function
1017 // -- lr: return address
1018 // -----------------------------------
1019
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001020 // Enter an internal frame.
1021 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001023 // Preserve the function.
1024 __ push(r1);
1025
1026 // Push the function on the stack as the argument to the runtime function.
1027 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001028 __ CallRuntime(Runtime::kLazyCompile, 1);
1029
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001030 // Calculate the entry point.
1031 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001032
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001033 // Restore saved function.
1034 __ pop(r1);
1035
1036 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +00001037 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038
1039 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001040 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001042 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043}
1044
1045
ager@chromium.org5c838252010-02-19 08:53:10 +00001046Object* CallStubCompiler::CompileCallField(JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001048 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001049 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001050 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001051 // -- r2 : name
1052 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054 Label miss;
1055
mads.s.ager31e71382008-08-13 09:32:07 +00001056 const int argc = arguments().immediate();
1057
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001058 // Get the receiver of the function from the stack into r0.
1059 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060 // Check that the receiver isn't a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001061 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062 __ b(eq, &miss);
1063
1064 // Do the right check and compute the holder register.
ager@chromium.org5c838252010-02-19 08:53:10 +00001065 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001066 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001067
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001068 GenerateCallFunction(masm(), object, arguments(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069
1070 // Handle call cache miss.
1071 __ bind(&miss);
1072 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001073 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074
1075 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001076 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077}
1078
1079
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001080Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1081 JSObject* holder,
1082 JSFunction* function,
1083 String* name,
1084 CheckType check) {
1085 // ----------- S t a t e -------------
1086 // -- r2 : name
1087 // -- lr : return address
1088 // -----------------------------------
1089
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001090 // If object is not an array, bail out to regular call.
1091 if (!object->IsJSArray()) {
1092 return Heap::undefined_value();
1093 }
1094
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001095 // TODO(639): faster implementation.
1096 ASSERT(check == RECEIVER_MAP_CHECK);
1097
1098 Label miss;
1099
1100 // Get the receiver from the stack
1101 const int argc = arguments().immediate();
1102 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1103
1104 // Check that the receiver isn't a smi.
1105 __ tst(r1, Operand(kSmiTagMask));
1106 __ b(eq, &miss);
1107
1108 // Check that the maps haven't changed.
1109 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1110
1111 if (object->IsGlobalObject()) {
1112 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1113 __ str(r3, MemOperand(sp, argc * kPointerSize));
1114 }
1115
1116 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1117 argc + 1,
1118 1);
1119
1120 // Handle call cache miss.
1121 __ bind(&miss);
1122 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1123 __ Jump(ic, RelocInfo::CODE_TARGET);
1124
1125 // Return the generated code.
1126 String* function_name = NULL;
1127 if (function->shared()->name()->IsString()) {
1128 function_name = String::cast(function->shared()->name());
1129 }
1130 return GetCode(CONSTANT_FUNCTION, function_name);
1131}
1132
1133
1134Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1135 JSObject* holder,
1136 JSFunction* function,
1137 String* name,
1138 CheckType check) {
1139 // ----------- S t a t e -------------
1140 // -- r2 : name
1141 // -- lr : return address
1142 // -----------------------------------
1143
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001144 // If object is not an array, bail out to regular call.
1145 if (!object->IsJSArray()) {
1146 return Heap::undefined_value();
1147 }
1148
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001149 // TODO(642): faster implementation.
1150 ASSERT(check == RECEIVER_MAP_CHECK);
1151
1152 Label miss;
1153
1154 // Get the receiver from the stack
1155 const int argc = arguments().immediate();
1156 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1157
1158 // Check that the receiver isn't a smi.
1159 __ tst(r1, Operand(kSmiTagMask));
1160 __ b(eq, &miss);
1161
1162 // Check that the maps haven't changed.
1163 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1164
1165 if (object->IsGlobalObject()) {
1166 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1167 __ str(r3, MemOperand(sp, argc * kPointerSize));
1168 }
1169
1170 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1171 argc + 1,
1172 1);
1173
1174 // Handle call cache miss.
1175 __ bind(&miss);
1176 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1177 __ Jump(ic, RelocInfo::CODE_TARGET);
1178
1179 // Return the generated code.
1180 String* function_name = NULL;
1181 if (function->shared()->name()->IsString()) {
1182 function_name = String::cast(function->shared()->name());
1183 }
1184 return GetCode(CONSTANT_FUNCTION, function_name);
1185}
1186
1187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188Object* CallStubCompiler::CompileCallConstant(Object* object,
1189 JSObject* holder,
1190 JSFunction* function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001191 String* name,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001192 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001194 // -- r2 : name
1195 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001197 SharedFunctionInfo* function_info = function->shared();
1198 if (function_info->HasCustomCallGenerator()) {
1199 CustomCallGenerator generator =
1200 ToCData<CustomCallGenerator>(function_info->function_data());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001201 Object* result = generator(this, object, holder, function, name, check);
1202 // undefined means bail out to regular compiler.
1203 if (!result->IsUndefined()) {
1204 return result;
1205 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001206 }
1207
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001208 Label miss_in_smi_check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209
mads.s.ager31e71382008-08-13 09:32:07 +00001210 // Get the receiver from the stack
1211 const int argc = arguments().immediate();
1212 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1213
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 // Check that the receiver isn't a smi.
1215 if (check != NUMBER_CHECK) {
1216 __ tst(r1, Operand(kSmiTagMask));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001217 __ b(eq, &miss_in_smi_check);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218 }
1219
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001220 // Make sure that it's okay not to patch the on stack receiver
1221 // unless we're doing a receiver map check.
1222 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1223
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001224 CallOptimization optimization(function);
1225 int depth = kInvalidProtoDepth;
1226 Label miss;
1227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 switch (check) {
1229 case RECEIVER_MAP_CHECK:
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001230 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1231
1232 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1233 depth = optimization.GetPrototypeDepthOfExpectedType(
1234 JSObject::cast(object), holder);
1235 }
1236
1237 if (depth != kInvalidProtoDepth) {
1238 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1239 ReserveSpaceForFastApiCall(masm(), r0);
1240 }
1241
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242 // Check that the maps haven't changed.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001243 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, name,
1244 depth, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001245
1246 // Patch the receiver on the stack with the global proxy if
1247 // necessary.
1248 if (object->IsGlobalObject()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001249 ASSERT(depth == kInvalidProtoDepth);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001250 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1251 __ str(r3, MemOperand(sp, argc * kPointerSize));
1252 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253 break;
1254
1255 case STRING_CHECK:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001256 if (!function->IsBuiltin()) {
1257 // Calling non-builtins with a value as receiver requires boxing.
1258 __ jmp(&miss);
1259 } else {
1260 // Check that the object is a two-byte string or a symbol.
ager@chromium.org5c838252010-02-19 08:53:10 +00001261 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001262 __ b(hs, &miss);
1263 // Check that the maps starting from the prototype haven't changed.
1264 GenerateLoadGlobalFunctionPrototype(masm(),
1265 Context::STRING_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +00001266 r0);
1267 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001268 r1, name, &miss);
1269 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 break;
1271
1272 case NUMBER_CHECK: {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001273 if (!function->IsBuiltin()) {
1274 // Calling non-builtins with a value as receiver requires boxing.
1275 __ jmp(&miss);
1276 } else {
1277 Label fast;
1278 // Check that the object is a smi or a heap number.
1279 __ tst(r1, Operand(kSmiTagMask));
1280 __ b(eq, &fast);
ager@chromium.org5c838252010-02-19 08:53:10 +00001281 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001282 __ b(ne, &miss);
1283 __ bind(&fast);
1284 // Check that the maps starting from the prototype haven't changed.
1285 GenerateLoadGlobalFunctionPrototype(masm(),
1286 Context::NUMBER_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +00001287 r0);
1288 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001289 r1, name, &miss);
1290 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 break;
1292 }
1293
1294 case BOOLEAN_CHECK: {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001295 if (!function->IsBuiltin()) {
1296 // Calling non-builtins with a value as receiver requires boxing.
1297 __ jmp(&miss);
1298 } else {
1299 Label fast;
1300 // Check that the object is a boolean.
1301 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1302 __ cmp(r1, ip);
1303 __ b(eq, &fast);
1304 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1305 __ cmp(r1, ip);
1306 __ b(ne, &miss);
1307 __ bind(&fast);
1308 // Check that the maps starting from the prototype haven't changed.
1309 GenerateLoadGlobalFunctionPrototype(masm(),
1310 Context::BOOLEAN_FUNCTION_INDEX,
ager@chromium.org5c838252010-02-19 08:53:10 +00001311 r0);
1312 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001313 r1, name, &miss);
1314 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 break;
1316 }
1317
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318 default:
1319 UNREACHABLE();
1320 }
1321
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001322 if (depth != kInvalidProtoDepth) {
1323 GenerateFastApiCall(masm(), optimization, argc);
1324 } else {
1325 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1326 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327
1328 // Handle call cache miss.
1329 __ bind(&miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001330 if (depth != kInvalidProtoDepth) {
1331 FreeSpaceForFastApiCall(masm());
1332 }
1333
1334 __ bind(&miss_in_smi_check);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001336 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337
1338 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001339 String* function_name = NULL;
1340 if (function->shared()->name()->IsString()) {
1341 function_name = String::cast(function->shared()->name());
1342 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001343 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344}
1345
1346
ager@chromium.org5c838252010-02-19 08:53:10 +00001347Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 JSObject* holder,
1349 String* name) {
1350 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001351 // -- r2 : name
1352 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001354
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001355 Label miss;
ager@chromium.org5c838252010-02-19 08:53:10 +00001356
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001357 // Get the number of arguments.
1358 const int argc = arguments().immediate();
1359
1360 LookupResult lookup;
1361 LookupPostInterceptor(holder, name, &lookup);
1362
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001363 // Get the receiver from the stack.
1364 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001365
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001366 CallInterceptorCompiler compiler(this, arguments(), r2);
1367 compiler.Compile(masm(),
1368 object,
1369 holder,
1370 name,
1371 &lookup,
1372 r1,
1373 r3,
1374 r4,
1375 &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001376
1377 // Move returned value, the function to call, to r1.
1378 __ mov(r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001379 // Restore receiver.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001380 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001381
1382 GenerateCallFunction(masm(), object, arguments(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001383
1384 // Handle call cache miss.
1385 __ bind(&miss);
1386 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001387 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388
1389 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001390 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391}
1392
1393
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001394Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1395 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001396 JSGlobalPropertyCell* cell,
1397 JSFunction* function,
1398 String* name) {
1399 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001400 // -- r2 : name
1401 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001402 // -----------------------------------
1403 Label miss;
1404
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001405 // Get the number of arguments.
1406 const int argc = arguments().immediate();
1407
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001408 // Get the receiver from the stack.
1409 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1410
1411 // If the object is the holder then we know that it's a global
1412 // object which can only happen for contextual calls. In this case,
1413 // the receiver cannot be a smi.
1414 if (object != holder) {
1415 __ tst(r0, Operand(kSmiTagMask));
1416 __ b(eq, &miss);
1417 }
1418
1419 // Check that the maps haven't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001420 CheckPrototypes(object, r0, holder, r3, r1, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001421
1422 // Get the value from the cell.
1423 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1424 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1425
1426 // Check that the cell contains the same function.
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001427 if (Heap::InNewSpace(function)) {
1428 // We can't embed a pointer to a function in new space so we have
1429 // to verify that the shared function info is unchanged. This has
1430 // the nice side effect that multiple closures based on the same
1431 // function can all use this call IC. Before we load through the
1432 // function, we have to verify that it still is a function.
1433 __ tst(r1, Operand(kSmiTagMask));
1434 __ b(eq, &miss);
1435 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1436 __ b(ne, &miss);
1437
1438 // Check the shared function info. Make sure it hasn't changed.
1439 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
ager@chromium.org5c838252010-02-19 08:53:10 +00001440 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1441 __ cmp(r4, r3);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001442 __ b(ne, &miss);
1443 } else {
1444 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1445 __ b(ne, &miss);
1446 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001447
1448 // Patch the receiver on the stack with the global proxy if
1449 // necessary.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001450 if (object->IsGlobalObject()) {
1451 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1452 __ str(r3, MemOperand(sp, argc * kPointerSize));
1453 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001454
1455 // Setup the context (function already in r1).
1456 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1457
1458 // Jump to the cached code (tail call).
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001459 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001460 ASSERT(function->is_compiled());
1461 Handle<Code> code(function->code());
1462 ParameterCount expected(function->shared()->formal_parameter_count());
1463 __ InvokeCode(code, expected, arguments(),
1464 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1465
1466 // Handle call cache miss.
1467 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001468 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
1469 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1470 __ Jump(ic, RelocInfo::CODE_TARGET);
1471
1472 // Return the generated code.
1473 return GetCode(NORMAL, name);
1474}
1475
1476
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1478 int index,
1479 Map* transition,
1480 String* name) {
1481 // ----------- S t a t e -------------
1482 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001483 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484 // -- r2 : name
1485 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001487 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001488
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001489 GenerateStoreField(masm(),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001490 object,
1491 index,
1492 transition,
ager@chromium.org5c838252010-02-19 08:53:10 +00001493 r1, r2, r3,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001494 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001495 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001497 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001498
1499 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001500 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501}
1502
1503
1504Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1505 AccessorInfo* callback,
1506 String* name) {
1507 // ----------- S t a t e -------------
1508 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001509 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510 // -- r2 : name
1511 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001512 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001513 Label miss;
1514
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 // Check that the object isn't a smi.
ager@chromium.org5c838252010-02-19 08:53:10 +00001516 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517 __ b(eq, &miss);
1518
1519 // Check that the map of the object hasn't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001520 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1521 __ cmp(r3, Operand(Handle<Map>(object->map())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001522 __ b(ne, &miss);
1523
1524 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001525 if (object->IsJSGlobalProxy()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001526 __ CheckAccessGlobalProxy(r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 }
1528
1529 // Stub never generated for non-global objects that require access
1530 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001531 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001532
ager@chromium.org5c838252010-02-19 08:53:10 +00001533 __ push(r1); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001535 __ Push(ip, r2, r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536
mads.s.ager31e71382008-08-13 09:32:07 +00001537 // Do tail-call to the runtime system.
1538 ExternalReference store_callback_property =
1539 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001540 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001541
1542 // Handle store cache miss.
1543 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001545 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546
1547 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001548 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549}
1550
1551
1552Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1553 String* name) {
1554 // ----------- S t a t e -------------
1555 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001556 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001557 // -- r2 : name
1558 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 Label miss;
1561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 // Check that the object isn't a smi.
ager@chromium.org5c838252010-02-19 08:53:10 +00001563 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 __ b(eq, &miss);
1565
1566 // Check that the map of the object hasn't changed.
ager@chromium.org5c838252010-02-19 08:53:10 +00001567 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1568 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 __ b(ne, &miss);
1570
1571 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001572 if (receiver->IsJSGlobalProxy()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001573 __ CheckAccessGlobalProxy(r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 }
1575
ager@chromium.org5c838252010-02-19 08:53:10 +00001576 // Stub is never generated for non-global objects that require access
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001578 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001579
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001580 __ Push(r1, r2, r0); // Receiver, name, value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581
mads.s.ager31e71382008-08-13 09:32:07 +00001582 // Do tail-call to the runtime system.
1583 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001585 __ TailCallExternalReference(store_ic_property, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586
1587 // Handle store cache miss.
1588 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001590 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591
1592 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001593 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594}
1595
1596
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001597Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1598 JSGlobalPropertyCell* cell,
1599 String* name) {
1600 // ----------- S t a t e -------------
1601 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001602 // -- r1 : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001603 // -- r2 : name
1604 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001605 // -----------------------------------
1606 Label miss;
1607
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001608 // Check that the map of the global has not changed.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001609 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1610 __ cmp(r3, Operand(Handle<Map>(object->map())));
1611 __ b(ne, &miss);
1612
1613 // Store the value in the cell.
1614 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1615 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001616
ager@chromium.org5c838252010-02-19 08:53:10 +00001617 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001618 __ Ret();
1619
1620 // Handle store cache miss.
1621 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001622 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001623 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1624 __ Jump(ic, RelocInfo::CODE_TARGET);
1625
1626 // Return the generated code.
1627 return GetCode(NORMAL, name);
1628}
1629
1630
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001631Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1632 JSObject* object,
1633 JSObject* last) {
1634 // ----------- S t a t e -------------
1635 // -- r2 : name
1636 // -- lr : return address
1637 // -- [sp] : receiver
1638 // -----------------------------------
1639 Label miss;
1640
1641 // Load receiver.
1642 __ ldr(r0, MemOperand(sp, 0));
1643
1644 // Check that receiver is not a smi.
1645 __ tst(r0, Operand(kSmiTagMask));
1646 __ b(eq, &miss);
1647
1648 // Check the maps of the full prototype chain.
1649 CheckPrototypes(object, r0, last, r3, r1, name, &miss);
1650
1651 // If the last object in the prototype chain is a global object,
1652 // check that the global property cell is empty.
1653 if (last->IsGlobalObject()) {
1654 Object* cell = GenerateCheckPropertyCell(masm(),
1655 GlobalObject::cast(last),
1656 name,
1657 r1,
1658 &miss);
1659 if (cell->IsFailure()) return cell;
1660 }
1661
1662 // Return undefined if maps of the full prototype chain are still the
1663 // same and no global property with this name contains a value.
1664 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1665 __ Ret();
1666
1667 __ bind(&miss);
1668 GenerateLoadMiss(masm(), Code::LOAD_IC);
1669
1670 // Return the generated code.
1671 return GetCode(NONEXISTENT, Heap::empty_string());
1672}
1673
1674
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1676 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001677 int index,
1678 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001679 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 // -- r2 : name
1681 // -- lr : return address
1682 // -- [sp] : receiver
1683 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001684 Label miss;
1685
mads.s.ager31e71382008-08-13 09:32:07 +00001686 __ ldr(r0, MemOperand(sp, 0));
1687
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001688 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001690 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001691
1692 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001693 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001694}
1695
1696
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001697Object* LoadStubCompiler::CompileLoadCallback(String* name,
1698 JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699 JSObject* holder,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001700 AccessorInfo* callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001701 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702 // -- r2 : name
1703 // -- lr : return address
1704 // -- [sp] : receiver
1705 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706 Label miss;
1707
mads.s.ager31e71382008-08-13 09:32:07 +00001708 __ ldr(r0, MemOperand(sp, 0));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001709 Failure* failure = Failure::InternalError();
1710 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
1711 callback, name, &miss, &failure);
1712 if (!success) return failure;
1713
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001714 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001715 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001716
1717 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001718 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719}
1720
1721
1722Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1723 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001724 Object* value,
1725 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001726 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727 // -- r2 : name
1728 // -- lr : return address
1729 // -- [sp] : receiver
1730 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001731 Label miss;
1732
mads.s.ager31e71382008-08-13 09:32:07 +00001733 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001734
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001735 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001736 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001737 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001738
1739 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001740 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741}
1742
1743
1744Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1745 JSObject* holder,
1746 String* name) {
1747 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001748 // -- r2 : name
1749 // -- lr : return address
1750 // -- [sp] : receiver
1751 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001752 Label miss;
1753
mads.s.ager31e71382008-08-13 09:32:07 +00001754 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001755
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001756 LookupResult lookup;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001757 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001758 GenerateLoadInterceptor(object,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001759 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001760 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001761 r0,
1762 r2,
1763 r3,
1764 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001765 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001766 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001767 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001768 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001769
1770 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001771 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772}
1773
1774
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001775Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1776 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001777 JSGlobalPropertyCell* cell,
1778 String* name,
1779 bool is_dont_delete) {
1780 // ----------- S t a t e -------------
1781 // -- r2 : name
1782 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001783 // -- r0 : receiver
1784 // -- sp[0] : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001785 // -----------------------------------
1786 Label miss;
1787
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001788 // If the object is the holder then we know that it's a global
1789 // object which can only happen for contextual calls. In this case,
1790 // the receiver cannot be a smi.
1791 if (object != holder) {
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001792 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001793 __ b(eq, &miss);
1794 }
1795
1796 // Check that the map of the global has not changed.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001797 CheckPrototypes(object, r0, holder, r3, r4, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001798
1799 // Get the value from the cell.
1800 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001801 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001802
1803 // Check for deleted property if property can actually be deleted.
1804 if (!is_dont_delete) {
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001805 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001806 __ cmp(r4, ip);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001807 __ b(eq, &miss);
1808 }
1809
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001810 __ mov(r0, r4);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001811 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001812 __ Ret();
1813
1814 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001815 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1816 GenerateLoadMiss(masm(), Code::LOAD_IC);
1817
1818 // Return the generated code.
1819 return GetCode(NORMAL, name);
1820}
1821
1822
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001823Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1824 JSObject* receiver,
1825 JSObject* holder,
1826 int index) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001827 // ----------- S t a t e -------------
1828 // -- lr : return address
1829 // -- sp[0] : key
1830 // -- sp[4] : receiver
1831 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001832 Label miss;
1833
1834 __ ldr(r2, MemOperand(sp, 0));
1835 __ ldr(r0, MemOperand(sp, kPointerSize));
1836
1837 __ cmp(r2, Operand(Handle<String>(name)));
1838 __ b(ne, &miss);
1839
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001840 GenerateLoadField(receiver, holder, r0, r3, r1, index, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001841 __ bind(&miss);
1842 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1843
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001844 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001845}
1846
1847
1848Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1849 JSObject* receiver,
1850 JSObject* holder,
1851 AccessorInfo* callback) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001852 // ----------- S t a t e -------------
1853 // -- lr : return address
1854 // -- sp[0] : key
1855 // -- sp[4] : receiver
1856 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001857 Label miss;
1858
1859 __ ldr(r2, MemOperand(sp, 0));
1860 __ ldr(r0, MemOperand(sp, kPointerSize));
1861
1862 __ cmp(r2, Operand(Handle<String>(name)));
1863 __ b(ne, &miss);
1864
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001865 Failure* failure = Failure::InternalError();
1866 bool success = GenerateLoadCallback(receiver, holder, r0, r2, r3, r1,
1867 callback, name, &miss, &failure);
1868 if (!success) return failure;
1869
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001870 __ bind(&miss);
1871 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1872
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001873 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001874}
1875
1876
1877Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1878 JSObject* receiver,
1879 JSObject* holder,
1880 Object* value) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001881 // ----------- S t a t e -------------
1882 // -- lr : return address
1883 // -- sp[0] : key
1884 // -- sp[4] : receiver
1885 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001886 Label miss;
1887
1888 // Check the key is the cached one
1889 __ ldr(r2, MemOperand(sp, 0));
1890 __ ldr(r0, MemOperand(sp, kPointerSize));
1891
1892 __ cmp(r2, Operand(Handle<String>(name)));
1893 __ b(ne, &miss);
1894
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001895 GenerateLoadConstant(receiver, holder, r0, r3, r1, value, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001896 __ bind(&miss);
1897 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1898
1899 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001900 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001901}
1902
1903
1904Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1905 JSObject* holder,
1906 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001907 // ----------- S t a t e -------------
1908 // -- lr : return address
1909 // -- sp[0] : key
1910 // -- sp[4] : receiver
1911 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001912 Label miss;
1913
1914 // Check the key is the cached one
1915 __ ldr(r2, MemOperand(sp, 0));
1916 __ ldr(r0, MemOperand(sp, kPointerSize));
1917
1918 __ cmp(r2, Operand(Handle<String>(name)));
1919 __ b(ne, &miss);
1920
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001921 LookupResult lookup;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001922 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001923 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001924 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001925 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001926 r0,
1927 r2,
1928 r3,
1929 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001930 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001931 &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001932 __ bind(&miss);
1933 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1934
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001935 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001936}
1937
1938
1939Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001940 // ----------- S t a t e -------------
1941 // -- lr : return address
1942 // -- sp[0] : key
1943 // -- sp[4] : receiver
1944 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001945 Label miss;
1946
1947 // Check the key is the cached one
1948 __ ldr(r2, MemOperand(sp, 0));
1949 __ ldr(r0, MemOperand(sp, kPointerSize));
1950
1951 __ cmp(r2, Operand(Handle<String>(name)));
1952 __ b(ne, &miss);
1953
1954 GenerateLoadArrayLength(masm(), r0, r3, &miss);
1955 __ bind(&miss);
1956 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1957
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001958 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959}
1960
1961
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001962Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001963 // ----------- S t a t e -------------
1964 // -- lr : return address
1965 // -- sp[0] : key
1966 // -- sp[4] : receiver
1967 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001968 Label miss;
1969 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1970
1971 __ ldr(r2, MemOperand(sp));
1972 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver
1973
1974 __ cmp(r2, Operand(Handle<String>(name)));
1975 __ b(ne, &miss);
1976
ager@chromium.org5c838252010-02-19 08:53:10 +00001977 GenerateLoadStringLength(masm(), r0, r1, r3, &miss);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001978 __ bind(&miss);
1979 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1980
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001981 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1982
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001983 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984}
1985
1986
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001987// TODO(1224671): implement the fast case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001988Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001989 // ----------- S t a t e -------------
1990 // -- lr : return address
1991 // -- sp[0] : key
1992 // -- sp[4] : receiver
1993 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001994 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1995
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001996 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997}
1998
1999
2000Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
2001 int index,
2002 Map* transition,
2003 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002004 // ----------- S t a t e -------------
2005 // -- r0 : value
2006 // -- r2 : name
2007 // -- lr : return address
2008 // -- [sp] : receiver
2009 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002010 Label miss;
2011
2012 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
2013
2014 // Check that the name has not changed.
2015 __ cmp(r2, Operand(Handle<String>(name)));
2016 __ b(ne, &miss);
2017
2018 // Load receiver from the stack.
2019 __ ldr(r3, MemOperand(sp));
2020 // r1 is used as scratch register, r3 and r2 might be clobbered.
2021 GenerateStoreField(masm(),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002022 object,
2023 index,
2024 transition,
2025 r3, r2, r1,
2026 &miss);
2027 __ bind(&miss);
2028
2029 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
2030 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002031 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
2032 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002033
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002034 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002035 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002036}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002037
2038
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002039Object* ConstructStubCompiler::CompileConstructStub(
2040 SharedFunctionInfo* shared) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00002041 // ----------- S t a t e -------------
2042 // -- r0 : argc
2043 // -- r1 : constructor
2044 // -- lr : return address
2045 // -- [sp] : last argument
2046 // -----------------------------------
2047 Label generic_stub_call;
2048
2049 // Use r7 for holding undefined which is used in several places below.
2050 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2051
2052#ifdef ENABLE_DEBUGGER_SUPPORT
2053 // Check to see whether there are any break points in the function code. If
2054 // there are jump to the generic constructor stub which calls the actual
2055 // code for the function thereby hitting the break points.
2056 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2057 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2058 __ cmp(r2, r7);
2059 __ b(ne, &generic_stub_call);
2060#endif
2061
2062 // Load the initial map and verify that it is in fact a map.
2063 // r1: constructor function
2064 // r7: undefined
2065 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2066 __ tst(r2, Operand(kSmiTagMask));
2067 __ b(eq, &generic_stub_call);
2068 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2069 __ b(ne, &generic_stub_call);
2070
2071#ifdef DEBUG
2072 // Cannot construct functions this way.
2073 // r0: argc
2074 // r1: constructor function
2075 // r2: initial map
2076 // r7: undefined
2077 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2078 __ Check(ne, "Function constructed by construct stub.");
2079#endif
2080
2081 // Now allocate the JSObject in new space.
2082 // r0: argc
2083 // r1: constructor function
2084 // r2: initial map
2085 // r7: undefined
2086 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002087 __ AllocateInNewSpace(r3,
2088 r4,
2089 r5,
2090 r6,
2091 &generic_stub_call,
2092 NO_ALLOCATION_FLAGS);
ager@chromium.orga1645e22009-09-09 19:27:10 +00002093
2094 // Allocated the JSObject, now initialize the fields. Map is set to initial
2095 // map and properties and elements are set to empty fixed array.
2096 // r0: argc
2097 // r1: constructor function
2098 // r2: initial map
2099 // r3: object size (in words)
2100 // r4: JSObject (not tagged)
2101 // r7: undefined
2102 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2103 __ mov(r5, r4);
2104 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2105 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2106 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2107 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2108 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2109 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2110
2111 // Calculate the location of the first argument. The stack contains only the
2112 // argc arguments.
2113 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2114
2115 // Fill all the in-object properties with undefined.
2116 // r0: argc
2117 // r1: first argument
2118 // r3: object size (in words)
2119 // r4: JSObject (not tagged)
2120 // r5: First in-object property of JSObject (not tagged)
2121 // r7: undefined
2122 // Fill the initialized properties with a constant value or a passed argument
2123 // depending on the this.x = ...; assignment in the function.
2124 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2125 if (shared->IsThisPropertyAssignmentArgument(i)) {
2126 Label not_passed, next;
2127 // Check if the argument assigned to the property is actually passed.
2128 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2129 __ cmp(r0, Operand(arg_number));
2130 __ b(le, &not_passed);
2131 // Argument passed - find it on the stack.
2132 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2133 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2134 __ b(&next);
2135 __ bind(&not_passed);
2136 // Set the property to undefined.
2137 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2138 __ bind(&next);
2139 } else {
2140 // Set the property to the constant value.
2141 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2142 __ mov(r2, Operand(constant));
2143 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2144 }
2145 }
2146
2147 // Fill the unused in-object property fields with undefined.
2148 for (int i = shared->this_property_assignments_count();
2149 i < shared->CalculateInObjectProperties();
2150 i++) {
2151 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2152 }
2153
2154 // r0: argc
2155 // r4: JSObject (not tagged)
2156 // Move argc to r1 and the JSObject to return to r0 and tag it.
2157 __ mov(r1, r0);
2158 __ mov(r0, r4);
2159 __ orr(r0, r0, Operand(kHeapObjectTag));
2160
2161 // r0: JSObject
2162 // r1: argc
2163 // Remove caller arguments and receiver from the stack and return.
2164 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2165 __ add(sp, sp, Operand(kPointerSize));
2166 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2167 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2168 __ Jump(lr);
2169
2170 // Jump to the generic stub in case the specialized code cannot handle the
2171 // construction.
2172 __ bind(&generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002173 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2174 Handle<Code> generic_construct_stub(code);
2175 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2176
2177 // Return the generated code.
2178 return GetCode();
2179}
2180
2181
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002182#undef __
2183
2184} } // namespace v8::internal