• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &not_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(&not_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