blob: 877354ccae478a851fb12828cf6b44392344da5b [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// 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
34namespace v8 {
35namespace internal {
36
37#define __ ACCESS_MASM(masm)
38
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));
Steve Block6ded16b2010-05-10 14:33:55 +010056 __ cmp(name, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +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));
65 __ and_(offset, offset, Operand(~Code::kFlagsNotUsedInLookup));
66 __ 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,
88 Register scratch,
89 Register extra) {
90 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.
Steve Blockd0582a62009-12-15 09:54:21 +0000108 __ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000109 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
110 __ 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
153// 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.
167 int offset = index * kPointerSize + FixedArray::kHeaderSize;
168 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
169 __ ldr(dst, FieldMemOperand(dst, offset));
170 }
171}
172
173
174void 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.
183 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
184 __ 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
Andrei Popescu402d9372010-02-26 13:31:12 +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.
Steve Blocka7e24c12009-10-30 11:49:00 +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
215// 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.
Andrei Popescu402d9372010-02-26 13:31:12 +0000219void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
220 Register receiver,
221 Register scratch1,
222 Register scratch2,
223 Label* miss) {
224 Label check_wrapper;
Steve Blocka7e24c12009-10-30 11:49:00 +0000225
Steve Blocka7e24c12009-10-30 11:49:00 +0000226 // Check if the object is a string leaving the instance type in the
227 // scratch1 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000228 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
Steve Blocka7e24c12009-10-30 11:49:00 +0000229
230 // Load length directly from the string.
Steve Blocka7e24c12009-10-30 11:49:00 +0000231 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 __ Ret();
233
234 // Check if the object is a JSValue wrapper.
235 __ bind(&check_wrapper);
236 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
237 __ b(ne, miss);
238
Andrei Popescu402d9372010-02-26 13:31:12 +0000239 // Unwrap the value and check if the wrapped value is a string.
240 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
241 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
242 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
Andrei Popescu402d9372010-02-26 13:31:12 +0000243 __ Ret();
Steve Blocka7e24c12009-10-30 11:49:00 +0000244}
245
246
247void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
248 Register receiver,
249 Register scratch1,
250 Register scratch2,
251 Label* miss_label) {
252 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
253 __ mov(r0, scratch1);
254 __ Ret();
255}
256
257
258// Generate StoreField code, value is passed in r0 register.
Andrei Popescu402d9372010-02-26 13:31:12 +0000259// When leaving generated code after success, the receiver_reg and name_reg
260// may be clobbered. Upon branch to miss_label, the receiver and name
261// registers have their original values.
Steve Blocka7e24c12009-10-30 11:49:00 +0000262void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Steve Blocka7e24c12009-10-30 11:49:00 +0000263 JSObject* object,
264 int index,
265 Map* transition,
266 Register receiver_reg,
267 Register name_reg,
268 Register scratch,
269 Label* miss_label) {
270 // r0 : value
271 Label exit;
272
273 // Check that the receiver isn't a smi.
274 __ tst(receiver_reg, Operand(kSmiTagMask));
275 __ b(eq, miss_label);
276
277 // Check that the map of the receiver hasn't changed.
278 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
279 __ cmp(scratch, Operand(Handle<Map>(object->map())));
280 __ b(ne, miss_label);
281
282 // Perform global security token check if needed.
283 if (object->IsJSGlobalProxy()) {
284 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
285 }
286
287 // Stub never generated for non-global objects that require access
288 // checks.
289 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
290
291 // Perform map transition for the receiver if necessary.
292 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
293 // The properties must be extended before we can store the value.
294 // We jump to a runtime call that extends the properties array.
Andrei Popescu402d9372010-02-26 13:31:12 +0000295 __ push(receiver_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000296 __ mov(r2, Operand(Handle<Map>(transition)));
Steve Block6ded16b2010-05-10 14:33:55 +0100297 __ Push(r2, r0);
298 __ TailCallExternalReference(
Andrei Popescu402d9372010-02-26 13:31:12 +0000299 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)),
300 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000301 return;
302 }
303
304 if (transition != NULL) {
305 // Update the map of the object; no write barrier updating is
306 // needed because the map is never in new space.
307 __ mov(ip, Operand(Handle<Map>(transition)));
308 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
309 }
310
311 // Adjust for the number of properties stored in the object. Even in the
312 // face of a transition we can use the old map here because the size of the
313 // object and the number of in-object properties is not going to change.
314 index -= object->map()->inobject_properties();
315
316 if (index < 0) {
317 // Set the property straight into the object.
318 int offset = object->map()->instance_size() + (index * kPointerSize);
319 __ str(r0, FieldMemOperand(receiver_reg, offset));
320
321 // Skip updating write barrier if storing a smi.
322 __ tst(r0, Operand(kSmiTagMask));
323 __ b(eq, &exit);
324
325 // Update the write barrier for the array address.
326 // Pass the value being stored in the now unused name_reg.
327 __ mov(name_reg, Operand(offset));
328 __ RecordWrite(receiver_reg, name_reg, scratch);
329 } else {
330 // Write to the properties array.
331 int offset = index * kPointerSize + FixedArray::kHeaderSize;
332 // Get the properties array
333 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
334 __ str(r0, FieldMemOperand(scratch, offset));
335
336 // Skip updating write barrier if storing a smi.
337 __ tst(r0, Operand(kSmiTagMask));
338 __ b(eq, &exit);
339
340 // Update the write barrier for the array address.
341 // Ok to clobber receiver_reg and name_reg, since we return.
342 __ mov(name_reg, Operand(offset));
343 __ RecordWrite(scratch, name_reg, receiver_reg);
344 }
345
346 // Return the value (register r0).
347 __ bind(&exit);
348 __ Ret();
349}
350
351
352void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
353 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
354 Code* code = NULL;
355 if (kind == Code::LOAD_IC) {
356 code = Builtins::builtin(Builtins::LoadIC_Miss);
357 } else {
358 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
359 }
360
361 Handle<Code> ic(code);
362 __ Jump(ic, RelocInfo::CODE_TARGET);
363}
364
365
Leon Clarke4515c472010-02-03 11:58:03 +0000366static void GenerateCallFunction(MacroAssembler* masm,
367 Object* object,
368 const ParameterCount& arguments,
369 Label* miss) {
370 // ----------- S t a t e -------------
371 // -- r0: receiver
372 // -- r1: function to call
373 // -----------------------------------
374
375 // Check that the function really is a function.
376 __ BranchOnSmi(r1, miss);
Andrei Popescu402d9372010-02-26 13:31:12 +0000377 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
Leon Clarke4515c472010-02-03 11:58:03 +0000378 __ b(ne, miss);
379
380 // Patch the receiver on the stack with the global proxy if
381 // necessary.
382 if (object->IsGlobalObject()) {
383 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
384 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
385 }
386
387 // Invoke the function.
388 __ InvokeFunction(r1, arguments, JUMP_FUNCTION);
389}
390
391
Leon Clarke4515c472010-02-03 11:58:03 +0000392static void PushInterceptorArguments(MacroAssembler* masm,
393 Register receiver,
394 Register holder,
395 Register name,
396 JSObject* holder_obj) {
Leon Clarke4515c472010-02-03 11:58:03 +0000397 __ push(name);
398 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
399 ASSERT(!Heap::InNewSpace(interceptor));
Steve Block6ded16b2010-05-10 14:33:55 +0100400 Register scratch = name;
Leon Clarke4515c472010-02-03 11:58:03 +0000401 __ mov(scratch, Operand(Handle<Object>(interceptor)));
402 __ push(scratch);
Steve Block6ded16b2010-05-10 14:33:55 +0100403 __ push(receiver);
404 __ push(holder);
Leon Clarke4515c472010-02-03 11:58:03 +0000405 __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
406 __ push(scratch);
407}
408
409
410static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
411 Register receiver,
412 Register holder,
413 Register name,
414 JSObject* holder_obj) {
415 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
416
417 ExternalReference ref =
418 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
419 __ mov(r0, Operand(5));
420 __ mov(r1, Operand(ref));
421
422 CEntryStub stub(1);
423 __ CallStub(&stub);
424}
425
426
427class LoadInterceptorCompiler BASE_EMBEDDED {
428 public:
429 explicit LoadInterceptorCompiler(Register name) : name_(name) {}
430
431 void CompileCacheable(MacroAssembler* masm,
432 StubCompiler* stub_compiler,
433 Register receiver,
434 Register holder,
435 Register scratch1,
436 Register scratch2,
437 JSObject* holder_obj,
438 LookupResult* lookup,
439 String* name,
440 Label* miss_label) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000441 AccessorInfo* callback = NULL;
Leon Clarke4515c472010-02-03 11:58:03 +0000442 bool optimize = false;
443 // So far the most popular follow ups for interceptor loads are FIELD
444 // and CALLBACKS, so inline only them, other cases may be added
445 // later.
446 if (lookup->type() == FIELD) {
447 optimize = true;
448 } else if (lookup->type() == CALLBACKS) {
449 Object* callback_object = lookup->GetCallbackObject();
450 if (callback_object->IsAccessorInfo()) {
451 callback = AccessorInfo::cast(callback_object);
452 optimize = callback->getter() != NULL;
453 }
454 }
455
456 if (!optimize) {
457 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label);
458 return;
459 }
460
461 // Note: starting a frame here makes GC aware of pointers pushed below.
462 __ EnterInternalFrame();
463
Andrei Popescu402d9372010-02-26 13:31:12 +0000464 __ push(receiver);
Steve Block6ded16b2010-05-10 14:33:55 +0100465 __ Push(holder, name_);
Leon Clarke4515c472010-02-03 11:58:03 +0000466
467 CompileCallLoadPropertyWithInterceptor(masm,
468 receiver,
469 holder,
470 name_,
471 holder_obj);
472
473 Label interceptor_failed;
474 // Compare with no_interceptor_result_sentinel.
475 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
476 __ cmp(r0, scratch1);
477 __ b(eq, &interceptor_failed);
478 __ LeaveInternalFrame();
479 __ Ret();
480
481 __ bind(&interceptor_failed);
482 __ pop(name_);
483 __ pop(holder);
Andrei Popescu402d9372010-02-26 13:31:12 +0000484 __ pop(receiver);
Leon Clarke4515c472010-02-03 11:58:03 +0000485
486 __ LeaveInternalFrame();
487
488 if (lookup->type() == FIELD) {
489 holder = stub_compiler->CheckPrototypes(holder_obj,
490 holder,
491 lookup->holder(),
492 scratch1,
493 scratch2,
494 name,
495 miss_label);
496 stub_compiler->GenerateFastPropertyLoad(masm,
497 r0,
498 holder,
499 lookup->holder(),
500 lookup->GetFieldIndex());
501 __ Ret();
502 } else {
503 ASSERT(lookup->type() == CALLBACKS);
504 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
505 ASSERT(callback != NULL);
506 ASSERT(callback->getter() != NULL);
507
508 Label cleanup;
509 __ pop(scratch2);
Steve Block6ded16b2010-05-10 14:33:55 +0100510 __ Push(receiver, scratch2);
Leon Clarke4515c472010-02-03 11:58:03 +0000511
512 holder = stub_compiler->CheckPrototypes(holder_obj, holder,
513 lookup->holder(), scratch1,
514 scratch2,
515 name,
516 &cleanup);
517
518 __ push(holder);
519 __ Move(holder, Handle<AccessorInfo>(callback));
520 __ push(holder);
521 __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset));
Steve Block6ded16b2010-05-10 14:33:55 +0100522 __ Push(scratch1, name_);
Leon Clarke4515c472010-02-03 11:58:03 +0000523
524 ExternalReference ref =
525 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +0100526 __ TailCallExternalReference(ref, 5, 1);
Leon Clarke4515c472010-02-03 11:58:03 +0000527
528 __ bind(&cleanup);
529 __ pop(scratch1);
530 __ pop(scratch2);
531 __ push(scratch1);
532 }
533 }
534
535
536 void CompileRegular(MacroAssembler* masm,
537 Register receiver,
538 Register holder,
539 Register scratch,
540 JSObject* holder_obj,
541 Label* miss_label) {
542 PushInterceptorArguments(masm, receiver, holder, name_, holder_obj);
543
544 ExternalReference ref = ExternalReference(
545 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
Steve Block6ded16b2010-05-10 14:33:55 +0100546 __ TailCallExternalReference(ref, 5, 1);
Leon Clarke4515c472010-02-03 11:58:03 +0000547 }
548
549 private:
550 Register name_;
551};
552
553
Andrei Popescu402d9372010-02-26 13:31:12 +0000554static void CompileLoadInterceptor(LoadInterceptorCompiler* compiler,
555 StubCompiler* stub_compiler,
556 MacroAssembler* masm,
557 JSObject* object,
558 JSObject* holder,
559 String* name,
560 LookupResult* lookup,
561 Register receiver,
562 Register scratch1,
563 Register scratch2,
564 Label* miss) {
565 ASSERT(holder->HasNamedInterceptor());
566 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
Leon Clarke4515c472010-02-03 11:58:03 +0000567
Andrei Popescu402d9372010-02-26 13:31:12 +0000568 // Check that the receiver isn't a smi.
569 __ BranchOnSmi(receiver, miss);
Leon Clarke4515c472010-02-03 11:58:03 +0000570
Andrei Popescu402d9372010-02-26 13:31:12 +0000571 // Check that the maps haven't changed.
572 Register reg =
573 stub_compiler->CheckPrototypes(object, receiver, holder,
574 scratch1, scratch2, name, miss);
Leon Clarke4515c472010-02-03 11:58:03 +0000575
Andrei Popescu402d9372010-02-26 13:31:12 +0000576 if (lookup->IsProperty() && lookup->IsCacheable()) {
577 compiler->CompileCacheable(masm,
578 stub_compiler,
579 receiver,
580 reg,
581 scratch1,
582 scratch2,
583 holder,
584 lookup,
585 name,
586 miss);
587 } else {
588 compiler->CompileRegular(masm,
Leon Clarke4515c472010-02-03 11:58:03 +0000589 receiver,
Andrei Popescu402d9372010-02-26 13:31:12 +0000590 reg,
591 scratch2,
Leon Clarke4515c472010-02-03 11:58:03 +0000592 holder,
Andrei Popescu402d9372010-02-26 13:31:12 +0000593 miss);
Leon Clarke4515c472010-02-03 11:58:03 +0000594 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000595}
Leon Clarke4515c472010-02-03 11:58:03 +0000596
597
Steve Block6ded16b2010-05-10 14:33:55 +0100598// Reserves space for the extra arguments to FastHandleApiCall in the
599// caller's frame.
600//
601// These arguments are set by CheckPrototypes and GenerateFastApiCall.
602static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
603 Register scratch) {
604 __ mov(scratch, Operand(Smi::FromInt(0)));
605 __ push(scratch);
606 __ push(scratch);
607 __ push(scratch);
608 __ push(scratch);
609}
610
611
612// Undoes the effects of ReserveSpaceForFastApiCall.
613static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
614 __ Drop(4);
615}
616
617
618// Generates call to FastHandleApiCall builtin.
619static void GenerateFastApiCall(MacroAssembler* masm,
620 const CallOptimization& optimization,
621 int argc) {
622 // Get the function and setup the context.
623 JSFunction* function = optimization.constant_function();
624 __ mov(r7, Operand(Handle<JSFunction>(function)));
625 __ ldr(cp, FieldMemOperand(r7, JSFunction::kContextOffset));
626
627 // Pass the additional arguments FastHandleApiCall expects.
628 bool info_loaded = false;
629 Object* callback = optimization.api_call_info()->callback();
630 if (Heap::InNewSpace(callback)) {
631 info_loaded = true;
632 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
633 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
634 } else {
635 __ Move(r6, Handle<Object>(callback));
636 }
637 Object* call_data = optimization.api_call_info()->data();
638 if (Heap::InNewSpace(call_data)) {
639 if (!info_loaded) {
640 __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
641 }
642 __ ldr(r5, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
643 } else {
644 __ Move(r5, Handle<Object>(call_data));
645 }
646
647 __ add(sp, sp, Operand(1 * kPointerSize));
648 __ stm(ia, sp, r5.bit() | r6.bit() | r7.bit());
649 __ sub(sp, sp, Operand(1 * kPointerSize));
650
651 // Set the number of arguments.
652 __ mov(r0, Operand(argc + 4));
653
654 // Jump to the fast api call builtin (tail call).
655 Handle<Code> code = Handle<Code>(
656 Builtins::builtin(Builtins::FastHandleApiCall));
657 ParameterCount expected(0);
658 __ InvokeCode(code, expected, expected,
659 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
660}
661
662
663class CallInterceptorCompiler BASE_EMBEDDED {
664 public:
665 CallInterceptorCompiler(StubCompiler* stub_compiler,
666 const ParameterCount& arguments,
667 Register name)
668 : stub_compiler_(stub_compiler),
669 arguments_(arguments),
670 name_(name) {}
671
672 void Compile(MacroAssembler* masm,
673 JSObject* object,
674 JSObject* holder,
675 String* name,
676 LookupResult* lookup,
677 Register receiver,
678 Register scratch1,
679 Register scratch2,
680 Label* miss) {
681 ASSERT(holder->HasNamedInterceptor());
682 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
683
684 // Check that the receiver isn't a smi.
685 __ BranchOnSmi(receiver, miss);
686
687 CallOptimization optimization(lookup);
688
689 if (optimization.is_constant_call()) {
690 CompileCacheable(masm,
691 object,
692 receiver,
693 scratch1,
694 scratch2,
695 holder,
696 lookup,
697 name,
698 optimization,
699 miss);
700 } else {
701 CompileRegular(masm,
702 object,
703 receiver,
704 scratch1,
705 scratch2,
706 name,
707 holder,
708 miss);
709 }
710 }
711
712 private:
713 void CompileCacheable(MacroAssembler* masm,
714 JSObject* object,
715 Register receiver,
716 Register scratch1,
717 Register scratch2,
718 JSObject* holder_obj,
719 LookupResult* lookup,
720 String* name,
721 const CallOptimization& optimization,
722 Label* miss_label) {
723 ASSERT(optimization.is_constant_call());
724 ASSERT(!lookup->holder()->IsGlobalObject());
725
726 int depth1 = kInvalidProtoDepth;
727 int depth2 = kInvalidProtoDepth;
728 bool can_do_fast_api_call = false;
729 if (optimization.is_simple_api_call() &&
730 !lookup->holder()->IsGlobalObject()) {
731 depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj);
732 if (depth1 == kInvalidProtoDepth) {
733 depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj,
734 lookup->holder());
735 }
736 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
737 (depth2 != kInvalidProtoDepth);
738 }
739
740 __ IncrementCounter(&Counters::call_const_interceptor, 1,
741 scratch1, scratch2);
742
743 if (can_do_fast_api_call) {
744 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1,
745 scratch1, scratch2);
746 ReserveSpaceForFastApiCall(masm, scratch1);
747 }
748
749 Label miss_cleanup;
750 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
751 Register holder =
752 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, scratch1,
753 scratch2, name, depth1, miss);
754
755 Label regular_invoke;
756 LoadWithInterceptor(masm, receiver, holder, holder_obj, scratch2,
757 &regular_invoke);
758
759 // Generate code for the failed interceptor case.
760
761 // Check the lookup is still valid.
762 stub_compiler_->CheckPrototypes(holder_obj, receiver,
763 lookup->holder(), scratch1,
764 scratch2, name, depth2, miss);
765
766 if (can_do_fast_api_call) {
767 GenerateFastApiCall(masm, optimization, arguments_.immediate());
768 } else {
769 __ InvokeFunction(optimization.constant_function(), arguments_,
770 JUMP_FUNCTION);
771 }
772
773 if (can_do_fast_api_call) {
774 __ bind(&miss_cleanup);
775 FreeSpaceForFastApiCall(masm);
776 __ b(miss_label);
777 }
778
779 __ bind(&regular_invoke);
780 if (can_do_fast_api_call) {
781 FreeSpaceForFastApiCall(masm);
782 }
783 }
784
785 void CompileRegular(MacroAssembler* masm,
786 JSObject* object,
787 Register receiver,
788 Register scratch1,
789 Register scratch2,
790 String* name,
791 JSObject* holder_obj,
792 Label* miss_label) {
793 Register holder =
794 stub_compiler_->CheckPrototypes(object, receiver, holder_obj,
795 scratch1, scratch2, name,
796 miss_label);
797
798 // Call a runtime function to load the interceptor property.
799 __ EnterInternalFrame();
800 // Save the name_ register across the call.
801 __ push(name_);
802
803 PushInterceptorArguments(masm,
804 receiver,
805 holder,
806 name_,
807 holder_obj);
808
809 __ CallExternalReference(
810 ExternalReference(
811 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
812 5);
813
814 // Restore the name_ register.
815 __ pop(name_);
816 __ LeaveInternalFrame();
817 }
818
819 void LoadWithInterceptor(MacroAssembler* masm,
820 Register receiver,
821 Register holder,
822 JSObject* holder_obj,
823 Register scratch,
824 Label* interceptor_succeeded) {
825 __ EnterInternalFrame();
826 __ Push(holder, name_);
827
828 CompileCallLoadPropertyWithInterceptor(masm,
829 receiver,
830 holder,
831 name_,
832 holder_obj);
833
834 __ pop(name_); // Restore the name.
835 __ pop(receiver); // Restore the holder.
836 __ LeaveInternalFrame();
837
838 // If interceptor returns no-result sentinel, call the constant function.
839 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
840 __ cmp(r0, scratch);
841 __ b(ne, interceptor_succeeded);
842 }
843
844 StubCompiler* stub_compiler_;
845 const ParameterCount& arguments_;
846 Register name_;
847};
848
849
850// Generate code to check that a global property cell is empty. Create
851// the property cell at compilation time if no cell exists for the
852// property.
853static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
854 GlobalObject* global,
855 String* name,
856 Register scratch,
857 Label* miss) {
858 Object* probe = global->EnsurePropertyCell(name);
859 if (probe->IsFailure()) return probe;
860 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
861 ASSERT(cell->value()->IsTheHole());
862 __ mov(scratch, Operand(Handle<Object>(cell)));
863 __ ldr(scratch,
864 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
865 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
866 __ cmp(scratch, ip);
867 __ b(ne, miss);
868 return cell;
869}
870
871
Steve Blocka7e24c12009-10-30 11:49:00 +0000872#undef __
873#define __ ACCESS_MASM(masm())
874
875
876Register StubCompiler::CheckPrototypes(JSObject* object,
877 Register object_reg,
878 JSObject* holder,
879 Register holder_reg,
880 Register scratch,
881 String* name,
Andrei Popescu402d9372010-02-26 13:31:12 +0000882 int save_at_depth,
Steve Blocka7e24c12009-10-30 11:49:00 +0000883 Label* miss) {
884 // Check that the maps haven't changed.
885 Register result =
Steve Block6ded16b2010-05-10 14:33:55 +0100886 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch,
887 save_at_depth, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000888
889 // If we've skipped any global objects, it's not enough to verify
Steve Block6ded16b2010-05-10 14:33:55 +0100890 // that their maps haven't changed. We also need to check that the
891 // property cell for the property is still empty.
Steve Blocka7e24c12009-10-30 11:49:00 +0000892 while (object != holder) {
893 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100894 Object* cell = GenerateCheckPropertyCell(masm(),
895 GlobalObject::cast(object),
896 name,
897 scratch,
898 miss);
899 if (cell->IsFailure()) {
900 set_failure(Failure::cast(cell));
Steve Blocka7e24c12009-10-30 11:49:00 +0000901 return result;
902 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000903 }
904 object = JSObject::cast(object->GetPrototype());
905 }
906
Andrei Popescu402d9372010-02-26 13:31:12 +0000907 // Return the register containing the holder.
Steve Blocka7e24c12009-10-30 11:49:00 +0000908 return result;
909}
910
911
912void StubCompiler::GenerateLoadField(JSObject* object,
913 JSObject* holder,
914 Register receiver,
915 Register scratch1,
916 Register scratch2,
917 int index,
918 String* name,
919 Label* miss) {
920 // Check that the receiver isn't a smi.
921 __ tst(receiver, Operand(kSmiTagMask));
922 __ b(eq, miss);
923
924 // Check that the maps haven't changed.
925 Register reg =
926 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
927 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
928 __ Ret();
929}
930
931
932void StubCompiler::GenerateLoadConstant(JSObject* object,
933 JSObject* holder,
934 Register receiver,
935 Register scratch1,
936 Register scratch2,
937 Object* value,
938 String* name,
939 Label* miss) {
940 // Check that the receiver isn't a smi.
941 __ tst(receiver, Operand(kSmiTagMask));
942 __ b(eq, miss);
943
944 // Check that the maps haven't changed.
945 Register reg =
946 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
947
948 // Return the constant value.
949 __ mov(r0, Operand(Handle<Object>(value)));
950 __ Ret();
951}
952
953
Leon Clarkee46be812010-01-19 14:06:41 +0000954bool StubCompiler::GenerateLoadCallback(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +0000955 JSObject* holder,
956 Register receiver,
957 Register name_reg,
958 Register scratch1,
959 Register scratch2,
960 AccessorInfo* callback,
961 String* name,
Leon Clarkee46be812010-01-19 14:06:41 +0000962 Label* miss,
963 Failure** failure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000964 // Check that the receiver isn't a smi.
965 __ tst(receiver, Operand(kSmiTagMask));
966 __ b(eq, miss);
967
968 // Check that the maps haven't changed.
969 Register reg =
970 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
971
972 // Push the arguments on the JS stack of the caller.
Steve Block6ded16b2010-05-10 14:33:55 +0100973 __ push(receiver); // Receiver.
974 __ push(reg); // Holder.
Steve Blocka7e24c12009-10-30 11:49:00 +0000975 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
Steve Blocka7e24c12009-10-30 11:49:00 +0000976 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
Steve Block6ded16b2010-05-10 14:33:55 +0100977 __ Push(ip, reg, name_reg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000978
979 // Do tail-call to the runtime system.
980 ExternalReference load_callback_property =
981 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +0100982 __ TailCallExternalReference(load_callback_property, 5, 1);
Leon Clarkee46be812010-01-19 14:06:41 +0000983
984 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000985}
986
987
988void StubCompiler::GenerateLoadInterceptor(JSObject* object,
989 JSObject* holder,
990 LookupResult* lookup,
991 Register receiver,
992 Register name_reg,
993 Register scratch1,
994 Register scratch2,
995 String* name,
996 Label* miss) {
Leon Clarke4515c472010-02-03 11:58:03 +0000997 LoadInterceptorCompiler compiler(name_reg);
998 CompileLoadInterceptor(&compiler,
999 this,
1000 masm(),
1001 object,
1002 holder,
1003 name,
1004 lookup,
1005 receiver,
1006 scratch1,
1007 scratch2,
1008 miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001009}
1010
1011
1012Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
1013 // ----------- S t a t e -------------
1014 // -- r1: function
1015 // -- lr: return address
1016 // -----------------------------------
1017
1018 // Enter an internal frame.
1019 __ EnterInternalFrame();
1020
1021 // Preserve the function.
1022 __ push(r1);
1023
1024 // Push the function on the stack as the argument to the runtime function.
1025 __ push(r1);
1026 __ CallRuntime(Runtime::kLazyCompile, 1);
1027
1028 // Calculate the entry point.
1029 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
1030
1031 // Restore saved function.
1032 __ pop(r1);
1033
1034 // Tear down temporary frame.
1035 __ LeaveInternalFrame();
1036
1037 // Do a tail-call of the compiled function.
1038 __ Jump(r2);
1039
1040 return GetCodeWithFlags(flags, "LazyCompileStub");
1041}
1042
1043
Andrei Popescu402d9372010-02-26 13:31:12 +00001044Object* CallStubCompiler::CompileCallField(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001045 JSObject* holder,
1046 int index,
1047 String* name) {
1048 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001049 // -- r2 : name
1050 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001051 // -----------------------------------
1052 Label miss;
1053
1054 const int argc = arguments().immediate();
1055
1056 // Get the receiver of the function from the stack into r0.
1057 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1058 // Check that the receiver isn't a smi.
1059 __ tst(r0, Operand(kSmiTagMask));
1060 __ b(eq, &miss);
1061
1062 // Do the right check and compute the holder register.
Andrei Popescu402d9372010-02-26 13:31:12 +00001063 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001064 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
1065
Leon Clarke4515c472010-02-03 11:58:03 +00001066 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001067
1068 // Handle call cache miss.
1069 __ bind(&miss);
1070 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1071 __ Jump(ic, RelocInfo::CODE_TARGET);
1072
1073 // Return the generated code.
1074 return GetCode(FIELD, name);
1075}
1076
1077
Steve Block6ded16b2010-05-10 14:33:55 +01001078Object* CallStubCompiler::CompileArrayPushCall(Object* object,
1079 JSObject* holder,
1080 JSFunction* function,
1081 String* name,
1082 CheckType check) {
1083 // ----------- S t a t e -------------
1084 // -- r2 : name
1085 // -- lr : return address
1086 // -----------------------------------
1087
1088 // If object is not an array, bail out to regular call.
1089 if (!object->IsJSArray()) {
1090 return Heap::undefined_value();
1091 }
1092
1093 // TODO(639): faster implementation.
1094 ASSERT(check == RECEIVER_MAP_CHECK);
1095
1096 Label miss;
1097
1098 // Get the receiver from the stack
1099 const int argc = arguments().immediate();
1100 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1101
1102 // Check that the receiver isn't a smi.
1103 __ tst(r1, Operand(kSmiTagMask));
1104 __ b(eq, &miss);
1105
1106 // Check that the maps haven't changed.
1107 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1108
1109 if (object->IsGlobalObject()) {
1110 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1111 __ str(r3, MemOperand(sp, argc * kPointerSize));
1112 }
1113
1114 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
1115 argc + 1,
1116 1);
1117
1118 // Handle call cache miss.
1119 __ bind(&miss);
1120 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1121 __ Jump(ic, RelocInfo::CODE_TARGET);
1122
1123 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001124 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001125}
1126
1127
1128Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1129 JSObject* holder,
1130 JSFunction* function,
1131 String* name,
1132 CheckType check) {
1133 // ----------- S t a t e -------------
1134 // -- r2 : name
1135 // -- lr : return address
1136 // -----------------------------------
1137
1138 // If object is not an array, bail out to regular call.
1139 if (!object->IsJSArray()) {
1140 return Heap::undefined_value();
1141 }
1142
1143 // TODO(642): faster implementation.
1144 ASSERT(check == RECEIVER_MAP_CHECK);
1145
1146 Label miss;
1147
1148 // Get the receiver from the stack
1149 const int argc = arguments().immediate();
1150 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1151
1152 // Check that the receiver isn't a smi.
1153 __ tst(r1, Operand(kSmiTagMask));
1154 __ b(eq, &miss);
1155
1156 // Check that the maps haven't changed.
1157 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1158
1159 if (object->IsGlobalObject()) {
1160 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1161 __ str(r3, MemOperand(sp, argc * kPointerSize));
1162 }
1163
1164 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1165 argc + 1,
1166 1);
1167
1168 // Handle call cache miss.
1169 __ bind(&miss);
1170 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1171 __ Jump(ic, RelocInfo::CODE_TARGET);
1172
1173 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001174 return GetCode(function);
Steve Block6ded16b2010-05-10 14:33:55 +01001175}
1176
1177
Steve Blocka7e24c12009-10-30 11:49:00 +00001178Object* CallStubCompiler::CompileCallConstant(Object* object,
1179 JSObject* holder,
1180 JSFunction* function,
1181 String* name,
1182 CheckType check) {
1183 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001184 // -- r2 : name
1185 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001186 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001187 SharedFunctionInfo* function_info = function->shared();
1188 if (function_info->HasCustomCallGenerator()) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001189 const int id = function_info->custom_call_generator_id();
1190 Object* result =
1191 CompileCustomCall(id, object, holder, function, name, check);
Steve Block6ded16b2010-05-10 14:33:55 +01001192 // undefined means bail out to regular compiler.
1193 if (!result->IsUndefined()) {
1194 return result;
1195 }
1196 }
1197
1198 Label miss_in_smi_check;
Steve Blocka7e24c12009-10-30 11:49:00 +00001199
1200 // Get the receiver from the stack
1201 const int argc = arguments().immediate();
1202 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1203
1204 // Check that the receiver isn't a smi.
1205 if (check != NUMBER_CHECK) {
1206 __ tst(r1, Operand(kSmiTagMask));
Steve Block6ded16b2010-05-10 14:33:55 +01001207 __ b(eq, &miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001208 }
1209
1210 // Make sure that it's okay not to patch the on stack receiver
1211 // unless we're doing a receiver map check.
1212 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1213
Steve Block6ded16b2010-05-10 14:33:55 +01001214 CallOptimization optimization(function);
1215 int depth = kInvalidProtoDepth;
1216 Label miss;
1217
Steve Blocka7e24c12009-10-30 11:49:00 +00001218 switch (check) {
1219 case RECEIVER_MAP_CHECK:
Steve Block6ded16b2010-05-10 14:33:55 +01001220 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1221
1222 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1223 depth = optimization.GetPrototypeDepthOfExpectedType(
1224 JSObject::cast(object), holder);
1225 }
1226
1227 if (depth != kInvalidProtoDepth) {
1228 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1229 ReserveSpaceForFastApiCall(masm(), r0);
1230 }
1231
Steve Blocka7e24c12009-10-30 11:49:00 +00001232 // Check that the maps haven't changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001233 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, name,
1234 depth, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001235
1236 // Patch the receiver on the stack with the global proxy if
1237 // necessary.
1238 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001239 ASSERT(depth == kInvalidProtoDepth);
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1241 __ str(r3, MemOperand(sp, argc * kPointerSize));
1242 }
1243 break;
1244
1245 case STRING_CHECK:
Leon Clarkee46be812010-01-19 14:06:41 +00001246 if (!function->IsBuiltin()) {
1247 // Calling non-builtins with a value as receiver requires boxing.
1248 __ jmp(&miss);
1249 } else {
1250 // Check that the object is a two-byte string or a symbol.
Andrei Popescu402d9372010-02-26 13:31:12 +00001251 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001252 __ b(hs, &miss);
1253 // Check that the maps starting from the prototype haven't changed.
1254 GenerateLoadGlobalFunctionPrototype(masm(),
1255 Context::STRING_FUNCTION_INDEX,
Andrei Popescu402d9372010-02-26 13:31:12 +00001256 r0);
1257 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001258 r1, name, &miss);
1259 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001260 break;
1261
1262 case NUMBER_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001263 if (!function->IsBuiltin()) {
1264 // Calling non-builtins with a value as receiver requires boxing.
1265 __ jmp(&miss);
1266 } else {
1267 Label fast;
1268 // Check that the object is a smi or a heap number.
1269 __ tst(r1, Operand(kSmiTagMask));
1270 __ b(eq, &fast);
Andrei Popescu402d9372010-02-26 13:31:12 +00001271 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001272 __ b(ne, &miss);
1273 __ bind(&fast);
1274 // Check that the maps starting from the prototype haven't changed.
1275 GenerateLoadGlobalFunctionPrototype(masm(),
1276 Context::NUMBER_FUNCTION_INDEX,
Andrei Popescu402d9372010-02-26 13:31:12 +00001277 r0);
1278 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001279 r1, name, &miss);
1280 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001281 break;
1282 }
1283
1284 case BOOLEAN_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001285 if (!function->IsBuiltin()) {
1286 // Calling non-builtins with a value as receiver requires boxing.
1287 __ jmp(&miss);
1288 } else {
1289 Label fast;
1290 // Check that the object is a boolean.
1291 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1292 __ cmp(r1, ip);
1293 __ b(eq, &fast);
1294 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1295 __ cmp(r1, ip);
1296 __ b(ne, &miss);
1297 __ bind(&fast);
1298 // Check that the maps starting from the prototype haven't changed.
1299 GenerateLoadGlobalFunctionPrototype(masm(),
1300 Context::BOOLEAN_FUNCTION_INDEX,
Andrei Popescu402d9372010-02-26 13:31:12 +00001301 r0);
1302 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001303 r1, name, &miss);
1304 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001305 break;
1306 }
1307
Steve Blocka7e24c12009-10-30 11:49:00 +00001308 default:
1309 UNREACHABLE();
1310 }
1311
Steve Block6ded16b2010-05-10 14:33:55 +01001312 if (depth != kInvalidProtoDepth) {
1313 GenerateFastApiCall(masm(), optimization, argc);
1314 } else {
1315 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1316 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001317
1318 // Handle call cache miss.
1319 __ bind(&miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001320 if (depth != kInvalidProtoDepth) {
1321 FreeSpaceForFastApiCall(masm());
1322 }
1323
1324 __ bind(&miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001325 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1326 __ Jump(ic, RelocInfo::CODE_TARGET);
1327
1328 // Return the generated code.
Kristian Monsen25f61362010-05-21 11:50:48 +01001329 return GetCode(function);
Steve Blocka7e24c12009-10-30 11:49:00 +00001330}
1331
1332
Andrei Popescu402d9372010-02-26 13:31:12 +00001333Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001334 JSObject* holder,
1335 String* name) {
1336 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001337 // -- r2 : name
1338 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001339 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001340
Steve Block6ded16b2010-05-10 14:33:55 +01001341 Label miss;
Andrei Popescu402d9372010-02-26 13:31:12 +00001342
Leon Clarke4515c472010-02-03 11:58:03 +00001343 // Get the number of arguments.
1344 const int argc = arguments().immediate();
1345
1346 LookupResult lookup;
1347 LookupPostInterceptor(holder, name, &lookup);
1348
Steve Block6ded16b2010-05-10 14:33:55 +01001349 // Get the receiver from the stack.
1350 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001351
Steve Block6ded16b2010-05-10 14:33:55 +01001352 CallInterceptorCompiler compiler(this, arguments(), r2);
1353 compiler.Compile(masm(),
1354 object,
1355 holder,
1356 name,
1357 &lookup,
1358 r1,
1359 r3,
1360 r4,
1361 &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001362
1363 // Move returned value, the function to call, to r1.
1364 __ mov(r1, r0);
Leon Clarke4515c472010-02-03 11:58:03 +00001365 // Restore receiver.
Steve Block6ded16b2010-05-10 14:33:55 +01001366 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001367
1368 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001369
1370 // Handle call cache miss.
1371 __ bind(&miss);
1372 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1373 __ Jump(ic, RelocInfo::CODE_TARGET);
1374
1375 // Return the generated code.
1376 return GetCode(INTERCEPTOR, name);
1377}
1378
1379
1380Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1381 GlobalObject* holder,
1382 JSGlobalPropertyCell* cell,
1383 JSFunction* function,
1384 String* name) {
1385 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001386 // -- r2 : name
1387 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001388 // -----------------------------------
1389 Label miss;
1390
1391 // Get the number of arguments.
1392 const int argc = arguments().immediate();
1393
1394 // Get the receiver from the stack.
1395 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1396
1397 // If the object is the holder then we know that it's a global
1398 // object which can only happen for contextual calls. In this case,
1399 // the receiver cannot be a smi.
1400 if (object != holder) {
1401 __ tst(r0, Operand(kSmiTagMask));
1402 __ b(eq, &miss);
1403 }
1404
1405 // Check that the maps haven't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001406 CheckPrototypes(object, r0, holder, r3, r1, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001407
1408 // Get the value from the cell.
1409 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1410 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1411
1412 // Check that the cell contains the same function.
Leon Clarkee46be812010-01-19 14:06:41 +00001413 if (Heap::InNewSpace(function)) {
1414 // We can't embed a pointer to a function in new space so we have
1415 // to verify that the shared function info is unchanged. This has
1416 // the nice side effect that multiple closures based on the same
1417 // function can all use this call IC. Before we load through the
1418 // function, we have to verify that it still is a function.
1419 __ tst(r1, Operand(kSmiTagMask));
1420 __ b(eq, &miss);
1421 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1422 __ b(ne, &miss);
1423
1424 // Check the shared function info. Make sure it hasn't changed.
1425 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
Andrei Popescu402d9372010-02-26 13:31:12 +00001426 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1427 __ cmp(r4, r3);
Leon Clarkee46be812010-01-19 14:06:41 +00001428 __ b(ne, &miss);
1429 } else {
1430 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1431 __ b(ne, &miss);
1432 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001433
1434 // Patch the receiver on the stack with the global proxy if
1435 // necessary.
1436 if (object->IsGlobalObject()) {
1437 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1438 __ str(r3, MemOperand(sp, argc * kPointerSize));
1439 }
1440
1441 // Setup the context (function already in r1).
1442 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1443
1444 // Jump to the cached code (tail call).
Steve Block6ded16b2010-05-10 14:33:55 +01001445 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001446 ASSERT(function->is_compiled());
1447 Handle<Code> code(function->code());
1448 ParameterCount expected(function->shared()->formal_parameter_count());
1449 __ InvokeCode(code, expected, arguments(),
1450 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1451
1452 // Handle call cache miss.
1453 __ bind(&miss);
1454 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
1455 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1456 __ Jump(ic, RelocInfo::CODE_TARGET);
1457
1458 // Return the generated code.
1459 return GetCode(NORMAL, name);
1460}
1461
1462
1463Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1464 int index,
1465 Map* transition,
1466 String* name) {
1467 // ----------- S t a t e -------------
1468 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001469 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001470 // -- r2 : name
1471 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001472 // -----------------------------------
1473 Label miss;
1474
Steve Blocka7e24c12009-10-30 11:49:00 +00001475 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001476 object,
1477 index,
1478 transition,
Andrei Popescu402d9372010-02-26 13:31:12 +00001479 r1, r2, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001480 &miss);
1481 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001482 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1483 __ Jump(ic, RelocInfo::CODE_TARGET);
1484
1485 // Return the generated code.
1486 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1487}
1488
1489
1490Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1491 AccessorInfo* callback,
1492 String* name) {
1493 // ----------- S t a t e -------------
1494 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001495 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001496 // -- r2 : name
1497 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001498 // -----------------------------------
1499 Label miss;
1500
Steve Blocka7e24c12009-10-30 11:49:00 +00001501 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001502 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001503 __ b(eq, &miss);
1504
1505 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001506 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1507 __ cmp(r3, Operand(Handle<Map>(object->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001508 __ b(ne, &miss);
1509
1510 // Perform global security token check if needed.
1511 if (object->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001512 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001513 }
1514
1515 // Stub never generated for non-global objects that require access
1516 // checks.
1517 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1518
Andrei Popescu402d9372010-02-26 13:31:12 +00001519 __ push(r1); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001520 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
Steve Block6ded16b2010-05-10 14:33:55 +01001521 __ Push(ip, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001522
1523 // Do tail-call to the runtime system.
1524 ExternalReference store_callback_property =
1525 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001526 __ TailCallExternalReference(store_callback_property, 4, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001527
1528 // Handle store cache miss.
1529 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001530 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1531 __ Jump(ic, RelocInfo::CODE_TARGET);
1532
1533 // Return the generated code.
1534 return GetCode(CALLBACKS, name);
1535}
1536
1537
1538Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1539 String* name) {
1540 // ----------- S t a t e -------------
1541 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001542 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001543 // -- r2 : name
1544 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001545 // -----------------------------------
1546 Label miss;
1547
Steve Blocka7e24c12009-10-30 11:49:00 +00001548 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001549 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001550 __ b(eq, &miss);
1551
1552 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001553 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1554 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001555 __ b(ne, &miss);
1556
1557 // Perform global security token check if needed.
1558 if (receiver->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001559 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001560 }
1561
Andrei Popescu402d9372010-02-26 13:31:12 +00001562 // Stub is never generated for non-global objects that require access
Steve Blocka7e24c12009-10-30 11:49:00 +00001563 // checks.
1564 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1565
Steve Block6ded16b2010-05-10 14:33:55 +01001566 __ Push(r1, r2, r0); // Receiver, name, value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001567
1568 // Do tail-call to the runtime system.
1569 ExternalReference store_ic_property =
1570 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001571 __ TailCallExternalReference(store_ic_property, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001572
1573 // Handle store cache miss.
1574 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001575 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1576 __ Jump(ic, RelocInfo::CODE_TARGET);
1577
1578 // Return the generated code.
1579 return GetCode(INTERCEPTOR, name);
1580}
1581
1582
1583Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1584 JSGlobalPropertyCell* cell,
1585 String* name) {
1586 // ----------- S t a t e -------------
1587 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001588 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001589 // -- r2 : name
1590 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001591 // -----------------------------------
1592 Label miss;
1593
1594 // Check that the map of the global has not changed.
Steve Blocka7e24c12009-10-30 11:49:00 +00001595 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1596 __ cmp(r3, Operand(Handle<Map>(object->map())));
1597 __ b(ne, &miss);
1598
1599 // Store the value in the cell.
1600 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1601 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
1602
Andrei Popescu402d9372010-02-26 13:31:12 +00001603 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001604 __ Ret();
1605
1606 // Handle store cache miss.
1607 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001608 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001609 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1610 __ Jump(ic, RelocInfo::CODE_TARGET);
1611
1612 // Return the generated code.
1613 return GetCode(NORMAL, name);
1614}
1615
1616
Steve Block6ded16b2010-05-10 14:33:55 +01001617Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1618 JSObject* object,
1619 JSObject* last) {
1620 // ----------- S t a t e -------------
1621 // -- r2 : name
1622 // -- lr : return address
1623 // -- [sp] : receiver
1624 // -----------------------------------
1625 Label miss;
1626
1627 // Load receiver.
1628 __ ldr(r0, MemOperand(sp, 0));
1629
1630 // Check that receiver is not a smi.
1631 __ tst(r0, Operand(kSmiTagMask));
1632 __ b(eq, &miss);
1633
1634 // Check the maps of the full prototype chain.
1635 CheckPrototypes(object, r0, last, r3, r1, name, &miss);
1636
1637 // If the last object in the prototype chain is a global object,
1638 // check that the global property cell is empty.
1639 if (last->IsGlobalObject()) {
1640 Object* cell = GenerateCheckPropertyCell(masm(),
1641 GlobalObject::cast(last),
1642 name,
1643 r1,
1644 &miss);
1645 if (cell->IsFailure()) return cell;
1646 }
1647
1648 // Return undefined if maps of the full prototype chain are still the
1649 // same and no global property with this name contains a value.
1650 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1651 __ Ret();
1652
1653 __ bind(&miss);
1654 GenerateLoadMiss(masm(), Code::LOAD_IC);
1655
1656 // Return the generated code.
1657 return GetCode(NONEXISTENT, Heap::empty_string());
1658}
1659
1660
Steve Blocka7e24c12009-10-30 11:49:00 +00001661Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1662 JSObject* holder,
1663 int index,
1664 String* name) {
1665 // ----------- S t a t e -------------
1666 // -- r2 : name
1667 // -- lr : return address
1668 // -- [sp] : receiver
1669 // -----------------------------------
1670 Label miss;
1671
1672 __ ldr(r0, MemOperand(sp, 0));
1673
1674 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
1675 __ bind(&miss);
1676 GenerateLoadMiss(masm(), Code::LOAD_IC);
1677
1678 // Return the generated code.
1679 return GetCode(FIELD, name);
1680}
1681
1682
Leon Clarkee46be812010-01-19 14:06:41 +00001683Object* LoadStubCompiler::CompileLoadCallback(String* name,
1684 JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001685 JSObject* holder,
Leon Clarkee46be812010-01-19 14:06:41 +00001686 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001687 // ----------- S t a t e -------------
1688 // -- r2 : name
1689 // -- lr : return address
1690 // -- [sp] : receiver
1691 // -----------------------------------
1692 Label miss;
1693
1694 __ ldr(r0, MemOperand(sp, 0));
Leon Clarkee46be812010-01-19 14:06:41 +00001695 Failure* failure = Failure::InternalError();
1696 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
1697 callback, name, &miss, &failure);
1698 if (!success) return failure;
1699
Steve Blocka7e24c12009-10-30 11:49:00 +00001700 __ bind(&miss);
1701 GenerateLoadMiss(masm(), Code::LOAD_IC);
1702
1703 // Return the generated code.
1704 return GetCode(CALLBACKS, name);
1705}
1706
1707
1708Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1709 JSObject* holder,
1710 Object* value,
1711 String* name) {
1712 // ----------- S t a t e -------------
1713 // -- r2 : name
1714 // -- lr : return address
1715 // -- [sp] : receiver
1716 // -----------------------------------
1717 Label miss;
1718
1719 __ ldr(r0, MemOperand(sp, 0));
1720
1721 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
1722 __ bind(&miss);
1723 GenerateLoadMiss(masm(), Code::LOAD_IC);
1724
1725 // Return the generated code.
1726 return GetCode(CONSTANT_FUNCTION, name);
1727}
1728
1729
1730Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1731 JSObject* holder,
1732 String* name) {
1733 // ----------- S t a t e -------------
1734 // -- r2 : name
1735 // -- lr : return address
1736 // -- [sp] : receiver
1737 // -----------------------------------
1738 Label miss;
1739
1740 __ ldr(r0, MemOperand(sp, 0));
1741
1742 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001743 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001744 GenerateLoadInterceptor(object,
1745 holder,
1746 &lookup,
1747 r0,
1748 r2,
1749 r3,
1750 r1,
1751 name,
1752 &miss);
1753 __ bind(&miss);
1754 GenerateLoadMiss(masm(), Code::LOAD_IC);
1755
1756 // Return the generated code.
1757 return GetCode(INTERCEPTOR, name);
1758}
1759
1760
1761Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1762 GlobalObject* holder,
1763 JSGlobalPropertyCell* cell,
1764 String* name,
1765 bool is_dont_delete) {
1766 // ----------- S t a t e -------------
1767 // -- r2 : name
1768 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001769 // -- r0 : receiver
1770 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001771 // -----------------------------------
1772 Label miss;
1773
Steve Blocka7e24c12009-10-30 11:49:00 +00001774 // If the object is the holder then we know that it's a global
1775 // object which can only happen for contextual calls. In this case,
1776 // the receiver cannot be a smi.
1777 if (object != holder) {
Steve Block6ded16b2010-05-10 14:33:55 +01001778 __ tst(r0, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001779 __ b(eq, &miss);
1780 }
1781
1782 // Check that the map of the global has not changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001783 CheckPrototypes(object, r0, holder, r3, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001784
1785 // Get the value from the cell.
1786 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
Steve Block6ded16b2010-05-10 14:33:55 +01001787 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001788
1789 // Check for deleted property if property can actually be deleted.
1790 if (!is_dont_delete) {
1791 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
Steve Block6ded16b2010-05-10 14:33:55 +01001792 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00001793 __ b(eq, &miss);
1794 }
1795
Steve Block6ded16b2010-05-10 14:33:55 +01001796 __ mov(r0, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001797 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1798 __ Ret();
1799
1800 __ bind(&miss);
1801 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1802 GenerateLoadMiss(masm(), Code::LOAD_IC);
1803
1804 // Return the generated code.
1805 return GetCode(NORMAL, name);
1806}
1807
1808
1809Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1810 JSObject* receiver,
1811 JSObject* holder,
1812 int index) {
1813 // ----------- S t a t e -------------
1814 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001815 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001816 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001817 // -----------------------------------
1818 Label miss;
1819
Steve Block6ded16b2010-05-10 14:33:55 +01001820 // Check the key is the cached one.
1821 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001822 __ b(ne, &miss);
1823
Steve Block6ded16b2010-05-10 14:33:55 +01001824 GenerateLoadField(receiver, holder, r1, r2, r3, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001825 __ bind(&miss);
1826 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1827
1828 return GetCode(FIELD, name);
1829}
1830
1831
1832Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1833 JSObject* receiver,
1834 JSObject* holder,
1835 AccessorInfo* callback) {
1836 // ----------- S t a t e -------------
1837 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001838 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001839 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001840 // -----------------------------------
1841 Label miss;
1842
Steve Block6ded16b2010-05-10 14:33:55 +01001843 // Check the key is the cached one.
1844 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001845 __ b(ne, &miss);
1846
Leon Clarkee46be812010-01-19 14:06:41 +00001847 Failure* failure = Failure::InternalError();
Steve Block6ded16b2010-05-10 14:33:55 +01001848 bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001849 callback, name, &miss, &failure);
1850 if (!success) return failure;
1851
Steve Blocka7e24c12009-10-30 11:49:00 +00001852 __ bind(&miss);
1853 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1854
1855 return GetCode(CALLBACKS, name);
1856}
1857
1858
1859Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1860 JSObject* receiver,
1861 JSObject* holder,
1862 Object* value) {
1863 // ----------- S t a t e -------------
1864 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001865 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001866 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001867 // -----------------------------------
1868 Label miss;
1869
Steve Block6ded16b2010-05-10 14:33:55 +01001870 // Check the key is the cached one.
1871 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001872 __ b(ne, &miss);
1873
Steve Block6ded16b2010-05-10 14:33:55 +01001874 GenerateLoadConstant(receiver, holder, r1, r2, r3, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001875 __ bind(&miss);
1876 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1877
1878 // Return the generated code.
1879 return GetCode(CONSTANT_FUNCTION, name);
1880}
1881
1882
1883Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1884 JSObject* holder,
1885 String* name) {
1886 // ----------- S t a t e -------------
1887 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001888 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001889 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001890 // -----------------------------------
1891 Label miss;
1892
Steve Block6ded16b2010-05-10 14:33:55 +01001893 // Check the key is the cached one.
1894 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001895 __ b(ne, &miss);
1896
1897 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001898 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001899 GenerateLoadInterceptor(receiver,
1900 holder,
1901 &lookup,
Steve Block6ded16b2010-05-10 14:33:55 +01001902 r1,
Steve Blocka7e24c12009-10-30 11:49:00 +00001903 r0,
1904 r2,
1905 r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001906 name,
1907 &miss);
1908 __ bind(&miss);
1909 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1910
1911 return GetCode(INTERCEPTOR, name);
1912}
1913
1914
1915Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1916 // ----------- S t a t e -------------
1917 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001918 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001919 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001920 // -----------------------------------
1921 Label miss;
1922
Steve Block6ded16b2010-05-10 14:33:55 +01001923 // Check the key is the cached one.
1924 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001925 __ b(ne, &miss);
1926
Steve Block6ded16b2010-05-10 14:33:55 +01001927 GenerateLoadArrayLength(masm(), r1, r2, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001928 __ bind(&miss);
1929 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1930
1931 return GetCode(CALLBACKS, name);
1932}
1933
1934
1935Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
1936 // ----------- S t a t e -------------
1937 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001938 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001939 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001940 // -----------------------------------
1941 Label miss;
1942 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1943
Steve Block6ded16b2010-05-10 14:33:55 +01001944 // Check the key is the cached one.
1945 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001946 __ b(ne, &miss);
1947
Steve Block6ded16b2010-05-10 14:33:55 +01001948 GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001949 __ bind(&miss);
1950 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1951
1952 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1953
1954 return GetCode(CALLBACKS, name);
1955}
1956
1957
1958// TODO(1224671): implement the fast case.
1959Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1960 // ----------- S t a t e -------------
1961 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001962 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001963 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001964 // -----------------------------------
1965 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1966
1967 return GetCode(CALLBACKS, name);
1968}
1969
1970
1971Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1972 int index,
1973 Map* transition,
1974 String* name) {
1975 // ----------- S t a t e -------------
1976 // -- r0 : value
1977 // -- r2 : name
1978 // -- lr : return address
1979 // -- [sp] : receiver
1980 // -----------------------------------
1981 Label miss;
1982
1983 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1984
1985 // Check that the name has not changed.
1986 __ cmp(r2, Operand(Handle<String>(name)));
1987 __ b(ne, &miss);
1988
1989 // Load receiver from the stack.
1990 __ ldr(r3, MemOperand(sp));
1991 // r1 is used as scratch register, r3 and r2 might be clobbered.
1992 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001993 object,
1994 index,
1995 transition,
1996 r3, r2, r1,
1997 &miss);
1998 __ bind(&miss);
1999
2000 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
2001 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
2002 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
2003 __ Jump(ic, RelocInfo::CODE_TARGET);
2004
2005 // Return the generated code.
2006 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2007}
2008
2009
2010Object* ConstructStubCompiler::CompileConstructStub(
2011 SharedFunctionInfo* shared) {
2012 // ----------- S t a t e -------------
2013 // -- r0 : argc
2014 // -- r1 : constructor
2015 // -- lr : return address
2016 // -- [sp] : last argument
2017 // -----------------------------------
2018 Label generic_stub_call;
2019
2020 // Use r7 for holding undefined which is used in several places below.
2021 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2022
2023#ifdef ENABLE_DEBUGGER_SUPPORT
2024 // Check to see whether there are any break points in the function code. If
2025 // there are jump to the generic constructor stub which calls the actual
2026 // code for the function thereby hitting the break points.
2027 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2028 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2029 __ cmp(r2, r7);
2030 __ b(ne, &generic_stub_call);
2031#endif
2032
2033 // Load the initial map and verify that it is in fact a map.
2034 // r1: constructor function
2035 // r7: undefined
2036 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2037 __ tst(r2, Operand(kSmiTagMask));
2038 __ b(eq, &generic_stub_call);
2039 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2040 __ b(ne, &generic_stub_call);
2041
2042#ifdef DEBUG
2043 // Cannot construct functions this way.
2044 // r0: argc
2045 // r1: constructor function
2046 // r2: initial map
2047 // r7: undefined
2048 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2049 __ Check(ne, "Function constructed by construct stub.");
2050#endif
2051
2052 // Now allocate the JSObject in new space.
2053 // r0: argc
2054 // r1: constructor function
2055 // r2: initial map
2056 // r7: undefined
2057 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
2058 __ AllocateInNewSpace(r3,
2059 r4,
2060 r5,
2061 r6,
2062 &generic_stub_call,
Kristian Monsen25f61362010-05-21 11:50:48 +01002063 SIZE_IN_WORDS);
Steve Blocka7e24c12009-10-30 11:49:00 +00002064
2065 // Allocated the JSObject, now initialize the fields. Map is set to initial
2066 // map and properties and elements are set to empty fixed array.
2067 // r0: argc
2068 // r1: constructor function
2069 // r2: initial map
2070 // r3: object size (in words)
2071 // r4: JSObject (not tagged)
2072 // r7: undefined
2073 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2074 __ mov(r5, r4);
2075 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2076 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2077 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2078 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2079 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2080 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2081
2082 // Calculate the location of the first argument. The stack contains only the
2083 // argc arguments.
2084 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2085
2086 // Fill all the in-object properties with undefined.
2087 // r0: argc
2088 // r1: first argument
2089 // r3: object size (in words)
2090 // r4: JSObject (not tagged)
2091 // r5: First in-object property of JSObject (not tagged)
2092 // r7: undefined
2093 // Fill the initialized properties with a constant value or a passed argument
2094 // depending on the this.x = ...; assignment in the function.
2095 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2096 if (shared->IsThisPropertyAssignmentArgument(i)) {
2097 Label not_passed, next;
2098 // Check if the argument assigned to the property is actually passed.
2099 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2100 __ cmp(r0, Operand(arg_number));
2101 __ b(le, &not_passed);
2102 // Argument passed - find it on the stack.
2103 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2104 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2105 __ b(&next);
2106 __ bind(&not_passed);
2107 // Set the property to undefined.
2108 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2109 __ bind(&next);
2110 } else {
2111 // Set the property to the constant value.
2112 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2113 __ mov(r2, Operand(constant));
2114 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2115 }
2116 }
2117
2118 // Fill the unused in-object property fields with undefined.
2119 for (int i = shared->this_property_assignments_count();
2120 i < shared->CalculateInObjectProperties();
2121 i++) {
2122 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2123 }
2124
2125 // r0: argc
2126 // r4: JSObject (not tagged)
2127 // Move argc to r1 and the JSObject to return to r0 and tag it.
2128 __ mov(r1, r0);
2129 __ mov(r0, r4);
2130 __ orr(r0, r0, Operand(kHeapObjectTag));
2131
2132 // r0: JSObject
2133 // r1: argc
2134 // Remove caller arguments and receiver from the stack and return.
2135 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2136 __ add(sp, sp, Operand(kPointerSize));
2137 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2138 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2139 __ Jump(lr);
2140
2141 // Jump to the generic stub in case the specialized code cannot handle the
2142 // construction.
2143 __ bind(&generic_stub_call);
2144 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2145 Handle<Code> generic_construct_stub(code);
2146 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2147
2148 // Return the generated code.
2149 return GetCode();
2150}
2151
2152
2153#undef __
2154
2155} } // namespace v8::internal