1 // 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
34 namespace v8 {
35 namespace internal {
36
37 #define __ ACCESS_MASM(masm)
38
39
ProbeTable(MacroAssembler * masm,Code::Flags flags,StubCache::Table table,Register name,Register offset)40 static void ProbeTable(MacroAssembler* masm,
41 Code::Flags flags,
42 StubCache::Table table,
43 Register name,
44 Register offset) {
45 ExternalReference key_offset(SCTableReference::keyReference(table));
46 ExternalReference value_offset(SCTableReference::valueReference(table));
47
48 Label miss;
49
50 // Save the offset on the stack.
51 __ push(offset);
52
53 // Check that the key in the entry matches the name.
54 __ mov(ip, Operand(key_offset));
55 __ ldr(ip, MemOperand(ip, offset, LSL, 1));
56 __ cmp(name, Operand(ip));
57 __ b(ne, &miss);
58
59 // Get the code entry from the cache.
60 __ mov(ip, Operand(value_offset));
61 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
62
63 // Check that the flags match what we're looking for.
64 __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
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
GenerateProbe(MacroAssembler * masm,Code::Flags flags,Register receiver,Register name,Register scratch,Register extra)84 void 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.
108 __ ldr(scratch, FieldMemOperand(name, String::kLengthOffset));
109 __ 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
GenerateLoadGlobalFunctionPrototype(MacroAssembler * masm,int index,Register prototype)135 void 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.
GenerateFastPropertyLoad(MacroAssembler * masm,Register dst,Register src,JSObject * holder,int index)156 void 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
GenerateLoadArrayLength(MacroAssembler * masm,Register receiver,Register scratch,Label * miss_label)174 void 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
192 // Generate code to check if an object is a string. If the object is
193 // a string, the map's instance type is left in the scratch1 register.
GenerateStringCheck(MacroAssembler * masm,Register receiver,Register scratch1,Register scratch2,Label * smi,Label * non_string_object)194 static void GenerateStringCheck(MacroAssembler* masm,
195 Register receiver,
196 Register scratch1,
197 Register scratch2,
198 Label* smi,
199 Label* non_string_object) {
200 // Check that the receiver isn't a smi.
201 __ tst(receiver, Operand(kSmiTagMask));
202 __ b(eq, smi);
203
204 // Check that the object is a string.
205 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
206 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
207 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
208 // The cast is to resolve the overload for the argument of 0x0.
209 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
210 __ b(ne, non_string_object);
211 }
212
213
214 // Generate code to load the length from a string object and return the length.
215 // If the receiver object is not a string or a wrapped string object the
216 // execution continues at the miss label. The register containing the
217 // receiver is potentially clobbered.
GenerateLoadStringLength2(MacroAssembler * masm,Register receiver,Register scratch1,Register scratch2,Label * miss)218 void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm,
219 Register receiver,
220 Register scratch1,
221 Register scratch2,
222 Label* miss) {
223 Label check_string, check_wrapper;
224
225 __ bind(&check_string);
226 // Check if the object is a string leaving the instance type in the
227 // scratch1 register.
228 GenerateStringCheck(masm, receiver, scratch1, scratch2,
229 miss, &check_wrapper);
230
231 // Load length directly from the string.
232 __ and_(scratch1, scratch1, Operand(kStringSizeMask));
233 __ add(scratch1, scratch1, Operand(String::kHashShift));
234 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
235 __ mov(r0, Operand(r0, LSR, scratch1));
236 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
237 __ Ret();
238
239 // Check if the object is a JSValue wrapper.
240 __ bind(&check_wrapper);
241 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
242 __ b(ne, miss);
243
244 // Unwrap the value in place and check if the wrapped value is a string.
245 __ ldr(receiver, FieldMemOperand(receiver, JSValue::kValueOffset));
246 __ b(&check_string);
247 }
248
249
GenerateLoadFunctionPrototype(MacroAssembler * masm,Register receiver,Register scratch1,Register scratch2,Label * miss_label)250 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
251 Register receiver,
252 Register scratch1,
253 Register scratch2,
254 Label* miss_label) {
255 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
256 __ mov(r0, scratch1);
257 __ Ret();
258 }
259
260
261 // Generate StoreField code, value is passed in r0 register.
262 // After executing generated code, the receiver_reg and name_reg
263 // may be clobbered.
GenerateStoreField(MacroAssembler * masm,Builtins::Name storage_extend,JSObject * object,int index,Map * transition,Register receiver_reg,Register name_reg,Register scratch,Label * miss_label)264 void StubCompiler::GenerateStoreField(MacroAssembler* masm,
265 Builtins::Name storage_extend,
266 JSObject* object,
267 int index,
268 Map* transition,
269 Register receiver_reg,
270 Register name_reg,
271 Register scratch,
272 Label* miss_label) {
273 // r0 : value
274 Label exit;
275
276 // Check that the receiver isn't a smi.
277 __ tst(receiver_reg, Operand(kSmiTagMask));
278 __ b(eq, miss_label);
279
280 // Check that the map of the receiver hasn't changed.
281 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
282 __ cmp(scratch, Operand(Handle<Map>(object->map())));
283 __ b(ne, miss_label);
284
285 // Perform global security token check if needed.
286 if (object->IsJSGlobalProxy()) {
287 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
288 }
289
290 // Stub never generated for non-global objects that require access
291 // checks.
292 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
293
294 // Perform map transition for the receiver if necessary.
295 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
296 // The properties must be extended before we can store the value.
297 // We jump to a runtime call that extends the properties array.
298 __ mov(r2, Operand(Handle<Map>(transition)));
299 // Please note, if we implement keyed store for arm we need
300 // to call the Builtins::KeyedStoreIC_ExtendStorage.
301 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
302 __ Jump(ic, RelocInfo::CODE_TARGET);
303 return;
304 }
305
306 if (transition != NULL) {
307 // Update the map of the object; no write barrier updating is
308 // needed because the map is never in new space.
309 __ mov(ip, Operand(Handle<Map>(transition)));
310 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
311 }
312
313 // Adjust for the number of properties stored in the object. Even in the
314 // face of a transition we can use the old map here because the size of the
315 // object and the number of in-object properties is not going to change.
316 index -= object->map()->inobject_properties();
317
318 if (index < 0) {
319 // Set the property straight into the object.
320 int offset = object->map()->instance_size() + (index * kPointerSize);
321 __ str(r0, FieldMemOperand(receiver_reg, offset));
322
323 // Skip updating write barrier if storing a smi.
324 __ tst(r0, Operand(kSmiTagMask));
325 __ b(eq, &exit);
326
327 // Update the write barrier for the array address.
328 // Pass the value being stored in the now unused name_reg.
329 __ mov(name_reg, Operand(offset));
330 __ RecordWrite(receiver_reg, name_reg, scratch);
331 } else {
332 // Write to the properties array.
333 int offset = index * kPointerSize + FixedArray::kHeaderSize;
334 // Get the properties array
335 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
336 __ str(r0, FieldMemOperand(scratch, offset));
337
338 // Skip updating write barrier if storing a smi.
339 __ tst(r0, Operand(kSmiTagMask));
340 __ b(eq, &exit);
341
342 // Update the write barrier for the array address.
343 // Ok to clobber receiver_reg and name_reg, since we return.
344 __ mov(name_reg, Operand(offset));
345 __ RecordWrite(scratch, name_reg, receiver_reg);
346 }
347
348 // Return the value (register r0).
349 __ bind(&exit);
350 __ Ret();
351 }
352
353
GenerateLoadMiss(MacroAssembler * masm,Code::Kind kind)354 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
355 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
356 Code* code = NULL;
357 if (kind == Code::LOAD_IC) {
358 code = Builtins::builtin(Builtins::LoadIC_Miss);
359 } else {
360 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
361 }
362
363 Handle<Code> ic(code);
364 __ Jump(ic, RelocInfo::CODE_TARGET);
365 }
366
367
368 #undef __
369 #define __ ACCESS_MASM(masm())
370
371
CheckPrototypes(JSObject * object,Register object_reg,JSObject * holder,Register holder_reg,Register scratch,String * name,Label * miss)372 Register StubCompiler::CheckPrototypes(JSObject* object,
373 Register object_reg,
374 JSObject* holder,
375 Register holder_reg,
376 Register scratch,
377 String* name,
378 Label* miss) {
379 // Check that the maps haven't changed.
380 Register result =
381 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
382
383 // If we've skipped any global objects, it's not enough to verify
384 // that their maps haven't changed.
385 while (object != holder) {
386 if (object->IsGlobalObject()) {
387 GlobalObject* global = GlobalObject::cast(object);
388 Object* probe = global->EnsurePropertyCell(name);
389 if (probe->IsFailure()) {
390 set_failure(Failure::cast(probe));
391 return result;
392 }
393 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
394 ASSERT(cell->value()->IsTheHole());
395 __ mov(scratch, Operand(Handle<Object>(cell)));
396 __ ldr(scratch,
397 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
398 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
399 __ cmp(scratch, ip);
400 __ b(ne, miss);
401 }
402 object = JSObject::cast(object->GetPrototype());
403 }
404
405 // Return the register containin the holder.
406 return result;
407 }
408
409
GenerateLoadField(JSObject * object,JSObject * holder,Register receiver,Register scratch1,Register scratch2,int index,String * name,Label * miss)410 void StubCompiler::GenerateLoadField(JSObject* object,
411 JSObject* holder,
412 Register receiver,
413 Register scratch1,
414 Register scratch2,
415 int index,
416 String* name,
417 Label* miss) {
418 // Check that the receiver isn't a smi.
419 __ tst(receiver, Operand(kSmiTagMask));
420 __ b(eq, miss);
421
422 // Check that the maps haven't changed.
423 Register reg =
424 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
425 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
426 __ Ret();
427 }
428
429
GenerateLoadConstant(JSObject * object,JSObject * holder,Register receiver,Register scratch1,Register scratch2,Object * value,String * name,Label * miss)430 void StubCompiler::GenerateLoadConstant(JSObject* object,
431 JSObject* holder,
432 Register receiver,
433 Register scratch1,
434 Register scratch2,
435 Object* value,
436 String* name,
437 Label* miss) {
438 // Check that the receiver isn't a smi.
439 __ tst(receiver, Operand(kSmiTagMask));
440 __ b(eq, miss);
441
442 // Check that the maps haven't changed.
443 Register reg =
444 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
445
446 // Return the constant value.
447 __ mov(r0, Operand(Handle<Object>(value)));
448 __ Ret();
449 }
450
451
GenerateLoadCallback(JSObject * object,JSObject * holder,Register receiver,Register name_reg,Register scratch1,Register scratch2,AccessorInfo * callback,String * name,Label * miss)452 void StubCompiler::GenerateLoadCallback(JSObject* object,
453 JSObject* holder,
454 Register receiver,
455 Register name_reg,
456 Register scratch1,
457 Register scratch2,
458 AccessorInfo* callback,
459 String* name,
460 Label* miss) {
461 // Check that the receiver isn't a smi.
462 __ tst(receiver, Operand(kSmiTagMask));
463 __ b(eq, miss);
464
465 // Check that the maps haven't changed.
466 Register reg =
467 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
468
469 // Push the arguments on the JS stack of the caller.
470 __ push(receiver); // receiver
471 __ push(reg); // holder
472 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
473 __ push(ip);
474 __ ldr(reg, FieldMemOperand(ip, AccessorInfo::kDataOffset));
475 __ push(reg);
476 __ push(name_reg); // name
477
478 // Do tail-call to the runtime system.
479 ExternalReference load_callback_property =
480 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
481 __ TailCallRuntime(load_callback_property, 5);
482 }
483
484
GenerateLoadInterceptor(JSObject * object,JSObject * holder,LookupResult * lookup,Register receiver,Register name_reg,Register scratch1,Register scratch2,String * name,Label * miss)485 void StubCompiler::GenerateLoadInterceptor(JSObject* object,
486 JSObject* holder,
487 LookupResult* lookup,
488 Register receiver,
489 Register name_reg,
490 Register scratch1,
491 Register scratch2,
492 String* name,
493 Label* miss) {
494 // Check that the receiver isn't a smi.
495 __ tst(receiver, Operand(kSmiTagMask));
496 __ b(eq, miss);
497
498 // Check that the maps haven't changed.
499 Register reg =
500 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
501
502 // Push the arguments on the JS stack of the caller.
503 __ push(receiver); // receiver
504 __ push(reg); // holder
505 __ push(name_reg); // name
506
507 InterceptorInfo* interceptor = holder->GetNamedInterceptor();
508 ASSERT(!Heap::InNewSpace(interceptor));
509 __ mov(scratch1, Operand(Handle<Object>(interceptor)));
510 __ push(scratch1);
511 __ ldr(scratch2, FieldMemOperand(scratch1, InterceptorInfo::kDataOffset));
512 __ push(scratch2);
513
514 // Do tail-call to the runtime system.
515 ExternalReference load_ic_property =
516 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
517 __ TailCallRuntime(load_ic_property, 5);
518 }
519
520
CompileLazyCompile(Code::Flags flags)521 Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
522 // ----------- S t a t e -------------
523 // -- r1: function
524 // -- lr: return address
525 // -----------------------------------
526
527 // Enter an internal frame.
528 __ EnterInternalFrame();
529
530 // Preserve the function.
531 __ push(r1);
532
533 // Push the function on the stack as the argument to the runtime function.
534 __ push(r1);
535 __ CallRuntime(Runtime::kLazyCompile, 1);
536
537 // Calculate the entry point.
538 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
539
540 // Restore saved function.
541 __ pop(r1);
542
543 // Tear down temporary frame.
544 __ LeaveInternalFrame();
545
546 // Do a tail-call of the compiled function.
547 __ Jump(r2);
548
549 return GetCodeWithFlags(flags, "LazyCompileStub");
550 }
551
552
CompileCallField(Object * object,JSObject * holder,int index,String * name)553 Object* CallStubCompiler::CompileCallField(Object* object,
554 JSObject* holder,
555 int index,
556 String* name) {
557 // ----------- S t a t e -------------
558 // -- lr: return address
559 // -----------------------------------
560 Label miss;
561
562 const int argc = arguments().immediate();
563
564 // Get the receiver of the function from the stack into r0.
565 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
566 // Check that the receiver isn't a smi.
567 __ tst(r0, Operand(kSmiTagMask));
568 __ b(eq, &miss);
569
570 // Do the right check and compute the holder register.
571 Register reg =
572 CheckPrototypes(JSObject::cast(object), r0, holder, r3, r2, name, &miss);
573 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
574
575 // Check that the function really is a function.
576 __ tst(r1, Operand(kSmiTagMask));
577 __ b(eq, &miss);
578 // Get the map.
579 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
580 __ b(ne, &miss);
581
582 // Patch the receiver on the stack with the global proxy if
583 // necessary.
584 if (object->IsGlobalObject()) {
585 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
586 __ str(r3, MemOperand(sp, argc * kPointerSize));
587 }
588
589 // Invoke the function.
590 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
591
592 // Handle call cache miss.
593 __ bind(&miss);
594 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
595 __ Jump(ic, RelocInfo::CODE_TARGET);
596
597 // Return the generated code.
598 return GetCode(FIELD, name);
599 }
600
601
CompileCallConstant(Object * object,JSObject * holder,JSFunction * function,String * name,CheckType check)602 Object* CallStubCompiler::CompileCallConstant(Object* object,
603 JSObject* holder,
604 JSFunction* function,
605 String* name,
606 CheckType check) {
607 // ----------- S t a t e -------------
608 // -- lr: return address
609 // -----------------------------------
610 Label miss;
611
612 // Get the receiver from the stack
613 const int argc = arguments().immediate();
614 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
615
616 // Check that the receiver isn't a smi.
617 if (check != NUMBER_CHECK) {
618 __ tst(r1, Operand(kSmiTagMask));
619 __ b(eq, &miss);
620 }
621
622 // Make sure that it's okay not to patch the on stack receiver
623 // unless we're doing a receiver map check.
624 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
625
626 switch (check) {
627 case RECEIVER_MAP_CHECK:
628 // Check that the maps haven't changed.
629 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
630
631 // Patch the receiver on the stack with the global proxy if
632 // necessary.
633 if (object->IsGlobalObject()) {
634 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
635 __ str(r3, MemOperand(sp, argc * kPointerSize));
636 }
637 break;
638
639 case STRING_CHECK:
640 // Check that the object is a two-byte string or a symbol.
641 __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
642 __ b(hs, &miss);
643 // Check that the maps starting from the prototype haven't changed.
644 GenerateLoadGlobalFunctionPrototype(masm(),
645 Context::STRING_FUNCTION_INDEX,
646 r2);
647 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
648 r1, name, &miss);
649 break;
650
651 case NUMBER_CHECK: {
652 Label fast;
653 // Check that the object is a smi or a heap number.
654 __ tst(r1, Operand(kSmiTagMask));
655 __ b(eq, &fast);
656 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
657 __ b(ne, &miss);
658 __ bind(&fast);
659 // Check that the maps starting from the prototype haven't changed.
660 GenerateLoadGlobalFunctionPrototype(masm(),
661 Context::NUMBER_FUNCTION_INDEX,
662 r2);
663 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
664 r1, name, &miss);
665 break;
666 }
667
668 case BOOLEAN_CHECK: {
669 Label fast;
670 // Check that the object is a boolean.
671 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
672 __ cmp(r1, ip);
673 __ b(eq, &fast);
674 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
675 __ cmp(r1, ip);
676 __ b(ne, &miss);
677 __ bind(&fast);
678 // Check that the maps starting from the prototype haven't changed.
679 GenerateLoadGlobalFunctionPrototype(masm(),
680 Context::BOOLEAN_FUNCTION_INDEX,
681 r2);
682 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
683 r1, name, &miss);
684 break;
685 }
686
687 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
688 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
689 // Make sure object->HasFastElements().
690 // Get the elements array of the object.
691 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
692 // Check that the object is in fast mode (not dictionary).
693 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
694 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
695 __ cmp(r2, ip);
696 __ b(ne, &miss);
697 break;
698
699 default:
700 UNREACHABLE();
701 }
702
703 // Get the function and setup the context.
704 __ mov(r1, Operand(Handle<JSFunction>(function)));
705 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
706
707 // Jump to the cached code (tail call).
708 ASSERT(function->is_compiled());
709 Handle<Code> code(function->code());
710 ParameterCount expected(function->shared()->formal_parameter_count());
711 __ InvokeCode(code, expected, arguments(),
712 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
713
714 // Handle call cache miss.
715 __ bind(&miss);
716 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
717 __ Jump(ic, RelocInfo::CODE_TARGET);
718
719 // Return the generated code.
720 String* function_name = NULL;
721 if (function->shared()->name()->IsString()) {
722 function_name = String::cast(function->shared()->name());
723 }
724 return GetCode(CONSTANT_FUNCTION, function_name);
725 }
726
727
CompileCallInterceptor(Object * object,JSObject * holder,String * name)728 Object* CallStubCompiler::CompileCallInterceptor(Object* object,
729 JSObject* holder,
730 String* name) {
731 // ----------- S t a t e -------------
732 // -- lr: return address
733 // -----------------------------------
734 Label miss;
735
736 // TODO(1224669): Implement.
737
738 // Handle call cache miss.
739 __ bind(&miss);
740 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
741 __ Jump(ic, RelocInfo::CODE_TARGET);
742
743 // Return the generated code.
744 return GetCode(INTERCEPTOR, name);
745 }
746
747
CompileCallGlobal(JSObject * object,GlobalObject * holder,JSGlobalPropertyCell * cell,JSFunction * function,String * name)748 Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
749 GlobalObject* holder,
750 JSGlobalPropertyCell* cell,
751 JSFunction* function,
752 String* name) {
753 // ----------- S t a t e -------------
754 // -- lr: return address
755 // -----------------------------------
756 Label miss;
757
758 // Get the number of arguments.
759 const int argc = arguments().immediate();
760
761 // Get the receiver from the stack.
762 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
763
764 // If the object is the holder then we know that it's a global
765 // object which can only happen for contextual calls. In this case,
766 // the receiver cannot be a smi.
767 if (object != holder) {
768 __ tst(r0, Operand(kSmiTagMask));
769 __ b(eq, &miss);
770 }
771
772 // Check that the maps haven't changed.
773 CheckPrototypes(object, r0, holder, r3, r2, name, &miss);
774
775 // Get the value from the cell.
776 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
777 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
778
779 // Check that the cell contains the same function.
780 __ cmp(r1, Operand(Handle<JSFunction>(function)));
781 __ b(ne, &miss);
782
783 // Patch the receiver on the stack with the global proxy if
784 // necessary.
785 if (object->IsGlobalObject()) {
786 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
787 __ str(r3, MemOperand(sp, argc * kPointerSize));
788 }
789
790 // Setup the context (function already in r1).
791 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
792
793 // Jump to the cached code (tail call).
794 __ IncrementCounter(&Counters::call_global_inline, 1, r2, r3);
795 ASSERT(function->is_compiled());
796 Handle<Code> code(function->code());
797 ParameterCount expected(function->shared()->formal_parameter_count());
798 __ InvokeCode(code, expected, arguments(),
799 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
800
801 // Handle call cache miss.
802 __ bind(&miss);
803 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
804 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
805 __ Jump(ic, RelocInfo::CODE_TARGET);
806
807 // Return the generated code.
808 return GetCode(NORMAL, name);
809 }
810
811
CompileStoreField(JSObject * object,int index,Map * transition,String * name)812 Object* StoreStubCompiler::CompileStoreField(JSObject* object,
813 int index,
814 Map* transition,
815 String* name) {
816 // ----------- S t a t e -------------
817 // -- r0 : value
818 // -- r2 : name
819 // -- lr : return address
820 // -- [sp] : receiver
821 // -----------------------------------
822 Label miss;
823
824 // Get the receiver from the stack.
825 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
826
827 // name register might be clobbered.
828 GenerateStoreField(masm(),
829 Builtins::StoreIC_ExtendStorage,
830 object,
831 index,
832 transition,
833 r3, r2, r1,
834 &miss);
835 __ bind(&miss);
836 __ mov(r2, Operand(Handle<String>(name))); // restore name
837 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
838 __ Jump(ic, RelocInfo::CODE_TARGET);
839
840 // Return the generated code.
841 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
842 }
843
844
CompileStoreCallback(JSObject * object,AccessorInfo * callback,String * name)845 Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
846 AccessorInfo* callback,
847 String* name) {
848 // ----------- S t a t e -------------
849 // -- r0 : value
850 // -- r2 : name
851 // -- lr : return address
852 // -- [sp] : receiver
853 // -----------------------------------
854 Label miss;
855
856 // Get the object from the stack.
857 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
858
859 // Check that the object isn't a smi.
860 __ tst(r3, Operand(kSmiTagMask));
861 __ b(eq, &miss);
862
863 // Check that the map of the object hasn't changed.
864 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
865 __ cmp(r1, Operand(Handle<Map>(object->map())));
866 __ b(ne, &miss);
867
868 // Perform global security token check if needed.
869 if (object->IsJSGlobalProxy()) {
870 __ CheckAccessGlobalProxy(r3, r1, &miss);
871 }
872
873 // Stub never generated for non-global objects that require access
874 // checks.
875 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
876
877 __ ldr(ip, MemOperand(sp)); // receiver
878 __ push(ip);
879 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
880 __ push(ip);
881 __ push(r2); // name
882 __ push(r0); // value
883
884 // Do tail-call to the runtime system.
885 ExternalReference store_callback_property =
886 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
887 __ TailCallRuntime(store_callback_property, 4);
888
889 // Handle store cache miss.
890 __ bind(&miss);
891 __ mov(r2, Operand(Handle<String>(name))); // restore name
892 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
893 __ Jump(ic, RelocInfo::CODE_TARGET);
894
895 // Return the generated code.
896 return GetCode(CALLBACKS, name);
897 }
898
899
CompileStoreInterceptor(JSObject * receiver,String * name)900 Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
901 String* name) {
902 // ----------- S t a t e -------------
903 // -- r0 : value
904 // -- r2 : name
905 // -- lr : return address
906 // -- [sp] : receiver
907 // -----------------------------------
908 Label miss;
909
910 // Get the object from the stack.
911 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
912
913 // Check that the object isn't a smi.
914 __ tst(r3, Operand(kSmiTagMask));
915 __ b(eq, &miss);
916
917 // Check that the map of the object hasn't changed.
918 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
919 __ cmp(r1, Operand(Handle<Map>(receiver->map())));
920 __ b(ne, &miss);
921
922 // Perform global security token check if needed.
923 if (receiver->IsJSGlobalProxy()) {
924 __ CheckAccessGlobalProxy(r3, r1, &miss);
925 }
926
927 // Stub never generated for non-global objects that require access
928 // checks.
929 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
930
931 __ ldr(ip, MemOperand(sp)); // receiver
932 __ push(ip);
933 __ push(r2); // name
934 __ push(r0); // value
935
936 // Do tail-call to the runtime system.
937 ExternalReference store_ic_property =
938 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
939 __ TailCallRuntime(store_ic_property, 3);
940
941 // Handle store cache miss.
942 __ bind(&miss);
943 __ mov(r2, Operand(Handle<String>(name))); // restore name
944 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
945 __ Jump(ic, RelocInfo::CODE_TARGET);
946
947 // Return the generated code.
948 return GetCode(INTERCEPTOR, name);
949 }
950
951
CompileStoreGlobal(GlobalObject * object,JSGlobalPropertyCell * cell,String * name)952 Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
953 JSGlobalPropertyCell* cell,
954 String* name) {
955 // ----------- S t a t e -------------
956 // -- r0 : value
957 // -- r2 : name
958 // -- lr : return address
959 // -- [sp] : receiver
960 // -----------------------------------
961 Label miss;
962
963 // Check that the map of the global has not changed.
964 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
965 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
966 __ cmp(r3, Operand(Handle<Map>(object->map())));
967 __ b(ne, &miss);
968
969 // Store the value in the cell.
970 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
971 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
972
973 __ IncrementCounter(&Counters::named_store_global_inline, 1, r1, r3);
974 __ Ret();
975
976 // Handle store cache miss.
977 __ bind(&miss);
978 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r1, r3);
979 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
980 __ Jump(ic, RelocInfo::CODE_TARGET);
981
982 // Return the generated code.
983 return GetCode(NORMAL, name);
984 }
985
986
CompileLoadField(JSObject * object,JSObject * holder,int index,String * name)987 Object* LoadStubCompiler::CompileLoadField(JSObject* object,
988 JSObject* holder,
989 int index,
990 String* name) {
991 // ----------- S t a t e -------------
992 // -- r2 : name
993 // -- lr : return address
994 // -- [sp] : receiver
995 // -----------------------------------
996 Label miss;
997
998 __ ldr(r0, MemOperand(sp, 0));
999
1000 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
1001 __ bind(&miss);
1002 GenerateLoadMiss(masm(), Code::LOAD_IC);
1003
1004 // Return the generated code.
1005 return GetCode(FIELD, name);
1006 }
1007
1008
CompileLoadCallback(JSObject * object,JSObject * holder,AccessorInfo * callback,String * name)1009 Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
1010 JSObject* holder,
1011 AccessorInfo* callback,
1012 String* name) {
1013 // ----------- S t a t e -------------
1014 // -- r2 : name
1015 // -- lr : return address
1016 // -- [sp] : receiver
1017 // -----------------------------------
1018 Label miss;
1019
1020 __ ldr(r0, MemOperand(sp, 0));
1021 GenerateLoadCallback(object, holder, r0, r2, r3, r1, callback, name, &miss);
1022 __ bind(&miss);
1023 GenerateLoadMiss(masm(), Code::LOAD_IC);
1024
1025 // Return the generated code.
1026 return GetCode(CALLBACKS, name);
1027 }
1028
1029
CompileLoadConstant(JSObject * object,JSObject * holder,Object * value,String * name)1030 Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1031 JSObject* holder,
1032 Object* value,
1033 String* name) {
1034 // ----------- S t a t e -------------
1035 // -- r2 : name
1036 // -- lr : return address
1037 // -- [sp] : receiver
1038 // -----------------------------------
1039 Label miss;
1040
1041 __ ldr(r0, MemOperand(sp, 0));
1042
1043 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
1044 __ bind(&miss);
1045 GenerateLoadMiss(masm(), Code::LOAD_IC);
1046
1047 // Return the generated code.
1048 return GetCode(CONSTANT_FUNCTION, name);
1049 }
1050
1051
CompileLoadInterceptor(JSObject * object,JSObject * holder,String * name)1052 Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1053 JSObject* holder,
1054 String* name) {
1055 // ----------- S t a t e -------------
1056 // -- r2 : name
1057 // -- lr : return address
1058 // -- [sp] : receiver
1059 // -----------------------------------
1060 Label miss;
1061
1062 __ ldr(r0, MemOperand(sp, 0));
1063
1064 LookupResult lookup;
1065 holder->LocalLookupRealNamedProperty(name, &lookup);
1066 GenerateLoadInterceptor(object,
1067 holder,
1068 &lookup,
1069 r0,
1070 r2,
1071 r3,
1072 r1,
1073 name,
1074 &miss);
1075 __ bind(&miss);
1076 GenerateLoadMiss(masm(), Code::LOAD_IC);
1077
1078 // Return the generated code.
1079 return GetCode(INTERCEPTOR, name);
1080 }
1081
1082
CompileLoadGlobal(JSObject * object,GlobalObject * holder,JSGlobalPropertyCell * cell,String * name,bool is_dont_delete)1083 Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1084 GlobalObject* holder,
1085 JSGlobalPropertyCell* cell,
1086 String* name,
1087 bool is_dont_delete) {
1088 // ----------- S t a t e -------------
1089 // -- r2 : name
1090 // -- lr : return address
1091 // -- [sp] : receiver
1092 // -----------------------------------
1093 Label miss;
1094
1095 // Get the receiver from the stack.
1096 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
1097
1098 // If the object is the holder then we know that it's a global
1099 // object which can only happen for contextual calls. In this case,
1100 // the receiver cannot be a smi.
1101 if (object != holder) {
1102 __ tst(r1, Operand(kSmiTagMask));
1103 __ b(eq, &miss);
1104 }
1105
1106 // Check that the map of the global has not changed.
1107 CheckPrototypes(object, r1, holder, r3, r0, name, &miss);
1108
1109 // Get the value from the cell.
1110 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1111 __ ldr(r0, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1112
1113 // Check for deleted property if property can actually be deleted.
1114 if (!is_dont_delete) {
1115 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1116 __ cmp(r0, ip);
1117 __ b(eq, &miss);
1118 }
1119
1120 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1121 __ Ret();
1122
1123 __ bind(&miss);
1124 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1125 GenerateLoadMiss(masm(), Code::LOAD_IC);
1126
1127 // Return the generated code.
1128 return GetCode(NORMAL, name);
1129 }
1130
1131
CompileLoadField(String * name,JSObject * receiver,JSObject * holder,int index)1132 Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1133 JSObject* receiver,
1134 JSObject* holder,
1135 int index) {
1136 // ----------- S t a t e -------------
1137 // -- lr : return address
1138 // -- sp[0] : key
1139 // -- sp[4] : receiver
1140 // -----------------------------------
1141 Label miss;
1142
1143 __ ldr(r2, MemOperand(sp, 0));
1144 __ ldr(r0, MemOperand(sp, kPointerSize));
1145
1146 __ cmp(r2, Operand(Handle<String>(name)));
1147 __ b(ne, &miss);
1148
1149 GenerateLoadField(receiver, holder, r0, r3, r1, index, name, &miss);
1150 __ bind(&miss);
1151 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1152
1153 return GetCode(FIELD, name);
1154 }
1155
1156
CompileLoadCallback(String * name,JSObject * receiver,JSObject * holder,AccessorInfo * callback)1157 Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1158 JSObject* receiver,
1159 JSObject* holder,
1160 AccessorInfo* callback) {
1161 // ----------- S t a t e -------------
1162 // -- lr : return address
1163 // -- sp[0] : key
1164 // -- sp[4] : receiver
1165 // -----------------------------------
1166 Label miss;
1167
1168 __ ldr(r2, MemOperand(sp, 0));
1169 __ ldr(r0, MemOperand(sp, kPointerSize));
1170
1171 __ cmp(r2, Operand(Handle<String>(name)));
1172 __ b(ne, &miss);
1173
1174 GenerateLoadCallback(receiver, holder, r0, r2, r3, r1, callback, name, &miss);
1175 __ bind(&miss);
1176 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1177
1178 return GetCode(CALLBACKS, name);
1179 }
1180
1181
CompileLoadConstant(String * name,JSObject * receiver,JSObject * holder,Object * value)1182 Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1183 JSObject* receiver,
1184 JSObject* holder,
1185 Object* value) {
1186 // ----------- S t a t e -------------
1187 // -- lr : return address
1188 // -- sp[0] : key
1189 // -- sp[4] : receiver
1190 // -----------------------------------
1191 Label miss;
1192
1193 // Check the key is the cached one
1194 __ ldr(r2, MemOperand(sp, 0));
1195 __ ldr(r0, MemOperand(sp, kPointerSize));
1196
1197 __ cmp(r2, Operand(Handle<String>(name)));
1198 __ b(ne, &miss);
1199
1200 GenerateLoadConstant(receiver, holder, r0, r3, r1, value, name, &miss);
1201 __ bind(&miss);
1202 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1203
1204 // Return the generated code.
1205 return GetCode(CONSTANT_FUNCTION, name);
1206 }
1207
1208
CompileLoadInterceptor(JSObject * receiver,JSObject * holder,String * name)1209 Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1210 JSObject* holder,
1211 String* name) {
1212 // ----------- S t a t e -------------
1213 // -- lr : return address
1214 // -- sp[0] : key
1215 // -- sp[4] : receiver
1216 // -----------------------------------
1217 Label miss;
1218
1219 // Check the key is the cached one
1220 __ ldr(r2, MemOperand(sp, 0));
1221 __ ldr(r0, MemOperand(sp, kPointerSize));
1222
1223 __ cmp(r2, Operand(Handle<String>(name)));
1224 __ b(ne, &miss);
1225
1226 LookupResult lookup;
1227 holder->LocalLookupRealNamedProperty(name, &lookup);
1228 GenerateLoadInterceptor(receiver,
1229 holder,
1230 &lookup,
1231 r0,
1232 r2,
1233 r3,
1234 r1,
1235 name,
1236 &miss);
1237 __ bind(&miss);
1238 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1239
1240 return GetCode(INTERCEPTOR, name);
1241 }
1242
1243
CompileLoadArrayLength(String * name)1244 Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1245 // ----------- S t a t e -------------
1246 // -- lr : return address
1247 // -- sp[0] : key
1248 // -- sp[4] : receiver
1249 // -----------------------------------
1250 Label miss;
1251
1252 // Check the key is the cached one
1253 __ ldr(r2, MemOperand(sp, 0));
1254 __ ldr(r0, MemOperand(sp, kPointerSize));
1255
1256 __ cmp(r2, Operand(Handle<String>(name)));
1257 __ b(ne, &miss);
1258
1259 GenerateLoadArrayLength(masm(), r0, r3, &miss);
1260 __ bind(&miss);
1261 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1262
1263 return GetCode(CALLBACKS, name);
1264 }
1265
1266
CompileLoadStringLength(String * name)1267 Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
1268 // ----------- S t a t e -------------
1269 // -- lr : return address
1270 // -- sp[0] : key
1271 // -- sp[4] : receiver
1272 // -----------------------------------
1273 Label miss;
1274 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1275
1276 __ ldr(r2, MemOperand(sp));
1277 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver
1278
1279 __ cmp(r2, Operand(Handle<String>(name)));
1280 __ b(ne, &miss);
1281
1282 GenerateLoadStringLength2(masm(), r0, r1, r3, &miss);
1283 __ bind(&miss);
1284 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1285
1286 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1287
1288 return GetCode(CALLBACKS, name);
1289 }
1290
1291
1292 // TODO(1224671): implement the fast case.
CompileLoadFunctionPrototype(String * name)1293 Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1294 // ----------- S t a t e -------------
1295 // -- lr : return address
1296 // -- sp[0] : key
1297 // -- sp[4] : receiver
1298 // -----------------------------------
1299 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1300
1301 return GetCode(CALLBACKS, name);
1302 }
1303
1304
CompileStoreField(JSObject * object,int index,Map * transition,String * name)1305 Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1306 int index,
1307 Map* transition,
1308 String* name) {
1309 // ----------- S t a t e -------------
1310 // -- r0 : value
1311 // -- r2 : name
1312 // -- lr : return address
1313 // -- [sp] : receiver
1314 // -----------------------------------
1315 Label miss;
1316
1317 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1318
1319 // Check that the name has not changed.
1320 __ cmp(r2, Operand(Handle<String>(name)));
1321 __ b(ne, &miss);
1322
1323 // Load receiver from the stack.
1324 __ ldr(r3, MemOperand(sp));
1325 // r1 is used as scratch register, r3 and r2 might be clobbered.
1326 GenerateStoreField(masm(),
1327 Builtins::StoreIC_ExtendStorage,
1328 object,
1329 index,
1330 transition,
1331 r3, r2, r1,
1332 &miss);
1333 __ bind(&miss);
1334
1335 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1336 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
1337 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
1338 __ Jump(ic, RelocInfo::CODE_TARGET);
1339
1340 // Return the generated code.
1341 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1342 }
1343
1344
CompileConstructStub(SharedFunctionInfo * shared)1345 Object* ConstructStubCompiler::CompileConstructStub(
1346 SharedFunctionInfo* shared) {
1347 // ----------- S t a t e -------------
1348 // -- r0 : argc
1349 // -- r1 : constructor
1350 // -- lr : return address
1351 // -- [sp] : last argument
1352 // -----------------------------------
1353 Label generic_stub_call;
1354
1355 // Use r7 for holding undefined which is used in several places below.
1356 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
1357
1358 #ifdef ENABLE_DEBUGGER_SUPPORT
1359 // Check to see whether there are any break points in the function code. If
1360 // there are jump to the generic constructor stub which calls the actual
1361 // code for the function thereby hitting the break points.
1362 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1363 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset));
1364 __ cmp(r2, r7);
1365 __ b(ne, &generic_stub_call);
1366 #endif
1367
1368 // Load the initial map and verify that it is in fact a map.
1369 // r1: constructor function
1370 // r7: undefined
1371 __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
1372 __ tst(r2, Operand(kSmiTagMask));
1373 __ b(eq, &generic_stub_call);
1374 __ CompareObjectType(r2, r3, r4, MAP_TYPE);
1375 __ b(ne, &generic_stub_call);
1376
1377 #ifdef DEBUG
1378 // Cannot construct functions this way.
1379 // r0: argc
1380 // r1: constructor function
1381 // r2: initial map
1382 // r7: undefined
1383 __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
1384 __ Check(ne, "Function constructed by construct stub.");
1385 #endif
1386
1387 // Now allocate the JSObject in new space.
1388 // r0: argc
1389 // r1: constructor function
1390 // r2: initial map
1391 // r7: undefined
1392 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1393 __ AllocateObjectInNewSpace(r3,
1394 r4,
1395 r5,
1396 r6,
1397 &generic_stub_call,
1398 NO_ALLOCATION_FLAGS);
1399
1400 // Allocated the JSObject, now initialize the fields. Map is set to initial
1401 // map and properties and elements are set to empty fixed array.
1402 // r0: argc
1403 // r1: constructor function
1404 // r2: initial map
1405 // r3: object size (in words)
1406 // r4: JSObject (not tagged)
1407 // r7: undefined
1408 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
1409 __ mov(r5, r4);
1410 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
1411 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1412 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
1413 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1414 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
1415 __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
1416
1417 // Calculate the location of the first argument. The stack contains only the
1418 // argc arguments.
1419 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2));
1420
1421 // Fill all the in-object properties with undefined.
1422 // r0: argc
1423 // r1: first argument
1424 // r3: object size (in words)
1425 // r4: JSObject (not tagged)
1426 // r5: First in-object property of JSObject (not tagged)
1427 // r7: undefined
1428 // Fill the initialized properties with a constant value or a passed argument
1429 // depending on the this.x = ...; assignment in the function.
1430 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
1431 if (shared->IsThisPropertyAssignmentArgument(i)) {
1432 Label not_passed, next;
1433 // Check if the argument assigned to the property is actually passed.
1434 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
1435 __ cmp(r0, Operand(arg_number));
1436 __ b(le, ¬_passed);
1437 // Argument passed - find it on the stack.
1438 __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize));
1439 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1440 __ b(&next);
1441 __ bind(¬_passed);
1442 // Set the property to undefined.
1443 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1444 __ bind(&next);
1445 } else {
1446 // Set the property to the constant value.
1447 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
1448 __ mov(r2, Operand(constant));
1449 __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
1450 }
1451 }
1452
1453 // Fill the unused in-object property fields with undefined.
1454 for (int i = shared->this_property_assignments_count();
1455 i < shared->CalculateInObjectProperties();
1456 i++) {
1457 __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
1458 }
1459
1460 // r0: argc
1461 // r4: JSObject (not tagged)
1462 // Move argc to r1 and the JSObject to return to r0 and tag it.
1463 __ mov(r1, r0);
1464 __ mov(r0, r4);
1465 __ orr(r0, r0, Operand(kHeapObjectTag));
1466
1467 // r0: JSObject
1468 // r1: argc
1469 // Remove caller arguments and receiver from the stack and return.
1470 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
1471 __ add(sp, sp, Operand(kPointerSize));
1472 __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
1473 __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
1474 __ Jump(lr);
1475
1476 // Jump to the generic stub in case the specialized code cannot handle the
1477 // construction.
1478 __ bind(&generic_stub_call);
1479 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1480 Handle<Code> generic_construct_stub(code);
1481 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
1482
1483 // Return the generated code.
1484 return GetCode();
1485 }
1486
1487
1488 #undef __
1489
1490 } } // namespace v8::internal
1491