blob: 095631d6428cea1abe0f3a9937fdc85e994c4f14 [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.
1124 String* function_name = NULL;
1125 if (function->shared()->name()->IsString()) {
1126 function_name = String::cast(function->shared()->name());
1127 }
1128 return GetCode(CONSTANT_FUNCTION, function_name);
1129}
1130
1131
1132Object* CallStubCompiler::CompileArrayPopCall(Object* object,
1133 JSObject* holder,
1134 JSFunction* function,
1135 String* name,
1136 CheckType check) {
1137 // ----------- S t a t e -------------
1138 // -- r2 : name
1139 // -- lr : return address
1140 // -----------------------------------
1141
1142 // If object is not an array, bail out to regular call.
1143 if (!object->IsJSArray()) {
1144 return Heap::undefined_value();
1145 }
1146
1147 // TODO(642): faster implementation.
1148 ASSERT(check == RECEIVER_MAP_CHECK);
1149
1150 Label miss;
1151
1152 // Get the receiver from the stack
1153 const int argc = arguments().immediate();
1154 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1155
1156 // Check that the receiver isn't a smi.
1157 __ tst(r1, Operand(kSmiTagMask));
1158 __ b(eq, &miss);
1159
1160 // Check that the maps haven't changed.
1161 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
1162
1163 if (object->IsGlobalObject()) {
1164 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1165 __ str(r3, MemOperand(sp, argc * kPointerSize));
1166 }
1167
1168 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
1169 argc + 1,
1170 1);
1171
1172 // Handle call cache miss.
1173 __ bind(&miss);
1174 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1175 __ Jump(ic, RelocInfo::CODE_TARGET);
1176
1177 // Return the generated code.
1178 String* function_name = NULL;
1179 if (function->shared()->name()->IsString()) {
1180 function_name = String::cast(function->shared()->name());
1181 }
1182 return GetCode(CONSTANT_FUNCTION, function_name);
1183}
1184
1185
Steve Blocka7e24c12009-10-30 11:49:00 +00001186Object* CallStubCompiler::CompileCallConstant(Object* object,
1187 JSObject* holder,
1188 JSFunction* function,
1189 String* name,
1190 CheckType check) {
1191 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001192 // -- r2 : name
1193 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001194 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001195 SharedFunctionInfo* function_info = function->shared();
1196 if (function_info->HasCustomCallGenerator()) {
1197 CustomCallGenerator generator =
1198 ToCData<CustomCallGenerator>(function_info->function_data());
1199 Object* result = generator(this, object, holder, function, name, check);
1200 // undefined means bail out to regular compiler.
1201 if (!result->IsUndefined()) {
1202 return result;
1203 }
1204 }
1205
1206 Label miss_in_smi_check;
Steve Blocka7e24c12009-10-30 11:49:00 +00001207
1208 // Get the receiver from the stack
1209 const int argc = arguments().immediate();
1210 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
1211
1212 // Check that the receiver isn't a smi.
1213 if (check != NUMBER_CHECK) {
1214 __ tst(r1, Operand(kSmiTagMask));
Steve Block6ded16b2010-05-10 14:33:55 +01001215 __ b(eq, &miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001216 }
1217
1218 // Make sure that it's okay not to patch the on stack receiver
1219 // unless we're doing a receiver map check.
1220 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1221
Steve Block6ded16b2010-05-10 14:33:55 +01001222 CallOptimization optimization(function);
1223 int depth = kInvalidProtoDepth;
1224 Label miss;
1225
Steve Blocka7e24c12009-10-30 11:49:00 +00001226 switch (check) {
1227 case RECEIVER_MAP_CHECK:
Steve Block6ded16b2010-05-10 14:33:55 +01001228 __ IncrementCounter(&Counters::call_const, 1, r0, r3);
1229
1230 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1231 depth = optimization.GetPrototypeDepthOfExpectedType(
1232 JSObject::cast(object), holder);
1233 }
1234
1235 if (depth != kInvalidProtoDepth) {
1236 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
1237 ReserveSpaceForFastApiCall(masm(), r0);
1238 }
1239
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 // Check that the maps haven't changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001241 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, name,
1242 depth, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001243
1244 // Patch the receiver on the stack with the global proxy if
1245 // necessary.
1246 if (object->IsGlobalObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001247 ASSERT(depth == kInvalidProtoDepth);
Steve Blocka7e24c12009-10-30 11:49:00 +00001248 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1249 __ str(r3, MemOperand(sp, argc * kPointerSize));
1250 }
1251 break;
1252
1253 case STRING_CHECK:
Leon Clarkee46be812010-01-19 14:06:41 +00001254 if (!function->IsBuiltin()) {
1255 // Calling non-builtins with a value as receiver requires boxing.
1256 __ jmp(&miss);
1257 } else {
1258 // Check that the object is a two-byte string or a symbol.
Andrei Popescu402d9372010-02-26 13:31:12 +00001259 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001260 __ b(hs, &miss);
1261 // Check that the maps starting from the prototype haven't changed.
1262 GenerateLoadGlobalFunctionPrototype(masm(),
1263 Context::STRING_FUNCTION_INDEX,
Andrei Popescu402d9372010-02-26 13:31:12 +00001264 r0);
1265 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001266 r1, name, &miss);
1267 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001268 break;
1269
1270 case NUMBER_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001271 if (!function->IsBuiltin()) {
1272 // Calling non-builtins with a value as receiver requires boxing.
1273 __ jmp(&miss);
1274 } else {
1275 Label fast;
1276 // Check that the object is a smi or a heap number.
1277 __ tst(r1, Operand(kSmiTagMask));
1278 __ b(eq, &fast);
Andrei Popescu402d9372010-02-26 13:31:12 +00001279 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
Leon Clarkee46be812010-01-19 14:06:41 +00001280 __ b(ne, &miss);
1281 __ bind(&fast);
1282 // Check that the maps starting from the prototype haven't changed.
1283 GenerateLoadGlobalFunctionPrototype(masm(),
1284 Context::NUMBER_FUNCTION_INDEX,
Andrei Popescu402d9372010-02-26 13:31:12 +00001285 r0);
1286 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001287 r1, name, &miss);
1288 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001289 break;
1290 }
1291
1292 case BOOLEAN_CHECK: {
Leon Clarkee46be812010-01-19 14:06:41 +00001293 if (!function->IsBuiltin()) {
1294 // Calling non-builtins with a value as receiver requires boxing.
1295 __ jmp(&miss);
1296 } else {
1297 Label fast;
1298 // Check that the object is a boolean.
1299 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1300 __ cmp(r1, ip);
1301 __ b(eq, &fast);
1302 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1303 __ cmp(r1, ip);
1304 __ b(ne, &miss);
1305 __ bind(&fast);
1306 // Check that the maps starting from the prototype haven't changed.
1307 GenerateLoadGlobalFunctionPrototype(masm(),
1308 Context::BOOLEAN_FUNCTION_INDEX,
Andrei Popescu402d9372010-02-26 13:31:12 +00001309 r0);
1310 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001311 r1, name, &miss);
1312 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001313 break;
1314 }
1315
Steve Blocka7e24c12009-10-30 11:49:00 +00001316 default:
1317 UNREACHABLE();
1318 }
1319
Steve Block6ded16b2010-05-10 14:33:55 +01001320 if (depth != kInvalidProtoDepth) {
1321 GenerateFastApiCall(masm(), optimization, argc);
1322 } else {
1323 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1324 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001325
1326 // Handle call cache miss.
1327 __ bind(&miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001328 if (depth != kInvalidProtoDepth) {
1329 FreeSpaceForFastApiCall(masm());
1330 }
1331
1332 __ bind(&miss_in_smi_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001333 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1334 __ Jump(ic, RelocInfo::CODE_TARGET);
1335
1336 // Return the generated code.
1337 String* function_name = NULL;
1338 if (function->shared()->name()->IsString()) {
1339 function_name = String::cast(function->shared()->name());
1340 }
1341 return GetCode(CONSTANT_FUNCTION, function_name);
1342}
1343
1344
Andrei Popescu402d9372010-02-26 13:31:12 +00001345Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001346 JSObject* holder,
1347 String* name) {
1348 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001349 // -- r2 : name
1350 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001351 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001352
Steve Block6ded16b2010-05-10 14:33:55 +01001353 Label miss;
Andrei Popescu402d9372010-02-26 13:31:12 +00001354
Leon Clarke4515c472010-02-03 11:58:03 +00001355 // Get the number of arguments.
1356 const int argc = arguments().immediate();
1357
1358 LookupResult lookup;
1359 LookupPostInterceptor(holder, name, &lookup);
1360
Steve Block6ded16b2010-05-10 14:33:55 +01001361 // Get the receiver from the stack.
1362 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001363
Steve Block6ded16b2010-05-10 14:33:55 +01001364 CallInterceptorCompiler compiler(this, arguments(), r2);
1365 compiler.Compile(masm(),
1366 object,
1367 holder,
1368 name,
1369 &lookup,
1370 r1,
1371 r3,
1372 r4,
1373 &miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001374
1375 // Move returned value, the function to call, to r1.
1376 __ mov(r1, r0);
Leon Clarke4515c472010-02-03 11:58:03 +00001377 // Restore receiver.
Steve Block6ded16b2010-05-10 14:33:55 +01001378 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
Leon Clarke4515c472010-02-03 11:58:03 +00001379
1380 GenerateCallFunction(masm(), object, arguments(), &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001381
1382 // Handle call cache miss.
1383 __ bind(&miss);
1384 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1385 __ Jump(ic, RelocInfo::CODE_TARGET);
1386
1387 // Return the generated code.
1388 return GetCode(INTERCEPTOR, name);
1389}
1390
1391
1392Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1393 GlobalObject* holder,
1394 JSGlobalPropertyCell* cell,
1395 JSFunction* function,
1396 String* name) {
1397 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001398 // -- r2 : name
1399 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001400 // -----------------------------------
1401 Label miss;
1402
1403 // Get the number of arguments.
1404 const int argc = arguments().immediate();
1405
1406 // Get the receiver from the stack.
1407 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1408
1409 // If the object is the holder then we know that it's a global
1410 // object which can only happen for contextual calls. In this case,
1411 // the receiver cannot be a smi.
1412 if (object != holder) {
1413 __ tst(r0, Operand(kSmiTagMask));
1414 __ b(eq, &miss);
1415 }
1416
1417 // Check that the maps haven't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001418 CheckPrototypes(object, r0, holder, r3, r1, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001419
1420 // Get the value from the cell.
1421 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1422 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1423
1424 // Check that the cell contains the same function.
Leon Clarkee46be812010-01-19 14:06:41 +00001425 if (Heap::InNewSpace(function)) {
1426 // We can't embed a pointer to a function in new space so we have
1427 // to verify that the shared function info is unchanged. This has
1428 // the nice side effect that multiple closures based on the same
1429 // function can all use this call IC. Before we load through the
1430 // function, we have to verify that it still is a function.
1431 __ tst(r1, Operand(kSmiTagMask));
1432 __ b(eq, &miss);
1433 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1434 __ b(ne, &miss);
1435
1436 // Check the shared function info. Make sure it hasn't changed.
1437 __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
Andrei Popescu402d9372010-02-26 13:31:12 +00001438 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1439 __ cmp(r4, r3);
Leon Clarkee46be812010-01-19 14:06:41 +00001440 __ b(ne, &miss);
1441 } else {
1442 __ cmp(r1, Operand(Handle<JSFunction>(function)));
1443 __ b(ne, &miss);
1444 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001445
1446 // Patch the receiver on the stack with the global proxy if
1447 // necessary.
1448 if (object->IsGlobalObject()) {
1449 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
1450 __ str(r3, MemOperand(sp, argc * kPointerSize));
1451 }
1452
1453 // Setup the context (function already in r1).
1454 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1455
1456 // Jump to the cached code (tail call).
Steve Block6ded16b2010-05-10 14:33:55 +01001457 __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001458 ASSERT(function->is_compiled());
1459 Handle<Code> code(function->code());
1460 ParameterCount expected(function->shared()->formal_parameter_count());
1461 __ InvokeCode(code, expected, arguments(),
1462 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1463
1464 // Handle call cache miss.
1465 __ bind(&miss);
1466 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
1467 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1468 __ Jump(ic, RelocInfo::CODE_TARGET);
1469
1470 // Return the generated code.
1471 return GetCode(NORMAL, name);
1472}
1473
1474
1475Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1476 int index,
1477 Map* transition,
1478 String* name) {
1479 // ----------- S t a t e -------------
1480 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001481 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001482 // -- r2 : name
1483 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001484 // -----------------------------------
1485 Label miss;
1486
Steve Blocka7e24c12009-10-30 11:49:00 +00001487 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001488 object,
1489 index,
1490 transition,
Andrei Popescu402d9372010-02-26 13:31:12 +00001491 r1, r2, r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001492 &miss);
1493 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001494 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1495 __ Jump(ic, RelocInfo::CODE_TARGET);
1496
1497 // Return the generated code.
1498 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1499}
1500
1501
1502Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1503 AccessorInfo* callback,
1504 String* name) {
1505 // ----------- S t a t e -------------
1506 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001507 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001508 // -- r2 : name
1509 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001510 // -----------------------------------
1511 Label miss;
1512
Steve Blocka7e24c12009-10-30 11:49:00 +00001513 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001514 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001515 __ b(eq, &miss);
1516
1517 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001518 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1519 __ cmp(r3, Operand(Handle<Map>(object->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001520 __ b(ne, &miss);
1521
1522 // Perform global security token check if needed.
1523 if (object->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001524 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001525 }
1526
1527 // Stub never generated for non-global objects that require access
1528 // checks.
1529 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1530
Andrei Popescu402d9372010-02-26 13:31:12 +00001531 __ push(r1); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001532 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
Steve Block6ded16b2010-05-10 14:33:55 +01001533 __ Push(ip, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001534
1535 // Do tail-call to the runtime system.
1536 ExternalReference store_callback_property =
1537 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001538 __ TailCallExternalReference(store_callback_property, 4, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001539
1540 // Handle store cache miss.
1541 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001542 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1543 __ Jump(ic, RelocInfo::CODE_TARGET);
1544
1545 // Return the generated code.
1546 return GetCode(CALLBACKS, name);
1547}
1548
1549
1550Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1551 String* name) {
1552 // ----------- S t a t e -------------
1553 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001554 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001555 // -- r2 : name
1556 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001557 // -----------------------------------
1558 Label miss;
1559
Steve Blocka7e24c12009-10-30 11:49:00 +00001560 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +00001561 __ tst(r1, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001562 __ b(eq, &miss);
1563
1564 // Check that the map of the object hasn't changed.
Andrei Popescu402d9372010-02-26 13:31:12 +00001565 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1566 __ cmp(r3, Operand(Handle<Map>(receiver->map())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001567 __ b(ne, &miss);
1568
1569 // Perform global security token check if needed.
1570 if (receiver->IsJSGlobalProxy()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001571 __ CheckAccessGlobalProxy(r1, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001572 }
1573
Andrei Popescu402d9372010-02-26 13:31:12 +00001574 // Stub is never generated for non-global objects that require access
Steve Blocka7e24c12009-10-30 11:49:00 +00001575 // checks.
1576 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1577
Steve Block6ded16b2010-05-10 14:33:55 +01001578 __ Push(r1, r2, r0); // Receiver, name, value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001579
1580 // Do tail-call to the runtime system.
1581 ExternalReference store_ic_property =
1582 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
Steve Block6ded16b2010-05-10 14:33:55 +01001583 __ TailCallExternalReference(store_ic_property, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001584
1585 // Handle store cache miss.
1586 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001587 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1588 __ Jump(ic, RelocInfo::CODE_TARGET);
1589
1590 // Return the generated code.
1591 return GetCode(INTERCEPTOR, name);
1592}
1593
1594
1595Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1596 JSGlobalPropertyCell* cell,
1597 String* name) {
1598 // ----------- S t a t e -------------
1599 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001600 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001601 // -- r2 : name
1602 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001603 // -----------------------------------
1604 Label miss;
1605
1606 // Check that the map of the global has not changed.
Steve Blocka7e24c12009-10-30 11:49:00 +00001607 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1608 __ cmp(r3, Operand(Handle<Map>(object->map())));
1609 __ b(ne, &miss);
1610
1611 // Store the value in the cell.
1612 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
1613 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
1614
Andrei Popescu402d9372010-02-26 13:31:12 +00001615 __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001616 __ Ret();
1617
1618 // Handle store cache miss.
1619 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001620 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001621 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1622 __ Jump(ic, RelocInfo::CODE_TARGET);
1623
1624 // Return the generated code.
1625 return GetCode(NORMAL, name);
1626}
1627
1628
Steve Block6ded16b2010-05-10 14:33:55 +01001629Object* LoadStubCompiler::CompileLoadNonexistent(String* name,
1630 JSObject* object,
1631 JSObject* last) {
1632 // ----------- S t a t e -------------
1633 // -- r2 : name
1634 // -- lr : return address
1635 // -- [sp] : receiver
1636 // -----------------------------------
1637 Label miss;
1638
1639 // Load receiver.
1640 __ ldr(r0, MemOperand(sp, 0));
1641
1642 // Check that receiver is not a smi.
1643 __ tst(r0, Operand(kSmiTagMask));
1644 __ b(eq, &miss);
1645
1646 // Check the maps of the full prototype chain.
1647 CheckPrototypes(object, r0, last, r3, r1, name, &miss);
1648
1649 // If the last object in the prototype chain is a global object,
1650 // check that the global property cell is empty.
1651 if (last->IsGlobalObject()) {
1652 Object* cell = GenerateCheckPropertyCell(masm(),
1653 GlobalObject::cast(last),
1654 name,
1655 r1,
1656 &miss);
1657 if (cell->IsFailure()) return cell;
1658 }
1659
1660 // Return undefined if maps of the full prototype chain are still the
1661 // same and no global property with this name contains a value.
1662 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1663 __ Ret();
1664
1665 __ bind(&miss);
1666 GenerateLoadMiss(masm(), Code::LOAD_IC);
1667
1668 // Return the generated code.
1669 return GetCode(NONEXISTENT, Heap::empty_string());
1670}
1671
1672
Steve Blocka7e24c12009-10-30 11:49:00 +00001673Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1674 JSObject* holder,
1675 int index,
1676 String* name) {
1677 // ----------- S t a t e -------------
1678 // -- r2 : name
1679 // -- lr : return address
1680 // -- [sp] : receiver
1681 // -----------------------------------
1682 Label miss;
1683
1684 __ ldr(r0, MemOperand(sp, 0));
1685
1686 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
1687 __ bind(&miss);
1688 GenerateLoadMiss(masm(), Code::LOAD_IC);
1689
1690 // Return the generated code.
1691 return GetCode(FIELD, name);
1692}
1693
1694
Leon Clarkee46be812010-01-19 14:06:41 +00001695Object* LoadStubCompiler::CompileLoadCallback(String* name,
1696 JSObject* object,
Steve Blocka7e24c12009-10-30 11:49:00 +00001697 JSObject* holder,
Leon Clarkee46be812010-01-19 14:06:41 +00001698 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001699 // ----------- S t a t e -------------
1700 // -- r2 : name
1701 // -- lr : return address
1702 // -- [sp] : receiver
1703 // -----------------------------------
1704 Label miss;
1705
1706 __ ldr(r0, MemOperand(sp, 0));
Leon Clarkee46be812010-01-19 14:06:41 +00001707 Failure* failure = Failure::InternalError();
1708 bool success = GenerateLoadCallback(object, holder, r0, r2, r3, r1,
1709 callback, name, &miss, &failure);
1710 if (!success) return failure;
1711
Steve Blocka7e24c12009-10-30 11:49:00 +00001712 __ bind(&miss);
1713 GenerateLoadMiss(masm(), Code::LOAD_IC);
1714
1715 // Return the generated code.
1716 return GetCode(CALLBACKS, name);
1717}
1718
1719
1720Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1721 JSObject* holder,
1722 Object* value,
1723 String* name) {
1724 // ----------- S t a t e -------------
1725 // -- r2 : name
1726 // -- lr : return address
1727 // -- [sp] : receiver
1728 // -----------------------------------
1729 Label miss;
1730
1731 __ ldr(r0, MemOperand(sp, 0));
1732
1733 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
1734 __ bind(&miss);
1735 GenerateLoadMiss(masm(), Code::LOAD_IC);
1736
1737 // Return the generated code.
1738 return GetCode(CONSTANT_FUNCTION, name);
1739}
1740
1741
1742Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1743 JSObject* holder,
1744 String* name) {
1745 // ----------- S t a t e -------------
1746 // -- r2 : name
1747 // -- lr : return address
1748 // -- [sp] : receiver
1749 // -----------------------------------
1750 Label miss;
1751
1752 __ ldr(r0, MemOperand(sp, 0));
1753
1754 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001755 LookupPostInterceptor(holder, name, &lookup);
Steve Blocka7e24c12009-10-30 11:49:00 +00001756 GenerateLoadInterceptor(object,
1757 holder,
1758 &lookup,
1759 r0,
1760 r2,
1761 r3,
1762 r1,
1763 name,
1764 &miss);
1765 __ bind(&miss);
1766 GenerateLoadMiss(masm(), Code::LOAD_IC);
1767
1768 // Return the generated code.
1769 return GetCode(INTERCEPTOR, name);
1770}
1771
1772
1773Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1774 GlobalObject* holder,
1775 JSGlobalPropertyCell* cell,
1776 String* name,
1777 bool is_dont_delete) {
1778 // ----------- S t a t e -------------
1779 // -- r2 : name
1780 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001781 // -- r0 : receiver
1782 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001783 // -----------------------------------
1784 Label miss;
1785
Steve Blocka7e24c12009-10-30 11:49:00 +00001786 // If the object is the holder then we know that it's a global
1787 // object which can only happen for contextual calls. In this case,
1788 // the receiver cannot be a smi.
1789 if (object != holder) {
Steve Block6ded16b2010-05-10 14:33:55 +01001790 __ tst(r0, Operand(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001791 __ b(eq, &miss);
1792 }
1793
1794 // Check that the map of the global has not changed.
Steve Block6ded16b2010-05-10 14:33:55 +01001795 CheckPrototypes(object, r0, holder, r3, r4, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001796
1797 // Get the value from the cell.
1798 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
Steve Block6ded16b2010-05-10 14:33:55 +01001799 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001800
1801 // Check for deleted property if property can actually be deleted.
1802 if (!is_dont_delete) {
1803 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
Steve Block6ded16b2010-05-10 14:33:55 +01001804 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00001805 __ b(eq, &miss);
1806 }
1807
Steve Block6ded16b2010-05-10 14:33:55 +01001808 __ mov(r0, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001809 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1810 __ Ret();
1811
1812 __ bind(&miss);
1813 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1814 GenerateLoadMiss(masm(), Code::LOAD_IC);
1815
1816 // Return the generated code.
1817 return GetCode(NORMAL, name);
1818}
1819
1820
1821Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1822 JSObject* receiver,
1823 JSObject* holder,
1824 int index) {
1825 // ----------- S t a t e -------------
1826 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001827 // -- r0 : key
Steve Blocka7e24c12009-10-30 11:49:00 +00001828 // -- sp[0] : key
1829 // -- sp[4] : receiver
1830 // -----------------------------------
1831 Label miss;
1832
Steve Block6ded16b2010-05-10 14:33:55 +01001833 // Check the key is the cached one.
1834 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001835 __ b(ne, &miss);
1836
Steve Block6ded16b2010-05-10 14:33:55 +01001837 __ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
1838 GenerateLoadField(receiver, holder, r1, r2, r3, index, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001839 __ bind(&miss);
1840 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1841
1842 return GetCode(FIELD, name);
1843}
1844
1845
1846Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1847 JSObject* receiver,
1848 JSObject* holder,
1849 AccessorInfo* callback) {
1850 // ----------- S t a t e -------------
1851 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001852 // -- r0 : key
Steve Blocka7e24c12009-10-30 11:49:00 +00001853 // -- sp[0] : key
1854 // -- sp[4] : receiver
1855 // -----------------------------------
1856 Label miss;
1857
Steve Block6ded16b2010-05-10 14:33:55 +01001858 // Check the key is the cached one.
1859 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001860 __ b(ne, &miss);
1861
Leon Clarkee46be812010-01-19 14:06:41 +00001862 Failure* failure = Failure::InternalError();
Steve Block6ded16b2010-05-10 14:33:55 +01001863 __ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
1864 bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3,
Leon Clarkee46be812010-01-19 14:06:41 +00001865 callback, name, &miss, &failure);
1866 if (!success) return failure;
1867
Steve Blocka7e24c12009-10-30 11:49:00 +00001868 __ bind(&miss);
1869 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1870
1871 return GetCode(CALLBACKS, name);
1872}
1873
1874
1875Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1876 JSObject* receiver,
1877 JSObject* holder,
1878 Object* value) {
1879 // ----------- S t a t e -------------
1880 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001881 // -- r0 : key
Steve Blocka7e24c12009-10-30 11:49:00 +00001882 // -- sp[0] : key
1883 // -- sp[4] : receiver
1884 // -----------------------------------
1885 Label miss;
1886
Steve Block6ded16b2010-05-10 14:33:55 +01001887 // Check the key is the cached one.
1888 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001889 __ b(ne, &miss);
1890
Steve Block6ded16b2010-05-10 14:33:55 +01001891 __ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
1892 GenerateLoadConstant(receiver, holder, r1, r2, r3, value, name, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001893 __ bind(&miss);
1894 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1895
1896 // Return the generated code.
1897 return GetCode(CONSTANT_FUNCTION, name);
1898}
1899
1900
1901Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1902 JSObject* holder,
1903 String* name) {
1904 // ----------- S t a t e -------------
1905 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001906 // -- r0 : key
Steve Blocka7e24c12009-10-30 11:49:00 +00001907 // -- sp[0] : key
1908 // -- sp[4] : receiver
1909 // -----------------------------------
1910 Label miss;
1911
Steve Block6ded16b2010-05-10 14:33:55 +01001912 // Check the key is the cached one.
1913 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001914 __ b(ne, &miss);
1915
1916 LookupResult lookup;
Leon Clarke4515c472010-02-03 11:58:03 +00001917 LookupPostInterceptor(holder, name, &lookup);
Steve Block6ded16b2010-05-10 14:33:55 +01001918 __ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
Steve Blocka7e24c12009-10-30 11:49:00 +00001919 GenerateLoadInterceptor(receiver,
1920 holder,
1921 &lookup,
Steve Block6ded16b2010-05-10 14:33:55 +01001922 r1,
Steve Blocka7e24c12009-10-30 11:49:00 +00001923 r0,
1924 r2,
1925 r3,
Steve Blocka7e24c12009-10-30 11:49:00 +00001926 name,
1927 &miss);
1928 __ bind(&miss);
1929 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1930
1931 return GetCode(INTERCEPTOR, name);
1932}
1933
1934
1935Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1936 // ----------- S t a t e -------------
1937 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001938 // -- r0 : key
Steve Blocka7e24c12009-10-30 11:49:00 +00001939 // -- sp[0] : key
1940 // -- sp[4] : receiver
1941 // -----------------------------------
1942 Label miss;
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 __ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
1949 GenerateLoadArrayLength(masm(), r1, r2, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001950 __ bind(&miss);
1951 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1952
1953 return GetCode(CALLBACKS, name);
1954}
1955
1956
1957Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
1958 // ----------- S t a t e -------------
1959 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001960 // -- r0 : key
Steve Blocka7e24c12009-10-30 11:49:00 +00001961 // -- sp[0] : key
1962 // -- sp[4] : receiver
1963 // -----------------------------------
1964 Label miss;
1965 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1966
Steve Block6ded16b2010-05-10 14:33:55 +01001967 // Check the key is the cached one.
1968 __ cmp(r0, Operand(Handle<String>(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001969 __ b(ne, &miss);
1970
Steve Block6ded16b2010-05-10 14:33:55 +01001971 __ ldr(r1, MemOperand(sp, kPointerSize)); // Receiver.
1972 GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +00001973 __ bind(&miss);
1974 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1975
1976 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1977
1978 return GetCode(CALLBACKS, name);
1979}
1980
1981
1982// TODO(1224671): implement the fast case.
1983Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1984 // ----------- S t a t e -------------
1985 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001986 // -- r0 : key
Steve Blocka7e24c12009-10-30 11:49:00 +00001987 // -- sp[0] : key
1988 // -- sp[4] : receiver
1989 // -----------------------------------
1990 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1991
1992 return GetCode(CALLBACKS, name);
1993}
1994
1995
1996Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1997 int index,
1998 Map* transition,
1999 String* name) {
2000 // ----------- S t a t e -------------
2001 // -- r0 : value
2002 // -- r2 : name
2003 // -- lr : return address
2004 // -- [sp] : receiver
2005 // -----------------------------------
2006 Label miss;
2007
2008 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
2009
2010 // Check that the name has not changed.
2011 __ cmp(r2, Operand(Handle<String>(name)));
2012 __ b(ne, &miss);
2013
2014 // Load receiver from the stack.
2015 __ ldr(r3, MemOperand(sp));
2016 // r1 is used as scratch register, r3 and r2 might be clobbered.
2017 GenerateStoreField(masm(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002018 object,
2019 index,
2020 transition,
2021 r3, r2, r1,
2022 &miss);
2023 __ bind(&miss);
2024
2025 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
2026 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
2027 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
2028 __ Jump(ic, RelocInfo::CODE_TARGET);
2029
2030 // Return the generated code.
2031 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2032}
2033
2034
2035Object* ConstructStubCompiler::CompileConstructStub(
2036 SharedFunctionInfo* shared) {
2037 // ----------- S t a t e -------------
2038 // -- r0 : argc
2039 // -- r1 : constructor
2040 // -- lr : return address
2041 // -- [sp] : last argument
2042 // -----------------------------------
2043 Label generic_stub_call;
2044
2045 // Use r7 for holding undefined which is used in several places below.
2046 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
2047
2048#ifdef ENABLE_DEBUGGER_SUPPORT
2049 // Check to see whether there are any break points in the function code. If
2050 // there are jump to the generic constructor stub which calls the actual
2051 // code for the function thereby hitting the break points.
2052 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
2053 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
2054 __ cmp(r2, r7);
2055 __ b(ne, &generic_stub_call);
2056#endif
2057
2058 // Load the initial map and verify that it is in fact a map.
2059 // r1: constructor function
2060 // r7: undefined
2061 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
2062 __ tst(r2, Operand(kSmiTagMask));
2063 __ b(eq, &generic_stub_call);
2064 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
2065 __ b(ne, &generic_stub_call);
2066
2067#ifdef DEBUG
2068 // Cannot construct functions this way.
2069 // r0: argc
2070 // r1: constructor function
2071 // r2: initial map
2072 // r7: undefined
2073 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
2074 __ Check(ne, "Function constructed by construct stub.");
2075#endif
2076
2077 // Now allocate the JSObject in new space.
2078 // r0: argc
2079 // r1: constructor function
2080 // r2: initial map
2081 // r7: undefined
2082 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
2083 __ AllocateInNewSpace(r3,
2084 r4,
2085 r5,
2086 r6,
2087 &generic_stub_call,
2088 NO_ALLOCATION_FLAGS);
2089
2090 // Allocated the JSObject, now initialize the fields. Map is set to initial
2091 // map and properties and elements are set to empty fixed array.
2092 // r0: argc
2093 // r1: constructor function
2094 // r2: initial map
2095 // r3: object size (in words)
2096 // r4: JSObject (not tagged)
2097 // r7: undefined
2098 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
2099 __ mov(r5, r4);
2100 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
2101 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2102 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
2103 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2104 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
2105 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
2106
2107 // Calculate the location of the first argument. The stack contains only the
2108 // argc arguments.
2109 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
2110
2111 // Fill all the in-object properties with undefined.
2112 // r0: argc
2113 // r1: first argument
2114 // r3: object size (in words)
2115 // r4: JSObject (not tagged)
2116 // r5: First in-object property of JSObject (not tagged)
2117 // r7: undefined
2118 // Fill the initialized properties with a constant value or a passed argument
2119 // depending on the this.x = ...; assignment in the function.
2120 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2121 if (shared->IsThisPropertyAssignmentArgument(i)) {
2122 Label not_passed, next;
2123 // Check if the argument assigned to the property is actually passed.
2124 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2125 __ cmp(r0, Operand(arg_number));
2126 __ b(le, &not_passed);
2127 // Argument passed - find it on the stack.
2128 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
2129 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2130 __ b(&next);
2131 __ bind(&not_passed);
2132 // Set the property to undefined.
2133 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2134 __ bind(&next);
2135 } else {
2136 // Set the property to the constant value.
2137 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2138 __ mov(r2, Operand(constant));
2139 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
2140 }
2141 }
2142
2143 // Fill the unused in-object property fields with undefined.
2144 for (int i = shared->this_property_assignments_count();
2145 i < shared->CalculateInObjectProperties();
2146 i++) {
2147 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
2148 }
2149
2150 // r0: argc
2151 // r4: JSObject (not tagged)
2152 // Move argc to r1 and the JSObject to return to r0 and tag it.
2153 __ mov(r1, r0);
2154 __ mov(r0, r4);
2155 __ orr(r0, r0, Operand(kHeapObjectTag));
2156
2157 // r0: JSObject
2158 // r1: argc
2159 // Remove caller arguments and receiver from the stack and return.
2160 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
2161 __ add(sp, sp, Operand(kPointerSize));
2162 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
2163 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
2164 __ Jump(lr);
2165
2166 // Jump to the generic stub in case the specialized code cannot handle the
2167 // construction.
2168 __ bind(&generic_stub_call);
2169 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2170 Handle<Code> generic_construct_stub(code);
2171 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
2172
2173 // Return the generated code.
2174 return GetCode();
2175}
2176
2177
2178#undef __
2179
2180} } // namespace v8::internal