• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 #if defined(V8_TARGET_ARCH_IA32)
31 
32 #include "ic-inl.h"
33 #include "codegen.h"
34 #include "stub-cache.h"
35 
36 namespace v8 {
37 namespace internal {
38 
39 #define __ ACCESS_MASM(masm)
40 
41 
ProbeTable(Isolate * isolate,MacroAssembler * masm,Code::Flags flags,StubCache::Table table,Register name,Register receiver,Register offset,Register extra)42 static void ProbeTable(Isolate* isolate,
43                        MacroAssembler* masm,
44                        Code::Flags flags,
45                        StubCache::Table table,
46                        Register name,
47                        Register receiver,
48                        // Number of the cache entry pointer-size scaled.
49                        Register offset,
50                        Register extra) {
51   ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
52   ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
53   ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
54 
55   Label miss;
56 
57   // Multiply by 3 because there are 3 fields per entry (name, code, map).
58   __ lea(offset, Operand(offset, offset, times_2, 0));
59 
60   if (extra.is_valid()) {
61     // Get the code entry from the cache.
62     __ mov(extra, Operand::StaticArray(offset, times_1, value_offset));
63 
64     // Check that the key in the entry matches the name.
65     __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
66     __ j(not_equal, &miss);
67 
68     // Check the map matches.
69     __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
70     __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
71     __ j(not_equal, &miss);
72 
73     // Check that the flags match what we're looking for.
74     __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
75     __ and_(offset, ~Code::kFlagsNotUsedInLookup);
76     __ cmp(offset, flags);
77     __ j(not_equal, &miss);
78 
79 #ifdef DEBUG
80     if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
81       __ jmp(&miss);
82     } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
83       __ jmp(&miss);
84     }
85 #endif
86 
87     // Jump to the first instruction in the code stub.
88     __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
89     __ jmp(extra);
90 
91     __ bind(&miss);
92   } else {
93     // Save the offset on the stack.
94     __ push(offset);
95 
96     // Check that the key in the entry matches the name.
97     __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
98     __ j(not_equal, &miss);
99 
100     // Check the map matches.
101     __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
102     __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
103     __ j(not_equal, &miss);
104 
105     // Restore offset register.
106     __ mov(offset, Operand(esp, 0));
107 
108     // Get the code entry from the cache.
109     __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
110 
111     // Check that the flags match what we're looking for.
112     __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
113     __ and_(offset, ~Code::kFlagsNotUsedInLookup);
114     __ cmp(offset, flags);
115     __ j(not_equal, &miss);
116 
117 #ifdef DEBUG
118     if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
119       __ jmp(&miss);
120     } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
121       __ jmp(&miss);
122     }
123 #endif
124 
125     // Restore offset and re-load code entry from cache.
126     __ pop(offset);
127     __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
128 
129     // Jump to the first instruction in the code stub.
130     __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
131     __ jmp(offset);
132 
133     // Pop at miss.
134     __ bind(&miss);
135     __ pop(offset);
136   }
137 }
138 
139 
140 // Helper function used to check that the dictionary doesn't contain
141 // the property. This function may return false negatives, so miss_label
142 // must always call a backup property check that is complete.
143 // This function is safe to call if the receiver has fast properties.
144 // Name must be a symbol and receiver must be a heap object.
GenerateDictionaryNegativeLookup(MacroAssembler * masm,Label * miss_label,Register receiver,Handle<String> name,Register r0,Register r1)145 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
146                                              Label* miss_label,
147                                              Register receiver,
148                                              Handle<String> name,
149                                              Register r0,
150                                              Register r1) {
151   ASSERT(name->IsSymbol());
152   Counters* counters = masm->isolate()->counters();
153   __ IncrementCounter(counters->negative_lookups(), 1);
154   __ IncrementCounter(counters->negative_lookups_miss(), 1);
155 
156   __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset));
157 
158   const int kInterceptorOrAccessCheckNeededMask =
159       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
160 
161   // Bail out if the receiver has a named interceptor or requires access checks.
162   __ test_b(FieldOperand(r0, Map::kBitFieldOffset),
163             kInterceptorOrAccessCheckNeededMask);
164   __ j(not_zero, miss_label);
165 
166   // Check that receiver is a JSObject.
167   __ CmpInstanceType(r0, FIRST_SPEC_OBJECT_TYPE);
168   __ j(below, miss_label);
169 
170   // Load properties array.
171   Register properties = r0;
172   __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
173 
174   // Check that the properties array is a dictionary.
175   __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
176          Immediate(masm->isolate()->factory()->hash_table_map()));
177   __ j(not_equal, miss_label);
178 
179   Label done;
180   StringDictionaryLookupStub::GenerateNegativeLookup(masm,
181                                                      miss_label,
182                                                      &done,
183                                                      properties,
184                                                      name,
185                                                      r1);
186   __ bind(&done);
187   __ DecrementCounter(counters->negative_lookups_miss(), 1);
188 }
189 
190 
GenerateProbe(MacroAssembler * masm,Code::Flags flags,Register receiver,Register name,Register scratch,Register extra,Register extra2,Register extra3)191 void StubCache::GenerateProbe(MacroAssembler* masm,
192                               Code::Flags flags,
193                               Register receiver,
194                               Register name,
195                               Register scratch,
196                               Register extra,
197                               Register extra2,
198                               Register extra3) {
199   Label miss;
200 
201   // Assert that code is valid.  The multiplying code relies on the entry size
202   // being 12.
203   ASSERT(sizeof(Entry) == 12);
204 
205   // Assert the flags do not name a specific type.
206   ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
207 
208   // Assert that there are no register conflicts.
209   ASSERT(!scratch.is(receiver));
210   ASSERT(!scratch.is(name));
211   ASSERT(!extra.is(receiver));
212   ASSERT(!extra.is(name));
213   ASSERT(!extra.is(scratch));
214 
215   // Assert scratch and extra registers are valid, and extra2/3 are unused.
216   ASSERT(!scratch.is(no_reg));
217   ASSERT(extra2.is(no_reg));
218   ASSERT(extra3.is(no_reg));
219 
220   Register offset = scratch;
221   scratch = no_reg;
222 
223   Counters* counters = masm->isolate()->counters();
224   __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
225 
226   // Check that the receiver isn't a smi.
227   __ JumpIfSmi(receiver, &miss);
228 
229   // Get the map of the receiver and compute the hash.
230   __ mov(offset, FieldOperand(name, String::kHashFieldOffset));
231   __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
232   __ xor_(offset, flags);
233   // We mask out the last two bits because they are not part of the hash and
234   // they are always 01 for maps.  Also in the two 'and' instructions below.
235   __ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
236   // ProbeTable expects the offset to be pointer scaled, which it is, because
237   // the heap object tag size is 2 and the pointer size log 2 is also 2.
238   ASSERT(kHeapObjectTagSize == kPointerSizeLog2);
239 
240   // Probe the primary table.
241   ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra);
242 
243   // Primary miss: Compute hash for secondary probe.
244   __ mov(offset, FieldOperand(name, String::kHashFieldOffset));
245   __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
246   __ xor_(offset, flags);
247   __ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
248   __ sub(offset, name);
249   __ add(offset, Immediate(flags));
250   __ and_(offset, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
251 
252   // Probe the secondary table.
253   ProbeTable(
254       isolate(), masm, flags, kSecondary, name, receiver, offset, extra);
255 
256   // Cache miss: Fall-through and let caller handle the miss by
257   // entering the runtime system.
258   __ bind(&miss);
259   __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
260 }
261 
262 
GenerateLoadGlobalFunctionPrototype(MacroAssembler * masm,int index,Register prototype)263 void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
264                                                        int index,
265                                                        Register prototype) {
266   __ LoadGlobalFunction(index, prototype);
267   __ LoadGlobalFunctionInitialMap(prototype, prototype);
268   // Load the prototype from the initial map.
269   __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
270 }
271 
272 
GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler * masm,int index,Register prototype,Label * miss)273 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
274     MacroAssembler* masm,
275     int index,
276     Register prototype,
277     Label* miss) {
278   // Check we're still in the same context.
279   __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)),
280          masm->isolate()->global());
281   __ j(not_equal, miss);
282   // Get the global function with the given index.
283   Handle<JSFunction> function(
284       JSFunction::cast(masm->isolate()->global_context()->get(index)));
285   // Load its initial map. The global functions all have initial maps.
286   __ Set(prototype, Immediate(Handle<Map>(function->initial_map())));
287   // Load the prototype from the initial map.
288   __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
289 }
290 
291 
GenerateLoadArrayLength(MacroAssembler * masm,Register receiver,Register scratch,Label * miss_label)292 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
293                                            Register receiver,
294                                            Register scratch,
295                                            Label* miss_label) {
296   // Check that the receiver isn't a smi.
297   __ JumpIfSmi(receiver, miss_label);
298 
299   // Check that the object is a JS array.
300   __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
301   __ j(not_equal, miss_label);
302 
303   // Load length directly from the JS array.
304   __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
305   __ ret(0);
306 }
307 
308 
309 // Generate code to check if an object is a string.  If the object is
310 // a string, the map's instance type is left in the scratch register.
GenerateStringCheck(MacroAssembler * masm,Register receiver,Register scratch,Label * smi,Label * non_string_object)311 static void GenerateStringCheck(MacroAssembler* masm,
312                                 Register receiver,
313                                 Register scratch,
314                                 Label* smi,
315                                 Label* non_string_object) {
316   // Check that the object isn't a smi.
317   __ JumpIfSmi(receiver, smi);
318 
319   // Check that the object is a string.
320   __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
321   __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
322   STATIC_ASSERT(kNotStringTag != 0);
323   __ test(scratch, Immediate(kNotStringTag));
324   __ j(not_zero, non_string_object);
325 }
326 
327 
GenerateLoadStringLength(MacroAssembler * masm,Register receiver,Register scratch1,Register scratch2,Label * miss,bool support_wrappers)328 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
329                                             Register receiver,
330                                             Register scratch1,
331                                             Register scratch2,
332                                             Label* miss,
333                                             bool support_wrappers) {
334   Label check_wrapper;
335 
336   // Check if the object is a string leaving the instance type in the
337   // scratch register.
338   GenerateStringCheck(masm, receiver, scratch1, miss,
339                       support_wrappers ? &check_wrapper : miss);
340 
341   // Load length from the string and convert to a smi.
342   __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
343   __ ret(0);
344 
345   if (support_wrappers) {
346     // Check if the object is a JSValue wrapper.
347     __ bind(&check_wrapper);
348     __ cmp(scratch1, JS_VALUE_TYPE);
349     __ j(not_equal, miss);
350 
351     // Check if the wrapped value is a string and load the length
352     // directly if it is.
353     __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
354     GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
355     __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
356     __ ret(0);
357   }
358 }
359 
360 
GenerateLoadFunctionPrototype(MacroAssembler * masm,Register receiver,Register scratch1,Register scratch2,Label * miss_label)361 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
362                                                  Register receiver,
363                                                  Register scratch1,
364                                                  Register scratch2,
365                                                  Label* miss_label) {
366   __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
367   __ mov(eax, scratch1);
368   __ ret(0);
369 }
370 
371 
372 // Load a fast property out of a holder object (src). In-object properties
373 // are loaded directly otherwise the property is loaded from the properties
374 // fixed array.
GenerateFastPropertyLoad(MacroAssembler * masm,Register dst,Register src,Handle<JSObject> holder,int index)375 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
376                                             Register dst,
377                                             Register src,
378                                             Handle<JSObject> holder,
379                                             int index) {
380   // Adjust for the number of properties stored in the holder.
381   index -= holder->map()->inobject_properties();
382   if (index < 0) {
383     // Get the property straight out of the holder.
384     int offset = holder->map()->instance_size() + (index * kPointerSize);
385     __ mov(dst, FieldOperand(src, offset));
386   } else {
387     // Calculate the offset into the properties array.
388     int offset = index * kPointerSize + FixedArray::kHeaderSize;
389     __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
390     __ mov(dst, FieldOperand(dst, offset));
391   }
392 }
393 
394 
PushInterceptorArguments(MacroAssembler * masm,Register receiver,Register holder,Register name,Handle<JSObject> holder_obj)395 static void PushInterceptorArguments(MacroAssembler* masm,
396                                      Register receiver,
397                                      Register holder,
398                                      Register name,
399                                      Handle<JSObject> holder_obj) {
400   __ push(name);
401   Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
402   ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
403   Register scratch = name;
404   __ mov(scratch, Immediate(interceptor));
405   __ push(scratch);
406   __ push(receiver);
407   __ push(holder);
408   __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset));
409 }
410 
411 
CompileCallLoadPropertyWithInterceptor(MacroAssembler * masm,Register receiver,Register holder,Register name,Handle<JSObject> holder_obj)412 static void CompileCallLoadPropertyWithInterceptor(
413     MacroAssembler* masm,
414     Register receiver,
415     Register holder,
416     Register name,
417     Handle<JSObject> holder_obj) {
418   PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
419   __ CallExternalReference(
420       ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
421                         masm->isolate()),
422       5);
423 }
424 
425 
426 // Number of pointers to be reserved on stack for fast API call.
427 static const int kFastApiCallArguments = 3;
428 
429 
430 // Reserves space for the extra arguments to API function in the
431 // caller's frame.
432 //
433 // These arguments are set by CheckPrototypes and GenerateFastApiCall.
ReserveSpaceForFastApiCall(MacroAssembler * masm,Register scratch)434 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
435   // ----------- S t a t e -------------
436   //  -- esp[0] : return address
437   //  -- esp[4] : last argument in the internal frame of the caller
438   // -----------------------------------
439   __ pop(scratch);
440   for (int i = 0; i < kFastApiCallArguments; i++) {
441     __ push(Immediate(Smi::FromInt(0)));
442   }
443   __ push(scratch);
444 }
445 
446 
447 // Undoes the effects of ReserveSpaceForFastApiCall.
FreeSpaceForFastApiCall(MacroAssembler * masm,Register scratch)448 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
449   // ----------- S t a t e -------------
450   //  -- esp[0]  : return address.
451   //  -- esp[4]  : last fast api call extra argument.
452   //  -- ...
453   //  -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
454   //  -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
455   //                                          frame.
456   // -----------------------------------
457   __ pop(scratch);
458   __ add(esp, Immediate(kPointerSize * kFastApiCallArguments));
459   __ push(scratch);
460 }
461 
462 
463 // Generates call to API function.
GenerateFastApiCall(MacroAssembler * masm,const CallOptimization & optimization,int argc)464 static void GenerateFastApiCall(MacroAssembler* masm,
465                                 const CallOptimization& optimization,
466                                 int argc) {
467   // ----------- S t a t e -------------
468   //  -- esp[0]              : return address
469   //  -- esp[4]              : object passing the type check
470   //                           (last fast api call extra argument,
471   //                            set by CheckPrototypes)
472   //  -- esp[8]              : api function
473   //                           (first fast api call extra argument)
474   //  -- esp[12]             : api call data
475   //  -- esp[16]             : last argument
476   //  -- ...
477   //  -- esp[(argc + 3) * 4] : first argument
478   //  -- esp[(argc + 4) * 4] : receiver
479   // -----------------------------------
480   // Get the function and setup the context.
481   Handle<JSFunction> function = optimization.constant_function();
482   __ LoadHeapObject(edi, function);
483   __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
484 
485   // Pass the additional arguments.
486   __ mov(Operand(esp, 2 * kPointerSize), edi);
487   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
488   Handle<Object> call_data(api_call_info->data());
489   if (masm->isolate()->heap()->InNewSpace(*call_data)) {
490     __ mov(ecx, api_call_info);
491     __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
492     __ mov(Operand(esp, 3 * kPointerSize), ebx);
493   } else {
494     __ mov(Operand(esp, 3 * kPointerSize), Immediate(call_data));
495   }
496 
497   // Prepare arguments.
498   __ lea(eax, Operand(esp, 3 * kPointerSize));
499 
500   const int kApiArgc = 1;  // API function gets reference to the v8::Arguments.
501 
502   // Allocate the v8::Arguments structure in the arguments' space since
503   // it's not controlled by GC.
504   const int kApiStackSpace = 4;
505 
506   __ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
507 
508   __ mov(ApiParameterOperand(1), eax);  // v8::Arguments::implicit_args_.
509   __ add(eax, Immediate(argc * kPointerSize));
510   __ mov(ApiParameterOperand(2), eax);  // v8::Arguments::values_.
511   __ Set(ApiParameterOperand(3), Immediate(argc));  // v8::Arguments::length_.
512   // v8::Arguments::is_construct_call_.
513   __ Set(ApiParameterOperand(4), Immediate(0));
514 
515   // v8::InvocationCallback's argument.
516   __ lea(eax, ApiParameterOperand(1));
517   __ mov(ApiParameterOperand(0), eax);
518 
519   // Function address is a foreign pointer outside V8's heap.
520   Address function_address = v8::ToCData<Address>(api_call_info->callback());
521   __ CallApiFunctionAndReturn(function_address,
522                               argc + kFastApiCallArguments + 1);
523 }
524 
525 
526 class CallInterceptorCompiler BASE_EMBEDDED {
527  public:
CallInterceptorCompiler(StubCompiler * stub_compiler,const ParameterCount & arguments,Register name,Code::ExtraICState extra_state)528   CallInterceptorCompiler(StubCompiler* stub_compiler,
529                           const ParameterCount& arguments,
530                           Register name,
531                           Code::ExtraICState extra_state)
532       : stub_compiler_(stub_compiler),
533         arguments_(arguments),
534         name_(name),
535         extra_state_(extra_state) {}
536 
Compile(MacroAssembler * masm,Handle<JSObject> object,Handle<JSObject> holder,Handle<String> name,LookupResult * lookup,Register receiver,Register scratch1,Register scratch2,Register scratch3,Label * miss)537   void Compile(MacroAssembler* masm,
538                Handle<JSObject> object,
539                Handle<JSObject> holder,
540                Handle<String> name,
541                LookupResult* lookup,
542                Register receiver,
543                Register scratch1,
544                Register scratch2,
545                Register scratch3,
546                Label* miss) {
547     ASSERT(holder->HasNamedInterceptor());
548     ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
549 
550     // Check that the receiver isn't a smi.
551     __ JumpIfSmi(receiver, miss);
552 
553     CallOptimization optimization(lookup);
554     if (optimization.is_constant_call()) {
555       CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
556                        holder, lookup, name, optimization, miss);
557     } else {
558       CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
559                      name, holder, miss);
560     }
561   }
562 
563  private:
CompileCacheable(MacroAssembler * masm,Handle<JSObject> object,Register receiver,Register scratch1,Register scratch2,Register scratch3,Handle<JSObject> interceptor_holder,LookupResult * lookup,Handle<String> name,const CallOptimization & optimization,Label * miss_label)564   void CompileCacheable(MacroAssembler* masm,
565                         Handle<JSObject> object,
566                         Register receiver,
567                         Register scratch1,
568                         Register scratch2,
569                         Register scratch3,
570                         Handle<JSObject> interceptor_holder,
571                         LookupResult* lookup,
572                         Handle<String> name,
573                         const CallOptimization& optimization,
574                         Label* miss_label) {
575     ASSERT(optimization.is_constant_call());
576     ASSERT(!lookup->holder()->IsGlobalObject());
577 
578     int depth1 = kInvalidProtoDepth;
579     int depth2 = kInvalidProtoDepth;
580     bool can_do_fast_api_call = false;
581     if (optimization.is_simple_api_call() &&
582         !lookup->holder()->IsGlobalObject()) {
583       depth1 = optimization.GetPrototypeDepthOfExpectedType(
584           object, interceptor_holder);
585       if (depth1 == kInvalidProtoDepth) {
586         depth2 = optimization.GetPrototypeDepthOfExpectedType(
587             interceptor_holder, Handle<JSObject>(lookup->holder()));
588       }
589       can_do_fast_api_call =
590           depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
591     }
592 
593     Counters* counters = masm->isolate()->counters();
594     __ IncrementCounter(counters->call_const_interceptor(), 1);
595 
596     if (can_do_fast_api_call) {
597       __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
598       ReserveSpaceForFastApiCall(masm, scratch1);
599     }
600 
601     // Check that the maps from receiver to interceptor's holder
602     // haven't changed and thus we can invoke interceptor.
603     Label miss_cleanup;
604     Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
605     Register holder =
606         stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
607                                         scratch1, scratch2, scratch3,
608                                         name, depth1, miss);
609 
610     // Invoke an interceptor and if it provides a value,
611     // branch to |regular_invoke|.
612     Label regular_invoke;
613     LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
614                         &regular_invoke);
615 
616     // Interceptor returned nothing for this property.  Try to use cached
617     // constant function.
618 
619     // Check that the maps from interceptor's holder to constant function's
620     // holder haven't changed and thus we can use cached constant function.
621     if (*interceptor_holder != lookup->holder()) {
622       stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
623                                       Handle<JSObject>(lookup->holder()),
624                                       scratch1, scratch2, scratch3,
625                                       name, depth2, miss);
626     } else {
627       // CheckPrototypes has a side effect of fetching a 'holder'
628       // for API (object which is instanceof for the signature).  It's
629       // safe to omit it here, as if present, it should be fetched
630       // by the previous CheckPrototypes.
631       ASSERT(depth2 == kInvalidProtoDepth);
632     }
633 
634     // Invoke function.
635     if (can_do_fast_api_call) {
636       GenerateFastApiCall(masm, optimization, arguments_.immediate());
637     } else {
638       CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
639           ? CALL_AS_FUNCTION
640           : CALL_AS_METHOD;
641       __ InvokeFunction(optimization.constant_function(), arguments_,
642                         JUMP_FUNCTION, NullCallWrapper(), call_kind);
643     }
644 
645     // Deferred code for fast API call case---clean preallocated space.
646     if (can_do_fast_api_call) {
647       __ bind(&miss_cleanup);
648       FreeSpaceForFastApiCall(masm, scratch1);
649       __ jmp(miss_label);
650     }
651 
652     // Invoke a regular function.
653     __ bind(&regular_invoke);
654     if (can_do_fast_api_call) {
655       FreeSpaceForFastApiCall(masm, scratch1);
656     }
657   }
658 
CompileRegular(MacroAssembler * masm,Handle<JSObject> object,Register receiver,Register scratch1,Register scratch2,Register scratch3,Handle<String> name,Handle<JSObject> interceptor_holder,Label * miss_label)659   void CompileRegular(MacroAssembler* masm,
660                       Handle<JSObject> object,
661                       Register receiver,
662                       Register scratch1,
663                       Register scratch2,
664                       Register scratch3,
665                       Handle<String> name,
666                       Handle<JSObject> interceptor_holder,
667                       Label* miss_label) {
668     Register holder =
669         stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
670                                         scratch1, scratch2, scratch3,
671                                         name, miss_label);
672 
673     FrameScope scope(masm, StackFrame::INTERNAL);
674     // Save the name_ register across the call.
675     __ push(name_);
676 
677     PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
678 
679     __ CallExternalReference(
680         ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
681                           masm->isolate()),
682         5);
683 
684     // Restore the name_ register.
685     __ pop(name_);
686 
687     // Leave the internal frame.
688   }
689 
LoadWithInterceptor(MacroAssembler * masm,Register receiver,Register holder,Handle<JSObject> holder_obj,Label * interceptor_succeeded)690   void LoadWithInterceptor(MacroAssembler* masm,
691                            Register receiver,
692                            Register holder,
693                            Handle<JSObject> holder_obj,
694                            Label* interceptor_succeeded) {
695     {
696       FrameScope scope(masm, StackFrame::INTERNAL);
697       __ push(holder);  // Save the holder.
698       __ push(name_);  // Save the name.
699 
700       CompileCallLoadPropertyWithInterceptor(masm,
701                                              receiver,
702                                              holder,
703                                              name_,
704                                              holder_obj);
705 
706       __ pop(name_);  // Restore the name.
707       __ pop(receiver);  // Restore the holder.
708       // Leave the internal frame.
709     }
710 
711     __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
712     __ j(not_equal, interceptor_succeeded);
713   }
714 
715   StubCompiler* stub_compiler_;
716   const ParameterCount& arguments_;
717   Register name_;
718   Code::ExtraICState extra_state_;
719 };
720 
721 
GenerateLoadMiss(MacroAssembler * masm,Code::Kind kind)722 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
723   ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
724   Handle<Code> code = (kind == Code::LOAD_IC)
725       ? masm->isolate()->builtins()->LoadIC_Miss()
726       : masm->isolate()->builtins()->KeyedLoadIC_Miss();
727   __ jmp(code, RelocInfo::CODE_TARGET);
728 }
729 
730 
GenerateKeyedLoadMissForceGeneric(MacroAssembler * masm)731 void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
732   Handle<Code> code =
733       masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
734   __ jmp(code, RelocInfo::CODE_TARGET);
735 }
736 
737 
738 // Both name_reg and receiver_reg are preserved on jumps to miss_label,
739 // but may be destroyed if store is successful.
GenerateStoreField(MacroAssembler * masm,Handle<JSObject> object,int index,Handle<Map> transition,Register receiver_reg,Register name_reg,Register scratch,Label * miss_label)740 void StubCompiler::GenerateStoreField(MacroAssembler* masm,
741                                       Handle<JSObject> object,
742                                       int index,
743                                       Handle<Map> transition,
744                                       Register receiver_reg,
745                                       Register name_reg,
746                                       Register scratch,
747                                       Label* miss_label) {
748   // Check that the map of the object hasn't changed.
749   CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
750                                              : REQUIRE_EXACT_MAP;
751   __ CheckMap(receiver_reg, Handle<Map>(object->map()),
752               miss_label, DO_SMI_CHECK, mode);
753 
754   // Perform global security token check if needed.
755   if (object->IsJSGlobalProxy()) {
756     __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
757   }
758 
759   // Stub never generated for non-global objects that require access
760   // checks.
761   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
762 
763   // Perform map transition for the receiver if necessary.
764   if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
765     // The properties must be extended before we can store the value.
766     // We jump to a runtime call that extends the properties array.
767     __ pop(scratch);  // Return address.
768     __ push(receiver_reg);
769     __ push(Immediate(transition));
770     __ push(eax);
771     __ push(scratch);
772     __ TailCallExternalReference(
773         ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
774                           masm->isolate()),
775         3,
776         1);
777     return;
778   }
779 
780   if (!transition.is_null()) {
781     // Update the map of the object; no write barrier updating is
782     // needed because the map is never in new space.
783     __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
784            Immediate(transition));
785   }
786 
787   // Adjust for the number of properties stored in the object. Even in the
788   // face of a transition we can use the old map here because the size of the
789   // object and the number of in-object properties is not going to change.
790   index -= object->map()->inobject_properties();
791 
792   if (index < 0) {
793     // Set the property straight into the object.
794     int offset = object->map()->instance_size() + (index * kPointerSize);
795     __ mov(FieldOperand(receiver_reg, offset), eax);
796 
797     // Update the write barrier for the array address.
798     // Pass the value being stored in the now unused name_reg.
799     __ mov(name_reg, eax);
800     __ RecordWriteField(receiver_reg,
801                         offset,
802                         name_reg,
803                         scratch,
804                         kDontSaveFPRegs);
805   } else {
806     // Write to the properties array.
807     int offset = index * kPointerSize + FixedArray::kHeaderSize;
808     // Get the properties array (optimistically).
809     __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
810     __ mov(FieldOperand(scratch, offset), eax);
811 
812     // Update the write barrier for the array address.
813     // Pass the value being stored in the now unused name_reg.
814     __ mov(name_reg, eax);
815     __ RecordWriteField(scratch,
816                         offset,
817                         name_reg,
818                         receiver_reg,
819                         kDontSaveFPRegs);
820   }
821 
822   // Return the value (register eax).
823   __ ret(0);
824 }
825 
826 
827 // Generate code to check that a global property cell is empty. Create
828 // the property cell at compilation time if no cell exists for the
829 // property.
GenerateCheckPropertyCell(MacroAssembler * masm,Handle<GlobalObject> global,Handle<String> name,Register scratch,Label * miss)830 static void GenerateCheckPropertyCell(MacroAssembler* masm,
831                                       Handle<GlobalObject> global,
832                                       Handle<String> name,
833                                       Register scratch,
834                                       Label* miss) {
835   Handle<JSGlobalPropertyCell> cell =
836       GlobalObject::EnsurePropertyCell(global, name);
837   ASSERT(cell->value()->IsTheHole());
838   Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
839   if (Serializer::enabled()) {
840     __ mov(scratch, Immediate(cell));
841     __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
842            Immediate(the_hole));
843   } else {
844     __ cmp(Operand::Cell(cell), Immediate(the_hole));
845   }
846   __ j(not_equal, miss);
847 }
848 
849 
850 // Calls GenerateCheckPropertyCell for each global object in the prototype chain
851 // from object to (but not including) holder.
GenerateCheckPropertyCells(MacroAssembler * masm,Handle<JSObject> object,Handle<JSObject> holder,Handle<String> name,Register scratch,Label * miss)852 static void GenerateCheckPropertyCells(MacroAssembler* masm,
853                                        Handle<JSObject> object,
854                                        Handle<JSObject> holder,
855                                        Handle<String> name,
856                                        Register scratch,
857                                        Label* miss) {
858   Handle<JSObject> current = object;
859   while (!current.is_identical_to(holder)) {
860     if (current->IsGlobalObject()) {
861       GenerateCheckPropertyCell(masm,
862                                 Handle<GlobalObject>::cast(current),
863                                 name,
864                                 scratch,
865                                 miss);
866     }
867     current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
868   }
869 }
870 
871 #undef __
872 #define __ ACCESS_MASM(masm())
873 
874 
CheckPrototypes(Handle<JSObject> object,Register object_reg,Handle<JSObject> holder,Register holder_reg,Register scratch1,Register scratch2,Handle<String> name,int save_at_depth,Label * miss)875 Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
876                                        Register object_reg,
877                                        Handle<JSObject> holder,
878                                        Register holder_reg,
879                                        Register scratch1,
880                                        Register scratch2,
881                                        Handle<String> name,
882                                        int save_at_depth,
883                                        Label* miss) {
884   // Make sure there's no overlap between holder and object registers.
885   ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
886   ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
887          && !scratch2.is(scratch1));
888 
889   // Keep track of the current object in register reg.
890   Register reg = object_reg;
891   Handle<JSObject> current = object;
892   int depth = 0;
893 
894   if (save_at_depth == depth) {
895     __ mov(Operand(esp, kPointerSize), reg);
896   }
897 
898   // Traverse the prototype chain and check the maps in the prototype chain for
899   // fast and global objects or do negative lookup for normal objects.
900   while (!current.is_identical_to(holder)) {
901     ++depth;
902 
903     // Only global objects and objects that do not require access
904     // checks are allowed in stubs.
905     ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
906 
907     Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
908     if (!current->HasFastProperties() &&
909         !current->IsJSGlobalObject() &&
910         !current->IsJSGlobalProxy()) {
911       if (!name->IsSymbol()) {
912         name = factory()->LookupSymbol(name);
913       }
914       ASSERT(current->property_dictionary()->FindEntry(*name) ==
915              StringDictionary::kNotFound);
916 
917       GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
918                                        scratch1, scratch2);
919 
920       __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
921       reg = holder_reg;  // From now on the object will be in holder_reg.
922       __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
923     } else {
924       bool in_new_space = heap()->InNewSpace(*prototype);
925       Handle<Map> current_map(current->map());
926       if (in_new_space) {
927         // Save the map in scratch1 for later.
928         __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
929       }
930       __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
931                   ALLOW_ELEMENT_TRANSITION_MAPS);
932 
933       // Check access rights to the global object.  This has to happen after
934       // the map check so that we know that the object is actually a global
935       // object.
936       if (current->IsJSGlobalProxy()) {
937         __ CheckAccessGlobalProxy(reg, scratch2, miss);
938       }
939       reg = holder_reg;  // From now on the object will be in holder_reg.
940 
941       if (in_new_space) {
942         // The prototype is in new space; we cannot store a reference to it
943         // in the code.  Load it from the map.
944         __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
945       } else {
946         // The prototype is in old space; load it directly.
947         __ mov(reg, prototype);
948       }
949     }
950 
951     if (save_at_depth == depth) {
952       __ mov(Operand(esp, kPointerSize), reg);
953     }
954 
955     // Go to the next object in the prototype chain.
956     current = prototype;
957   }
958   ASSERT(current.is_identical_to(holder));
959 
960   // Log the check depth.
961   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
962 
963   // Check the holder map.
964   __ CheckMap(reg, Handle<Map>(holder->map()),
965               miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
966 
967   // Perform security check for access to the global object.
968   ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
969   if (holder->IsJSGlobalProxy()) {
970     __ CheckAccessGlobalProxy(reg, scratch1, miss);
971   }
972 
973   // If we've skipped any global objects, it's not enough to verify that
974   // their maps haven't changed.  We also need to check that the property
975   // cell for the property is still empty.
976   GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
977 
978   // Return the register containing the holder.
979   return reg;
980 }
981 
982 
GenerateLoadField(Handle<JSObject> object,Handle<JSObject> holder,Register receiver,Register scratch1,Register scratch2,Register scratch3,int index,Handle<String> name,Label * miss)983 void StubCompiler::GenerateLoadField(Handle<JSObject> object,
984                                      Handle<JSObject> holder,
985                                      Register receiver,
986                                      Register scratch1,
987                                      Register scratch2,
988                                      Register scratch3,
989                                      int index,
990                                      Handle<String> name,
991                                      Label* miss) {
992   // Check that the receiver isn't a smi.
993   __ JumpIfSmi(receiver, miss);
994 
995   // Check the prototype chain.
996   Register reg = CheckPrototypes(
997       object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
998 
999   // Get the value from the properties.
1000   GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
1001   __ ret(0);
1002 }
1003 
1004 
GenerateLoadCallback(Handle<JSObject> object,Handle<JSObject> holder,Register receiver,Register name_reg,Register scratch1,Register scratch2,Register scratch3,Handle<AccessorInfo> callback,Handle<String> name,Label * miss)1005 void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1006                                         Handle<JSObject> holder,
1007                                         Register receiver,
1008                                         Register name_reg,
1009                                         Register scratch1,
1010                                         Register scratch2,
1011                                         Register scratch3,
1012                                         Handle<AccessorInfo> callback,
1013                                         Handle<String> name,
1014                                         Label* miss) {
1015   // Check that the receiver isn't a smi.
1016   __ JumpIfSmi(receiver, miss);
1017 
1018   // Check that the maps haven't changed.
1019   Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1020                                  scratch2, scratch3, name, miss);
1021 
1022   // Insert additional parameters into the stack frame above return address.
1023   ASSERT(!scratch3.is(reg));
1024   __ pop(scratch3);  // Get return address to place it below.
1025 
1026   __ push(receiver);  // receiver
1027   __ mov(scratch2, esp);
1028   ASSERT(!scratch2.is(reg));
1029   __ push(reg);  // holder
1030   // Push data from AccessorInfo.
1031   if (isolate()->heap()->InNewSpace(callback->data())) {
1032     __ mov(scratch1, Immediate(callback));
1033     __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset));
1034   } else {
1035     __ push(Immediate(Handle<Object>(callback->data())));
1036   }
1037 
1038   // Save a pointer to where we pushed the arguments pointer.
1039   // This will be passed as the const AccessorInfo& to the C++ callback.
1040   __ push(scratch2);
1041 
1042   __ push(name_reg);  // name
1043   __ mov(ebx, esp);  // esp points to reference to name (handler).
1044 
1045   __ push(scratch3);  // Restore return address.
1046 
1047   // 3 elements array for v8::Arguments::values_, handler for name and pointer
1048   // to the values (it considered as smi in GC).
1049   const int kStackSpace = 5;
1050   const int kApiArgc = 2;
1051 
1052   __ PrepareCallApiFunction(kApiArgc);
1053   __ mov(ApiParameterOperand(0), ebx);  // name.
1054   __ add(ebx, Immediate(kPointerSize));
1055   __ mov(ApiParameterOperand(1), ebx);  // arguments pointer.
1056 
1057   // Emitting a stub call may try to allocate (if the code is not
1058   // already generated).  Do not allow the assembler to perform a
1059   // garbage collection but instead return the allocation failure
1060   // object.
1061   Address getter_address = v8::ToCData<Address>(callback->getter());
1062   __ CallApiFunctionAndReturn(getter_address, kStackSpace);
1063 }
1064 
1065 
GenerateLoadConstant(Handle<JSObject> object,Handle<JSObject> holder,Register receiver,Register scratch1,Register scratch2,Register scratch3,Handle<JSFunction> value,Handle<String> name,Label * miss)1066 void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1067                                         Handle<JSObject> holder,
1068                                         Register receiver,
1069                                         Register scratch1,
1070                                         Register scratch2,
1071                                         Register scratch3,
1072                                         Handle<JSFunction> value,
1073                                         Handle<String> name,
1074                                         Label* miss) {
1075   // Check that the receiver isn't a smi.
1076   __ JumpIfSmi(receiver, miss);
1077 
1078   // Check that the maps haven't changed.
1079   CheckPrototypes(
1080       object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
1081 
1082   // Return the constant value.
1083   __ LoadHeapObject(eax, value);
1084   __ ret(0);
1085 }
1086 
1087 
GenerateLoadInterceptor(Handle<JSObject> object,Handle<JSObject> interceptor_holder,LookupResult * lookup,Register receiver,Register name_reg,Register scratch1,Register scratch2,Register scratch3,Handle<String> name,Label * miss)1088 void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1089                                            Handle<JSObject> interceptor_holder,
1090                                            LookupResult* lookup,
1091                                            Register receiver,
1092                                            Register name_reg,
1093                                            Register scratch1,
1094                                            Register scratch2,
1095                                            Register scratch3,
1096                                            Handle<String> name,
1097                                            Label* miss) {
1098   ASSERT(interceptor_holder->HasNamedInterceptor());
1099   ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1100 
1101   // Check that the receiver isn't a smi.
1102   __ JumpIfSmi(receiver, miss);
1103 
1104   // So far the most popular follow ups for interceptor loads are FIELD
1105   // and CALLBACKS, so inline only them, other cases may be added
1106   // later.
1107   bool compile_followup_inline = false;
1108   if (lookup->IsFound() && lookup->IsCacheable()) {
1109     if (lookup->type() == FIELD) {
1110       compile_followup_inline = true;
1111     } else if (lookup->type() == CALLBACKS &&
1112                lookup->GetCallbackObject()->IsAccessorInfo()) {
1113       compile_followup_inline =
1114           AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL;
1115     }
1116   }
1117 
1118   if (compile_followup_inline) {
1119     // Compile the interceptor call, followed by inline code to load the
1120     // property from further up the prototype chain if the call fails.
1121     // Check that the maps haven't changed.
1122     Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1123                                           scratch1, scratch2, scratch3,
1124                                           name, miss);
1125     ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1126 
1127     // Preserve the receiver register explicitly whenever it is different from
1128     // the holder and it is needed should the interceptor return without any
1129     // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1130     // the FIELD case might cause a miss during the prototype check.
1131     bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1132     bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1133         (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1134 
1135     // Save necessary data before invoking an interceptor.
1136     // Requires a frame to make GC aware of pushed pointers.
1137     {
1138       FrameScope frame_scope(masm(), StackFrame::INTERNAL);
1139 
1140       if (must_preserve_receiver_reg) {
1141         __ push(receiver);
1142       }
1143       __ push(holder_reg);
1144       __ push(name_reg);
1145 
1146       // Invoke an interceptor.  Note: map checks from receiver to
1147       // interceptor's holder has been compiled before (see a caller
1148       // of this method.)
1149       CompileCallLoadPropertyWithInterceptor(masm(),
1150                                              receiver,
1151                                              holder_reg,
1152                                              name_reg,
1153                                              interceptor_holder);
1154 
1155       // Check if interceptor provided a value for property.  If it's
1156       // the case, return immediately.
1157       Label interceptor_failed;
1158       __ cmp(eax, factory()->no_interceptor_result_sentinel());
1159       __ j(equal, &interceptor_failed);
1160       frame_scope.GenerateLeaveFrame();
1161       __ ret(0);
1162 
1163       // Clobber registers when generating debug-code to provoke errors.
1164       __ bind(&interceptor_failed);
1165       if (FLAG_debug_code) {
1166         __ mov(receiver, Immediate(BitCast<int32_t>(kZapValue)));
1167         __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
1168         __ mov(name_reg, Immediate(BitCast<int32_t>(kZapValue)));
1169       }
1170 
1171       __ pop(name_reg);
1172       __ pop(holder_reg);
1173       if (must_preserve_receiver_reg) {
1174         __ pop(receiver);
1175       }
1176 
1177       // Leave the internal frame.
1178     }
1179 
1180     // Check that the maps from interceptor's holder to lookup's holder
1181     // haven't changed.  And load lookup's holder into holder_reg.
1182     if (must_perfrom_prototype_check) {
1183       holder_reg = CheckPrototypes(interceptor_holder,
1184                                    holder_reg,
1185                                    Handle<JSObject>(lookup->holder()),
1186                                    scratch1,
1187                                    scratch2,
1188                                    scratch3,
1189                                    name,
1190                                    miss);
1191     }
1192 
1193     if (lookup->type() == FIELD) {
1194       // We found FIELD property in prototype chain of interceptor's holder.
1195       // Retrieve a field from field's holder.
1196       GenerateFastPropertyLoad(masm(), eax, holder_reg,
1197                                Handle<JSObject>(lookup->holder()),
1198                                lookup->GetFieldIndex());
1199       __ ret(0);
1200     } else {
1201       // We found CALLBACKS property in prototype chain of interceptor's
1202       // holder.
1203       ASSERT(lookup->type() == CALLBACKS);
1204       Handle<AccessorInfo> callback(
1205           AccessorInfo::cast(lookup->GetCallbackObject()));
1206       ASSERT(callback->getter() != NULL);
1207 
1208       // Tail call to runtime.
1209       // Important invariant in CALLBACKS case: the code above must be
1210       // structured to never clobber |receiver| register.
1211       __ pop(scratch2);  // return address
1212       __ push(receiver);
1213       __ push(holder_reg);
1214       __ mov(holder_reg, Immediate(callback));
1215       __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
1216       __ push(holder_reg);
1217       __ push(name_reg);
1218       __ push(scratch2);  // restore return address
1219 
1220       ExternalReference ref =
1221           ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1222                             masm()->isolate());
1223       __ TailCallExternalReference(ref, 5, 1);
1224     }
1225   } else {  // !compile_followup_inline
1226     // Call the runtime system to load the interceptor.
1227     // Check that the maps haven't changed.
1228     Register holder_reg =
1229         CheckPrototypes(object, receiver, interceptor_holder,
1230                         scratch1, scratch2, scratch3, name, miss);
1231     __ pop(scratch2);  // save old return address
1232     PushInterceptorArguments(masm(), receiver, holder_reg,
1233                              name_reg, interceptor_holder);
1234     __ push(scratch2);  // restore old return address
1235 
1236     ExternalReference ref =
1237         ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
1238                           isolate());
1239     __ TailCallExternalReference(ref, 5, 1);
1240   }
1241 }
1242 
1243 
GenerateNameCheck(Handle<String> name,Label * miss)1244 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
1245   if (kind_ == Code::KEYED_CALL_IC) {
1246     __ cmp(ecx, Immediate(name));
1247     __ j(not_equal, miss);
1248   }
1249 }
1250 
1251 
GenerateGlobalReceiverCheck(Handle<JSObject> object,Handle<JSObject> holder,Handle<String> name,Label * miss)1252 void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1253                                                    Handle<JSObject> holder,
1254                                                    Handle<String> name,
1255                                                    Label* miss) {
1256   ASSERT(holder->IsGlobalObject());
1257 
1258   // Get the number of arguments.
1259   const int argc = arguments().immediate();
1260 
1261   // Get the receiver from the stack.
1262   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1263 
1264 
1265   // Check that the maps haven't changed.
1266   __ JumpIfSmi(edx, miss);
1267   CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
1268 }
1269 
1270 
GenerateLoadFunctionFromCell(Handle<JSGlobalPropertyCell> cell,Handle<JSFunction> function,Label * miss)1271 void CallStubCompiler::GenerateLoadFunctionFromCell(
1272     Handle<JSGlobalPropertyCell> cell,
1273     Handle<JSFunction> function,
1274     Label* miss) {
1275   // Get the value from the cell.
1276   if (Serializer::enabled()) {
1277     __ mov(edi, Immediate(cell));
1278     __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
1279   } else {
1280     __ mov(edi, Operand::Cell(cell));
1281   }
1282 
1283   // Check that the cell contains the same function.
1284   if (isolate()->heap()->InNewSpace(*function)) {
1285     // We can't embed a pointer to a function in new space so we have
1286     // to verify that the shared function info is unchanged. This has
1287     // the nice side effect that multiple closures based on the same
1288     // function can all use this call IC. Before we load through the
1289     // function, we have to verify that it still is a function.
1290     __ JumpIfSmi(edi, miss);
1291     __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
1292     __ j(not_equal, miss);
1293 
1294     // Check the shared function info. Make sure it hasn't changed.
1295     __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
1296            Immediate(Handle<SharedFunctionInfo>(function->shared())));
1297   } else {
1298     __ cmp(edi, Immediate(function));
1299   }
1300   __ j(not_equal, miss);
1301 }
1302 
1303 
GenerateMissBranch()1304 void CallStubCompiler::GenerateMissBranch() {
1305   Handle<Code> code =
1306       isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1307                                                kind_,
1308                                                extra_state_);
1309   __ jmp(code, RelocInfo::CODE_TARGET);
1310 }
1311 
1312 
CompileCallField(Handle<JSObject> object,Handle<JSObject> holder,int index,Handle<String> name)1313 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1314                                                 Handle<JSObject> holder,
1315                                                 int index,
1316                                                 Handle<String> name) {
1317   // ----------- S t a t e -------------
1318   //  -- ecx                 : name
1319   //  -- esp[0]              : return address
1320   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1321   //  -- ...
1322   //  -- esp[(argc + 1) * 4] : receiver
1323   // -----------------------------------
1324   Label miss;
1325 
1326   GenerateNameCheck(name, &miss);
1327 
1328   // Get the receiver from the stack.
1329   const int argc = arguments().immediate();
1330   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1331 
1332   // Check that the receiver isn't a smi.
1333   __ JumpIfSmi(edx, &miss);
1334 
1335   // Do the right check and compute the holder register.
1336   Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
1337                                  name, &miss);
1338 
1339   GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
1340 
1341   // Check that the function really is a function.
1342   __ JumpIfSmi(edi, &miss);
1343   __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
1344   __ j(not_equal, &miss);
1345 
1346   // Patch the receiver on the stack with the global proxy if
1347   // necessary.
1348   if (object->IsGlobalObject()) {
1349     __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1350     __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1351   }
1352 
1353   // Invoke the function.
1354   CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
1355       ? CALL_AS_FUNCTION
1356       : CALL_AS_METHOD;
1357   __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
1358                     NullCallWrapper(), call_kind);
1359 
1360   // Handle call cache miss.
1361   __ bind(&miss);
1362   GenerateMissBranch();
1363 
1364   // Return the generated code.
1365   return GetCode(FIELD, name);
1366 }
1367 
1368 
CompileArrayPushCall(Handle<Object> object,Handle<JSObject> holder,Handle<JSGlobalPropertyCell> cell,Handle<JSFunction> function,Handle<String> name)1369 Handle<Code> CallStubCompiler::CompileArrayPushCall(
1370     Handle<Object> object,
1371     Handle<JSObject> holder,
1372     Handle<JSGlobalPropertyCell> cell,
1373     Handle<JSFunction> function,
1374     Handle<String> name) {
1375   // ----------- S t a t e -------------
1376   //  -- ecx                 : name
1377   //  -- esp[0]              : return address
1378   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1379   //  -- ...
1380   //  -- esp[(argc + 1) * 4] : receiver
1381   // -----------------------------------
1382 
1383   // If object is not an array, bail out to regular call.
1384   if (!object->IsJSArray() || !cell.is_null()) {
1385     return Handle<Code>::null();
1386   }
1387 
1388   Label miss;
1389 
1390   GenerateNameCheck(name, &miss);
1391 
1392   // Get the receiver from the stack.
1393   const int argc = arguments().immediate();
1394   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1395 
1396   // Check that the receiver isn't a smi.
1397   __ JumpIfSmi(edx, &miss);
1398 
1399   CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1400                   name, &miss);
1401 
1402   if (argc == 0) {
1403     // Noop, return the length.
1404     __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1405     __ ret((argc + 1) * kPointerSize);
1406   } else {
1407     Label call_builtin;
1408 
1409     if (argc == 1) {  // Otherwise fall through to call builtin.
1410       Label attempt_to_grow_elements, with_write_barrier;
1411 
1412       // Get the elements array of the object.
1413       __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1414 
1415       // Check that the elements are in fast mode and writable.
1416       __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1417              Immediate(factory()->fixed_array_map()));
1418       __ j(not_equal, &call_builtin);
1419 
1420       // Get the array's length into eax and calculate new length.
1421       __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1422       STATIC_ASSERT(kSmiTagSize == 1);
1423       STATIC_ASSERT(kSmiTag == 0);
1424       __ add(eax, Immediate(Smi::FromInt(argc)));
1425 
1426       // Get the elements' length into ecx.
1427       __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
1428 
1429       // Check if we could survive without allocation.
1430       __ cmp(eax, ecx);
1431       __ j(greater, &attempt_to_grow_elements);
1432 
1433       // Check if value is a smi.
1434       __ mov(ecx, Operand(esp, argc * kPointerSize));
1435       __ JumpIfNotSmi(ecx, &with_write_barrier);
1436 
1437       // Save new length.
1438       __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1439 
1440       // Store the value.
1441       __ mov(FieldOperand(edi,
1442                           eax,
1443                           times_half_pointer_size,
1444                           FixedArray::kHeaderSize - argc * kPointerSize),
1445              ecx);
1446 
1447       __ ret((argc + 1) * kPointerSize);
1448 
1449       __ bind(&with_write_barrier);
1450 
1451       __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1452 
1453       if (FLAG_smi_only_arrays  && !FLAG_trace_elements_transitions) {
1454         Label fast_object, not_fast_object;
1455         __ CheckFastObjectElements(ebx, &not_fast_object, Label::kNear);
1456         __ jmp(&fast_object);
1457         // In case of fast smi-only, convert to fast object, otherwise bail out.
1458         __ bind(&not_fast_object);
1459         __ CheckFastSmiOnlyElements(ebx, &call_builtin);
1460         // edi: elements array
1461         // edx: receiver
1462         // ebx: map
1463         __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
1464                                                FAST_ELEMENTS,
1465                                                ebx,
1466                                                edi,
1467                                                &call_builtin);
1468         ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm());
1469         // Restore edi.
1470         __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1471         __ bind(&fast_object);
1472       } else {
1473         __ CheckFastObjectElements(ebx, &call_builtin);
1474       }
1475 
1476       // Save new length.
1477       __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1478 
1479       // Store the value.
1480       __ lea(edx, FieldOperand(edi,
1481                                eax, times_half_pointer_size,
1482                                FixedArray::kHeaderSize - argc * kPointerSize));
1483       __ mov(Operand(edx, 0), ecx);
1484 
1485       __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
1486                      OMIT_SMI_CHECK);
1487 
1488       __ ret((argc + 1) * kPointerSize);
1489 
1490       __ bind(&attempt_to_grow_elements);
1491       if (!FLAG_inline_new) {
1492         __ jmp(&call_builtin);
1493       }
1494 
1495       __ mov(ebx, Operand(esp, argc * kPointerSize));
1496       // Growing elements that are SMI-only requires special handling in case
1497       // the new element is non-Smi. For now, delegate to the builtin.
1498       Label no_fast_elements_check;
1499       __ JumpIfSmi(ebx, &no_fast_elements_check);
1500       __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1501       __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar);
1502       __ bind(&no_fast_elements_check);
1503 
1504       // We could be lucky and the elements array could be at the top of
1505       // new-space.  In this case we can just grow it in place by moving the
1506       // allocation pointer up.
1507 
1508       ExternalReference new_space_allocation_top =
1509           ExternalReference::new_space_allocation_top_address(isolate());
1510       ExternalReference new_space_allocation_limit =
1511           ExternalReference::new_space_allocation_limit_address(isolate());
1512 
1513       const int kAllocationDelta = 4;
1514       // Load top.
1515       __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
1516 
1517       // Check if it's the end of elements.
1518       __ lea(edx, FieldOperand(edi,
1519                                eax, times_half_pointer_size,
1520                                FixedArray::kHeaderSize - argc * kPointerSize));
1521       __ cmp(edx, ecx);
1522       __ j(not_equal, &call_builtin);
1523       __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
1524       __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
1525       __ j(above, &call_builtin);
1526 
1527       // We fit and could grow elements.
1528       __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
1529 
1530       // Push the argument...
1531       __ mov(Operand(edx, 0), ebx);
1532       // ... and fill the rest with holes.
1533       for (int i = 1; i < kAllocationDelta; i++) {
1534         __ mov(Operand(edx, i * kPointerSize),
1535                Immediate(factory()->the_hole_value()));
1536       }
1537 
1538       // We know the elements array is in new space so we don't need the
1539       // remembered set, but we just pushed a value onto it so we may have to
1540       // tell the incremental marker to rescan the object that we just grew.  We
1541       // don't need to worry about the holes because they are in old space and
1542       // already marked black.
1543       __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
1544 
1545       // Restore receiver to edx as finish sequence assumes it's here.
1546       __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1547 
1548       // Increment element's and array's sizes.
1549       __ add(FieldOperand(edi, FixedArray::kLengthOffset),
1550              Immediate(Smi::FromInt(kAllocationDelta)));
1551 
1552       // NOTE: This only happen in new-space, where we don't
1553       // care about the black-byte-count on pages. Otherwise we should
1554       // update that too if the object is black.
1555 
1556       __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1557 
1558       __ ret((argc + 1) * kPointerSize);
1559     }
1560 
1561     __ bind(&call_builtin);
1562     __ TailCallExternalReference(
1563         ExternalReference(Builtins::c_ArrayPush, isolate()),
1564         argc + 1,
1565         1);
1566   }
1567 
1568   __ bind(&miss);
1569   GenerateMissBranch();
1570 
1571   // Return the generated code.
1572   return GetCode(function);
1573 }
1574 
1575 
CompileArrayPopCall(Handle<Object> object,Handle<JSObject> holder,Handle<JSGlobalPropertyCell> cell,Handle<JSFunction> function,Handle<String> name)1576 Handle<Code> CallStubCompiler::CompileArrayPopCall(
1577     Handle<Object> object,
1578     Handle<JSObject> holder,
1579     Handle<JSGlobalPropertyCell> cell,
1580     Handle<JSFunction> function,
1581     Handle<String> name) {
1582   // ----------- S t a t e -------------
1583   //  -- ecx                 : name
1584   //  -- esp[0]              : return address
1585   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1586   //  -- ...
1587   //  -- esp[(argc + 1) * 4] : receiver
1588   // -----------------------------------
1589 
1590   // If object is not an array, bail out to regular call.
1591   if (!object->IsJSArray() || !cell.is_null()) {
1592     return Handle<Code>::null();
1593   }
1594 
1595   Label miss, return_undefined, call_builtin;
1596 
1597   GenerateNameCheck(name, &miss);
1598 
1599   // Get the receiver from the stack.
1600   const int argc = arguments().immediate();
1601   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1602 
1603   // Check that the receiver isn't a smi.
1604   __ JumpIfSmi(edx, &miss);
1605   CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1606                   name, &miss);
1607 
1608   // Get the elements array of the object.
1609   __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
1610 
1611   // Check that the elements are in fast mode and writable.
1612   __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1613          Immediate(factory()->fixed_array_map()));
1614   __ j(not_equal, &call_builtin);
1615 
1616   // Get the array's length into ecx and calculate new length.
1617   __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
1618   __ sub(ecx, Immediate(Smi::FromInt(1)));
1619   __ j(negative, &return_undefined);
1620 
1621   // Get the last element.
1622   STATIC_ASSERT(kSmiTagSize == 1);
1623   STATIC_ASSERT(kSmiTag == 0);
1624   __ mov(eax, FieldOperand(ebx,
1625                            ecx, times_half_pointer_size,
1626                            FixedArray::kHeaderSize));
1627   __ cmp(eax, Immediate(factory()->the_hole_value()));
1628   __ j(equal, &call_builtin);
1629 
1630   // Set the array's length.
1631   __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
1632 
1633   // Fill with the hole.
1634   __ mov(FieldOperand(ebx,
1635                       ecx, times_half_pointer_size,
1636                       FixedArray::kHeaderSize),
1637          Immediate(factory()->the_hole_value()));
1638   __ ret((argc + 1) * kPointerSize);
1639 
1640   __ bind(&return_undefined);
1641   __ mov(eax, Immediate(factory()->undefined_value()));
1642   __ ret((argc + 1) * kPointerSize);
1643 
1644   __ bind(&call_builtin);
1645   __ TailCallExternalReference(
1646       ExternalReference(Builtins::c_ArrayPop, isolate()),
1647       argc + 1,
1648       1);
1649 
1650   __ bind(&miss);
1651   GenerateMissBranch();
1652 
1653   // Return the generated code.
1654   return GetCode(function);
1655 }
1656 
1657 
CompileStringCharCodeAtCall(Handle<Object> object,Handle<JSObject> holder,Handle<JSGlobalPropertyCell> cell,Handle<JSFunction> function,Handle<String> name)1658 Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1659     Handle<Object> object,
1660     Handle<JSObject> holder,
1661     Handle<JSGlobalPropertyCell> cell,
1662     Handle<JSFunction> function,
1663     Handle<String> name) {
1664   // ----------- S t a t e -------------
1665   //  -- ecx                 : function name
1666   //  -- esp[0]              : return address
1667   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1668   //  -- ...
1669   //  -- esp[(argc + 1) * 4] : receiver
1670   // -----------------------------------
1671 
1672   // If object is not a string, bail out to regular call.
1673   if (!object->IsString() || !cell.is_null()) {
1674     return Handle<Code>::null();
1675   }
1676 
1677   const int argc = arguments().immediate();
1678 
1679   Label miss;
1680   Label name_miss;
1681   Label index_out_of_range;
1682   Label* index_out_of_range_label = &index_out_of_range;
1683 
1684   if (kind_ == Code::CALL_IC &&
1685       (CallICBase::StringStubState::decode(extra_state_) ==
1686        DEFAULT_STRING_STUB)) {
1687     index_out_of_range_label = &miss;
1688   }
1689 
1690   GenerateNameCheck(name, &name_miss);
1691 
1692   // Check that the maps starting from the prototype haven't changed.
1693   GenerateDirectLoadGlobalFunctionPrototype(masm(),
1694                                             Context::STRING_FUNCTION_INDEX,
1695                                             eax,
1696                                             &miss);
1697   ASSERT(!object.is_identical_to(holder));
1698   CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1699                   eax, holder, ebx, edx, edi, name, &miss);
1700 
1701   Register receiver = ebx;
1702   Register index = edi;
1703   Register result = eax;
1704   __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1705   if (argc > 0) {
1706     __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1707   } else {
1708     __ Set(index, Immediate(factory()->undefined_value()));
1709   }
1710 
1711   StringCharCodeAtGenerator generator(receiver,
1712                                       index,
1713                                       result,
1714                                       &miss,  // When not a string.
1715                                       &miss,  // When not a number.
1716                                       index_out_of_range_label,
1717                                       STRING_INDEX_IS_NUMBER);
1718   generator.GenerateFast(masm());
1719   __ ret((argc + 1) * kPointerSize);
1720 
1721   StubRuntimeCallHelper call_helper;
1722   generator.GenerateSlow(masm(), call_helper);
1723 
1724   if (index_out_of_range.is_linked()) {
1725     __ bind(&index_out_of_range);
1726     __ Set(eax, Immediate(factory()->nan_value()));
1727     __ ret((argc + 1) * kPointerSize);
1728   }
1729 
1730   __ bind(&miss);
1731   // Restore function name in ecx.
1732   __ Set(ecx, Immediate(name));
1733   __ bind(&name_miss);
1734   GenerateMissBranch();
1735 
1736   // Return the generated code.
1737   return GetCode(function);
1738 }
1739 
1740 
CompileStringCharAtCall(Handle<Object> object,Handle<JSObject> holder,Handle<JSGlobalPropertyCell> cell,Handle<JSFunction> function,Handle<String> name)1741 Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1742     Handle<Object> object,
1743     Handle<JSObject> holder,
1744     Handle<JSGlobalPropertyCell> cell,
1745     Handle<JSFunction> function,
1746     Handle<String> name) {
1747   // ----------- S t a t e -------------
1748   //  -- ecx                 : function name
1749   //  -- esp[0]              : return address
1750   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1751   //  -- ...
1752   //  -- esp[(argc + 1) * 4] : receiver
1753   // -----------------------------------
1754 
1755   // If object is not a string, bail out to regular call.
1756   if (!object->IsString() || !cell.is_null()) {
1757     return Handle<Code>::null();
1758   }
1759 
1760   const int argc = arguments().immediate();
1761 
1762   Label miss;
1763   Label name_miss;
1764   Label index_out_of_range;
1765   Label* index_out_of_range_label = &index_out_of_range;
1766 
1767   if (kind_ == Code::CALL_IC &&
1768       (CallICBase::StringStubState::decode(extra_state_) ==
1769        DEFAULT_STRING_STUB)) {
1770     index_out_of_range_label = &miss;
1771   }
1772 
1773   GenerateNameCheck(name, &name_miss);
1774 
1775   // Check that the maps starting from the prototype haven't changed.
1776   GenerateDirectLoadGlobalFunctionPrototype(masm(),
1777                                             Context::STRING_FUNCTION_INDEX,
1778                                             eax,
1779                                             &miss);
1780   ASSERT(!object.is_identical_to(holder));
1781   CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1782                   eax, holder, ebx, edx, edi, name, &miss);
1783 
1784   Register receiver = eax;
1785   Register index = edi;
1786   Register scratch = edx;
1787   Register result = eax;
1788   __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1789   if (argc > 0) {
1790     __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1791   } else {
1792     __ Set(index, Immediate(factory()->undefined_value()));
1793   }
1794 
1795   StringCharAtGenerator generator(receiver,
1796                                   index,
1797                                   scratch,
1798                                   result,
1799                                   &miss,  // When not a string.
1800                                   &miss,  // When not a number.
1801                                   index_out_of_range_label,
1802                                   STRING_INDEX_IS_NUMBER);
1803   generator.GenerateFast(masm());
1804   __ ret((argc + 1) * kPointerSize);
1805 
1806   StubRuntimeCallHelper call_helper;
1807   generator.GenerateSlow(masm(), call_helper);
1808 
1809   if (index_out_of_range.is_linked()) {
1810     __ bind(&index_out_of_range);
1811     __ Set(eax, Immediate(factory()->empty_string()));
1812     __ ret((argc + 1) * kPointerSize);
1813   }
1814 
1815   __ bind(&miss);
1816   // Restore function name in ecx.
1817   __ Set(ecx, Immediate(name));
1818   __ bind(&name_miss);
1819   GenerateMissBranch();
1820 
1821   // Return the generated code.
1822   return GetCode(function);
1823 }
1824 
1825 
CompileStringFromCharCodeCall(Handle<Object> object,Handle<JSObject> holder,Handle<JSGlobalPropertyCell> cell,Handle<JSFunction> function,Handle<String> name)1826 Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1827     Handle<Object> object,
1828     Handle<JSObject> holder,
1829     Handle<JSGlobalPropertyCell> cell,
1830     Handle<JSFunction> function,
1831     Handle<String> name) {
1832   // ----------- S t a t e -------------
1833   //  -- ecx                 : function name
1834   //  -- esp[0]              : return address
1835   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1836   //  -- ...
1837   //  -- esp[(argc + 1) * 4] : receiver
1838   // -----------------------------------
1839 
1840   const int argc = arguments().immediate();
1841 
1842   // If the object is not a JSObject or we got an unexpected number of
1843   // arguments, bail out to the regular call.
1844   if (!object->IsJSObject() || argc != 1) {
1845     return Handle<Code>::null();
1846   }
1847 
1848   Label miss;
1849   GenerateNameCheck(name, &miss);
1850 
1851   if (cell.is_null()) {
1852     __ mov(edx, Operand(esp, 2 * kPointerSize));
1853     STATIC_ASSERT(kSmiTag == 0);
1854     __ JumpIfSmi(edx, &miss);
1855     CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1856                     name, &miss);
1857   } else {
1858     ASSERT(cell->value() == *function);
1859     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1860                                 &miss);
1861     GenerateLoadFunctionFromCell(cell, function, &miss);
1862   }
1863 
1864   // Load the char code argument.
1865   Register code = ebx;
1866   __ mov(code, Operand(esp, 1 * kPointerSize));
1867 
1868   // Check the code is a smi.
1869   Label slow;
1870   STATIC_ASSERT(kSmiTag == 0);
1871   __ JumpIfNotSmi(code, &slow);
1872 
1873   // Convert the smi code to uint16.
1874   __ and_(code, Immediate(Smi::FromInt(0xffff)));
1875 
1876   StringCharFromCodeGenerator generator(code, eax);
1877   generator.GenerateFast(masm());
1878   __ ret(2 * kPointerSize);
1879 
1880   StubRuntimeCallHelper call_helper;
1881   generator.GenerateSlow(masm(), call_helper);
1882 
1883   // Tail call the full function. We do not have to patch the receiver
1884   // because the function makes no use of it.
1885   __ bind(&slow);
1886   CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
1887       ? CALL_AS_FUNCTION
1888       : CALL_AS_METHOD;
1889   __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
1890                     NullCallWrapper(), call_kind);
1891 
1892   __ bind(&miss);
1893   // ecx: function name.
1894   GenerateMissBranch();
1895 
1896   // Return the generated code.
1897   return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
1898 }
1899 
1900 
CompileMathFloorCall(Handle<Object> object,Handle<JSObject> holder,Handle<JSGlobalPropertyCell> cell,Handle<JSFunction> function,Handle<String> name)1901 Handle<Code> CallStubCompiler::CompileMathFloorCall(
1902     Handle<Object> object,
1903     Handle<JSObject> holder,
1904     Handle<JSGlobalPropertyCell> cell,
1905     Handle<JSFunction> function,
1906     Handle<String> name) {
1907   // ----------- S t a t e -------------
1908   //  -- ecx                 : name
1909   //  -- esp[0]              : return address
1910   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1911   //  -- ...
1912   //  -- esp[(argc + 1) * 4] : receiver
1913   // -----------------------------------
1914 
1915   if (!CpuFeatures::IsSupported(SSE2)) {
1916     return Handle<Code>::null();
1917   }
1918 
1919   CpuFeatures::Scope use_sse2(SSE2);
1920 
1921   const int argc = arguments().immediate();
1922 
1923   // If the object is not a JSObject or we got an unexpected number of
1924   // arguments, bail out to the regular call.
1925   if (!object->IsJSObject() || argc != 1) {
1926     return Handle<Code>::null();
1927   }
1928 
1929   Label miss;
1930   GenerateNameCheck(name, &miss);
1931 
1932   if (cell.is_null()) {
1933     __ mov(edx, Operand(esp, 2 * kPointerSize));
1934 
1935     STATIC_ASSERT(kSmiTag == 0);
1936     __ JumpIfSmi(edx, &miss);
1937 
1938     CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1939                     name, &miss);
1940   } else {
1941     ASSERT(cell->value() == *function);
1942     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1943                                 &miss);
1944     GenerateLoadFunctionFromCell(cell, function, &miss);
1945   }
1946 
1947   // Load the (only) argument into eax.
1948   __ mov(eax, Operand(esp, 1 * kPointerSize));
1949 
1950   // Check if the argument is a smi.
1951   Label smi;
1952   STATIC_ASSERT(kSmiTag == 0);
1953   __ JumpIfSmi(eax, &smi);
1954 
1955   // Check if the argument is a heap number and load its value into xmm0.
1956   Label slow;
1957   __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
1958   __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
1959 
1960   // Check if the argument is strictly positive. Note this also
1961   // discards NaN.
1962   __ xorpd(xmm1, xmm1);
1963   __ ucomisd(xmm0, xmm1);
1964   __ j(below_equal, &slow);
1965 
1966   // Do a truncating conversion.
1967   __ cvttsd2si(eax, Operand(xmm0));
1968 
1969   // Check if the result fits into a smi. Note this also checks for
1970   // 0x80000000 which signals a failed conversion.
1971   Label wont_fit_into_smi;
1972   __ test(eax, Immediate(0xc0000000));
1973   __ j(not_zero, &wont_fit_into_smi);
1974 
1975   // Smi tag and return.
1976   __ SmiTag(eax);
1977   __ bind(&smi);
1978   __ ret(2 * kPointerSize);
1979 
1980   // Check if the argument is < 2^kMantissaBits.
1981   Label already_round;
1982   __ bind(&wont_fit_into_smi);
1983   __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits);
1984   __ ucomisd(xmm0, xmm1);
1985   __ j(above_equal, &already_round);
1986 
1987   // Save a copy of the argument.
1988   __ movaps(xmm2, xmm0);
1989 
1990   // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
1991   __ addsd(xmm0, xmm1);
1992   __ subsd(xmm0, xmm1);
1993 
1994   // Compare the argument and the tentative result to get the right mask:
1995   //   if xmm2 < xmm0:
1996   //     xmm2 = 1...1
1997   //   else:
1998   //     xmm2 = 0...0
1999   __ cmpltsd(xmm2, xmm0);
2000 
2001   // Subtract 1 if the argument was less than the tentative result.
2002   __ LoadPowerOf2(xmm1, ebx, 0);
2003   __ andpd(xmm1, xmm2);
2004   __ subsd(xmm0, xmm1);
2005 
2006   // Return a new heap number.
2007   __ AllocateHeapNumber(eax, ebx, edx, &slow);
2008   __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2009   __ ret(2 * kPointerSize);
2010 
2011   // Return the argument (when it's an already round heap number).
2012   __ bind(&already_round);
2013   __ mov(eax, Operand(esp, 1 * kPointerSize));
2014   __ ret(2 * kPointerSize);
2015 
2016   // Tail call the full function. We do not have to patch the receiver
2017   // because the function makes no use of it.
2018   __ bind(&slow);
2019   __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2020                     NullCallWrapper(), CALL_AS_METHOD);
2021 
2022   __ bind(&miss);
2023   // ecx: function name.
2024   GenerateMissBranch();
2025 
2026   // Return the generated code.
2027   return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
2028 }
2029 
2030 
CompileMathAbsCall(Handle<Object> object,Handle<JSObject> holder,Handle<JSGlobalPropertyCell> cell,Handle<JSFunction> function,Handle<String> name)2031 Handle<Code> CallStubCompiler::CompileMathAbsCall(
2032     Handle<Object> object,
2033     Handle<JSObject> holder,
2034     Handle<JSGlobalPropertyCell> cell,
2035     Handle<JSFunction> function,
2036     Handle<String> name) {
2037   // ----------- S t a t e -------------
2038   //  -- ecx                 : name
2039   //  -- esp[0]              : return address
2040   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
2041   //  -- ...
2042   //  -- esp[(argc + 1) * 4] : receiver
2043   // -----------------------------------
2044 
2045   const int argc = arguments().immediate();
2046 
2047   // If the object is not a JSObject or we got an unexpected number of
2048   // arguments, bail out to the regular call.
2049   if (!object->IsJSObject() || argc != 1) {
2050     return Handle<Code>::null();
2051   }
2052 
2053   Label miss;
2054   GenerateNameCheck(name, &miss);
2055 
2056   if (cell.is_null()) {
2057     __ mov(edx, Operand(esp, 2 * kPointerSize));
2058 
2059     STATIC_ASSERT(kSmiTag == 0);
2060     __ JumpIfSmi(edx, &miss);
2061 
2062     CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2063                     name, &miss);
2064   } else {
2065     ASSERT(cell->value() == *function);
2066     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2067                                 &miss);
2068     GenerateLoadFunctionFromCell(cell, function, &miss);
2069   }
2070 
2071   // Load the (only) argument into eax.
2072   __ mov(eax, Operand(esp, 1 * kPointerSize));
2073 
2074   // Check if the argument is a smi.
2075   Label not_smi;
2076   STATIC_ASSERT(kSmiTag == 0);
2077   __ JumpIfNotSmi(eax, &not_smi);
2078 
2079   // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2080   // otherwise.
2081   __ mov(ebx, eax);
2082   __ sar(ebx, kBitsPerInt - 1);
2083 
2084   // Do bitwise not or do nothing depending on ebx.
2085   __ xor_(eax, ebx);
2086 
2087   // Add 1 or do nothing depending on ebx.
2088   __ sub(eax, ebx);
2089 
2090   // If the result is still negative, go to the slow case.
2091   // This only happens for the most negative smi.
2092   Label slow;
2093   __ j(negative, &slow);
2094 
2095   // Smi case done.
2096   __ ret(2 * kPointerSize);
2097 
2098   // Check if the argument is a heap number and load its exponent and
2099   // sign into ebx.
2100   __ bind(&not_smi);
2101   __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
2102   __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset));
2103 
2104   // Check the sign of the argument. If the argument is positive,
2105   // just return it.
2106   Label negative_sign;
2107   __ test(ebx, Immediate(HeapNumber::kSignMask));
2108   __ j(not_zero, &negative_sign);
2109   __ ret(2 * kPointerSize);
2110 
2111   // If the argument is negative, clear the sign, and return a new
2112   // number.
2113   __ bind(&negative_sign);
2114   __ and_(ebx, ~HeapNumber::kSignMask);
2115   __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2116   __ AllocateHeapNumber(eax, edi, edx, &slow);
2117   __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx);
2118   __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
2119   __ ret(2 * kPointerSize);
2120 
2121   // Tail call the full function. We do not have to patch the receiver
2122   // because the function makes no use of it.
2123   __ bind(&slow);
2124   __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2125                     NullCallWrapper(), CALL_AS_METHOD);
2126 
2127   __ bind(&miss);
2128   // ecx: function name.
2129   GenerateMissBranch();
2130 
2131   // Return the generated code.
2132   return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
2133 }
2134 
2135 
CompileFastApiCall(const CallOptimization & optimization,Handle<Object> object,Handle<JSObject> holder,Handle<JSGlobalPropertyCell> cell,Handle<JSFunction> function,Handle<String> name)2136 Handle<Code> CallStubCompiler::CompileFastApiCall(
2137     const CallOptimization& optimization,
2138     Handle<Object> object,
2139     Handle<JSObject> holder,
2140     Handle<JSGlobalPropertyCell> cell,
2141     Handle<JSFunction> function,
2142     Handle<String> name) {
2143   ASSERT(optimization.is_simple_api_call());
2144   // Bail out if object is a global object as we don't want to
2145   // repatch it to global receiver.
2146   if (object->IsGlobalObject()) return Handle<Code>::null();
2147   if (!cell.is_null()) return Handle<Code>::null();
2148   if (!object->IsJSObject()) return Handle<Code>::null();
2149   int depth = optimization.GetPrototypeDepthOfExpectedType(
2150       Handle<JSObject>::cast(object), holder);
2151   if (depth == kInvalidProtoDepth) return Handle<Code>::null();
2152 
2153   Label miss, miss_before_stack_reserved;
2154 
2155   GenerateNameCheck(name, &miss_before_stack_reserved);
2156 
2157   // Get the receiver from the stack.
2158   const int argc = arguments().immediate();
2159   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2160 
2161   // Check that the receiver isn't a smi.
2162   __ JumpIfSmi(edx, &miss_before_stack_reserved);
2163 
2164   Counters* counters = isolate()->counters();
2165   __ IncrementCounter(counters->call_const(), 1);
2166   __ IncrementCounter(counters->call_const_fast_api(), 1);
2167 
2168   // Allocate space for v8::Arguments implicit values. Must be initialized
2169   // before calling any runtime function.
2170   __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize));
2171 
2172   // Check that the maps haven't changed and find a Holder as a side effect.
2173   CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2174                   name, depth, &miss);
2175 
2176   // Move the return address on top of the stack.
2177   __ mov(eax, Operand(esp, 3 * kPointerSize));
2178   __ mov(Operand(esp, 0 * kPointerSize), eax);
2179 
2180   // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
2181   // duplicate of return address and will be overwritten.
2182   GenerateFastApiCall(masm(), optimization, argc);
2183 
2184   __ bind(&miss);
2185   __ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
2186 
2187   __ bind(&miss_before_stack_reserved);
2188   GenerateMissBranch();
2189 
2190   // Return the generated code.
2191   return GetCode(function);
2192 }
2193 
2194 
CompileCallConstant(Handle<Object> object,Handle<JSObject> holder,Handle<JSFunction> function,Handle<String> name,CheckType check)2195 Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2196                                                    Handle<JSObject> holder,
2197                                                    Handle<JSFunction> function,
2198                                                    Handle<String> name,
2199                                                    CheckType check) {
2200   // ----------- S t a t e -------------
2201   //  -- ecx                 : name
2202   //  -- esp[0]              : return address
2203   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
2204   //  -- ...
2205   //  -- esp[(argc + 1) * 4] : receiver
2206   // -----------------------------------
2207 
2208   if (HasCustomCallGenerator(function)) {
2209     Handle<Code> code = CompileCustomCall(object, holder,
2210                                           Handle<JSGlobalPropertyCell>::null(),
2211                                           function, name);
2212     // A null handle means bail out to the regular compiler code below.
2213     if (!code.is_null()) return code;
2214   }
2215 
2216   Label miss;
2217   GenerateNameCheck(name, &miss);
2218 
2219   // Get the receiver from the stack.
2220   const int argc = arguments().immediate();
2221   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2222 
2223   // Check that the receiver isn't a smi.
2224   if (check != NUMBER_CHECK) {
2225     __ JumpIfSmi(edx, &miss);
2226   }
2227 
2228   // Make sure that it's okay not to patch the on stack receiver
2229   // unless we're doing a receiver map check.
2230   ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2231   switch (check) {
2232     case RECEIVER_MAP_CHECK:
2233       __ IncrementCounter(isolate()->counters()->call_const(), 1);
2234 
2235       // Check that the maps haven't changed.
2236       CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax,
2237                       edi, name, &miss);
2238 
2239       // Patch the receiver on the stack with the global proxy if
2240       // necessary.
2241       if (object->IsGlobalObject()) {
2242         __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2243         __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2244       }
2245       break;
2246 
2247     case STRING_CHECK:
2248       if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
2249         // Check that the object is a string or a symbol.
2250         __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
2251         __ j(above_equal, &miss);
2252         // Check that the maps starting from the prototype haven't changed.
2253         GenerateDirectLoadGlobalFunctionPrototype(
2254             masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
2255         CheckPrototypes(
2256             Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2257             eax, holder, ebx, edx, edi, name, &miss);
2258       } else {
2259         // Calling non-strict non-builtins with a value as the receiver
2260         // requires boxing.
2261         __ jmp(&miss);
2262       }
2263       break;
2264 
2265     case NUMBER_CHECK:
2266       if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
2267         Label fast;
2268         // Check that the object is a smi or a heap number.
2269         __ JumpIfSmi(edx, &fast);
2270         __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
2271         __ j(not_equal, &miss);
2272         __ bind(&fast);
2273         // Check that the maps starting from the prototype haven't changed.
2274         GenerateDirectLoadGlobalFunctionPrototype(
2275             masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
2276         CheckPrototypes(
2277             Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2278             eax, holder, ebx, edx, edi, name, &miss);
2279       } else {
2280         // Calling non-strict non-builtins with a value as the receiver
2281         // requires boxing.
2282         __ jmp(&miss);
2283       }
2284       break;
2285 
2286     case BOOLEAN_CHECK:
2287       if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
2288         Label fast;
2289         // Check that the object is a boolean.
2290         __ cmp(edx, factory()->true_value());
2291         __ j(equal, &fast);
2292         __ cmp(edx, factory()->false_value());
2293         __ j(not_equal, &miss);
2294         __ bind(&fast);
2295         // Check that the maps starting from the prototype haven't changed.
2296         GenerateDirectLoadGlobalFunctionPrototype(
2297             masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
2298         CheckPrototypes(
2299             Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2300             eax, holder, ebx, edx, edi, name, &miss);
2301       } else {
2302         // Calling non-strict non-builtins with a value as the receiver
2303         // requires boxing.
2304         __ jmp(&miss);
2305       }
2306       break;
2307   }
2308 
2309   CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2310       ? CALL_AS_FUNCTION
2311       : CALL_AS_METHOD;
2312   __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2313                     NullCallWrapper(), call_kind);
2314 
2315   // Handle call cache miss.
2316   __ bind(&miss);
2317   GenerateMissBranch();
2318 
2319   // Return the generated code.
2320   return GetCode(function);
2321 }
2322 
2323 
CompileCallInterceptor(Handle<JSObject> object,Handle<JSObject> holder,Handle<String> name)2324 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2325                                                       Handle<JSObject> holder,
2326                                                       Handle<String> name) {
2327   // ----------- S t a t e -------------
2328   //  -- ecx                 : name
2329   //  -- esp[0]              : return address
2330   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
2331   //  -- ...
2332   //  -- esp[(argc + 1) * 4] : receiver
2333   // -----------------------------------
2334   Label miss;
2335 
2336   GenerateNameCheck(name, &miss);
2337 
2338   // Get the number of arguments.
2339   const int argc = arguments().immediate();
2340 
2341   LookupResult lookup(isolate());
2342   LookupPostInterceptor(holder, name, &lookup);
2343 
2344   // Get the receiver from the stack.
2345   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2346 
2347   CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_);
2348   compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax,
2349                    &miss);
2350 
2351   // Restore receiver.
2352   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2353 
2354   // Check that the function really is a function.
2355   __ JumpIfSmi(eax, &miss);
2356   __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2357   __ j(not_equal, &miss);
2358 
2359   // Patch the receiver on the stack with the global proxy if
2360   // necessary.
2361   if (object->IsGlobalObject()) {
2362     __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2363     __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2364   }
2365 
2366   // Invoke the function.
2367   __ mov(edi, eax);
2368   CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2369       ? CALL_AS_FUNCTION
2370       : CALL_AS_METHOD;
2371   __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
2372                     NullCallWrapper(), call_kind);
2373 
2374   // Handle load cache miss.
2375   __ bind(&miss);
2376   GenerateMissBranch();
2377 
2378   // Return the generated code.
2379   return GetCode(INTERCEPTOR, name);
2380 }
2381 
2382 
CompileCallGlobal(Handle<JSObject> object,Handle<GlobalObject> holder,Handle<JSGlobalPropertyCell> cell,Handle<JSFunction> function,Handle<String> name)2383 Handle<Code> CallStubCompiler::CompileCallGlobal(
2384     Handle<JSObject> object,
2385     Handle<GlobalObject> holder,
2386     Handle<JSGlobalPropertyCell> cell,
2387     Handle<JSFunction> function,
2388     Handle<String> name) {
2389   // ----------- S t a t e -------------
2390   //  -- ecx                 : name
2391   //  -- esp[0]              : return address
2392   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
2393   //  -- ...
2394   //  -- esp[(argc + 1) * 4] : receiver
2395   // -----------------------------------
2396 
2397   if (HasCustomCallGenerator(function)) {
2398     Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2399     // A null handle means bail out to the regular compiler code below.
2400     if (!code.is_null()) return code;
2401   }
2402 
2403   Label miss;
2404   GenerateNameCheck(name, &miss);
2405 
2406   // Get the number of arguments.
2407   const int argc = arguments().immediate();
2408   GenerateGlobalReceiverCheck(object, holder, name, &miss);
2409   GenerateLoadFunctionFromCell(cell, function, &miss);
2410 
2411   // Patch the receiver on the stack with the global proxy.
2412   if (object->IsGlobalObject()) {
2413     __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2414     __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2415   }
2416 
2417   // Set up the context (function already in edi).
2418   __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2419 
2420   // Jump to the cached code (tail call).
2421   Counters* counters = isolate()->counters();
2422   __ IncrementCounter(counters->call_global_inline(), 1);
2423   ParameterCount expected(function->shared()->formal_parameter_count());
2424   CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2425       ? CALL_AS_FUNCTION
2426       : CALL_AS_METHOD;
2427   // We call indirectly through the code field in the function to
2428   // allow recompilation to take effect without changing any of the
2429   // call sites.
2430   __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2431                 expected, arguments(), JUMP_FUNCTION,
2432                 NullCallWrapper(), call_kind);
2433 
2434   // Handle call cache miss.
2435   __ bind(&miss);
2436   __ IncrementCounter(counters->call_global_inline_miss(), 1);
2437   GenerateMissBranch();
2438 
2439   // Return the generated code.
2440   return GetCode(NORMAL, name);
2441 }
2442 
2443 
CompileStoreField(Handle<JSObject> object,int index,Handle<Map> transition,Handle<String> name)2444 Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
2445                                                   int index,
2446                                                   Handle<Map> transition,
2447                                                   Handle<String> name) {
2448   // ----------- S t a t e -------------
2449   //  -- eax    : value
2450   //  -- ecx    : name
2451   //  -- edx    : receiver
2452   //  -- esp[0] : return address
2453   // -----------------------------------
2454   Label miss;
2455 
2456   // Generate store field code.  Trashes the name register.
2457   GenerateStoreField(masm(), object, index, transition, edx, ecx, ebx, &miss);
2458 
2459   // Handle store cache miss.
2460   __ bind(&miss);
2461   __ mov(ecx, Immediate(name));  // restore name
2462   Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2463   __ jmp(ic, RelocInfo::CODE_TARGET);
2464 
2465   // Return the generated code.
2466   return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
2467 }
2468 
2469 
CompileStoreCallback(Handle<JSObject> object,Handle<AccessorInfo> callback,Handle<String> name)2470 Handle<Code> StoreStubCompiler::CompileStoreCallback(
2471     Handle<JSObject> object,
2472     Handle<AccessorInfo> callback,
2473     Handle<String> name) {
2474   // ----------- S t a t e -------------
2475   //  -- eax    : value
2476   //  -- ecx    : name
2477   //  -- edx    : receiver
2478   //  -- esp[0] : return address
2479   // -----------------------------------
2480   Label miss;
2481 
2482   // Check that the map of the object hasn't changed.
2483   __ CheckMap(edx, Handle<Map>(object->map()),
2484               &miss, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
2485 
2486   // Perform global security token check if needed.
2487   if (object->IsJSGlobalProxy()) {
2488     __ CheckAccessGlobalProxy(edx, ebx, &miss);
2489   }
2490 
2491   // Stub never generated for non-global objects that require access
2492   // checks.
2493   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2494 
2495   __ pop(ebx);  // remove the return address
2496   __ push(edx);  // receiver
2497   __ push(Immediate(callback));  // callback info
2498   __ push(ecx);  // name
2499   __ push(eax);  // value
2500   __ push(ebx);  // restore return address
2501 
2502   // Do tail-call to the runtime system.
2503   ExternalReference store_callback_property =
2504       ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
2505   __ TailCallExternalReference(store_callback_property, 4, 1);
2506 
2507   // Handle store cache miss.
2508   __ bind(&miss);
2509   Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2510   __ jmp(ic, RelocInfo::CODE_TARGET);
2511 
2512   // Return the generated code.
2513   return GetCode(CALLBACKS, name);
2514 }
2515 
2516 
CompileStoreInterceptor(Handle<JSObject> receiver,Handle<String> name)2517 Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2518     Handle<JSObject> receiver,
2519     Handle<String> name) {
2520   // ----------- S t a t e -------------
2521   //  -- eax    : value
2522   //  -- ecx    : name
2523   //  -- edx    : receiver
2524   //  -- esp[0] : return address
2525   // -----------------------------------
2526   Label miss;
2527 
2528   // Check that the map of the object hasn't changed.
2529   __ CheckMap(edx, Handle<Map>(receiver->map()),
2530               &miss, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
2531 
2532   // Perform global security token check if needed.
2533   if (receiver->IsJSGlobalProxy()) {
2534     __ CheckAccessGlobalProxy(edx, ebx, &miss);
2535   }
2536 
2537   // Stub never generated for non-global objects that require access
2538   // checks.
2539   ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2540 
2541   __ pop(ebx);  // remove the return address
2542   __ push(edx);  // receiver
2543   __ push(ecx);  // name
2544   __ push(eax);  // value
2545   __ push(Immediate(Smi::FromInt(strict_mode_)));
2546   __ push(ebx);  // restore return address
2547 
2548   // Do tail-call to the runtime system.
2549   ExternalReference store_ic_property =
2550       ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
2551   __ TailCallExternalReference(store_ic_property, 4, 1);
2552 
2553   // Handle store cache miss.
2554   __ bind(&miss);
2555   Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2556   __ jmp(ic, RelocInfo::CODE_TARGET);
2557 
2558   // Return the generated code.
2559   return GetCode(INTERCEPTOR, name);
2560 }
2561 
2562 
CompileStoreGlobal(Handle<GlobalObject> object,Handle<JSGlobalPropertyCell> cell,Handle<String> name)2563 Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2564     Handle<GlobalObject> object,
2565     Handle<JSGlobalPropertyCell> cell,
2566     Handle<String> name) {
2567   // ----------- S t a t e -------------
2568   //  -- eax    : value
2569   //  -- ecx    : name
2570   //  -- edx    : receiver
2571   //  -- esp[0] : return address
2572   // -----------------------------------
2573   Label miss;
2574 
2575   // Check that the map of the global has not changed.
2576   __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2577          Immediate(Handle<Map>(object->map())));
2578   __ j(not_equal, &miss);
2579 
2580   // Compute the cell operand to use.
2581   __ mov(ebx, Immediate(cell));
2582   Operand cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset);
2583 
2584   // Check that the value in the cell is not the hole. If it is, this
2585   // cell could have been deleted and reintroducing the global needs
2586   // to update the property details in the property dictionary of the
2587   // global object. We bail out to the runtime system to do that.
2588   __ cmp(cell_operand, factory()->the_hole_value());
2589   __ j(equal, &miss);
2590 
2591   // Store the value in the cell.
2592   __ mov(cell_operand, eax);
2593   // No write barrier here, because cells are always rescanned.
2594 
2595   // Return the value (register eax).
2596   Counters* counters = isolate()->counters();
2597   __ IncrementCounter(counters->named_store_global_inline(), 1);
2598   __ ret(0);
2599 
2600   // Handle store cache miss.
2601   __ bind(&miss);
2602   __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
2603   Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2604   __ jmp(ic, RelocInfo::CODE_TARGET);
2605 
2606   // Return the generated code.
2607   return GetCode(NORMAL, name);
2608 }
2609 
2610 
CompileStoreField(Handle<JSObject> object,int index,Handle<Map> transition,Handle<String> name)2611 Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
2612                                                        int index,
2613                                                        Handle<Map> transition,
2614                                                        Handle<String> name) {
2615   // ----------- S t a t e -------------
2616   //  -- eax    : value
2617   //  -- ecx    : key
2618   //  -- edx    : receiver
2619   //  -- esp[0] : return address
2620   // -----------------------------------
2621   Label miss;
2622 
2623   Counters* counters = isolate()->counters();
2624   __ IncrementCounter(counters->keyed_store_field(), 1);
2625 
2626   // Check that the name has not changed.
2627   __ cmp(ecx, Immediate(name));
2628   __ j(not_equal, &miss);
2629 
2630   // Generate store field code.  Trashes the name register.
2631   GenerateStoreField(masm(), object, index, transition, edx, ecx, ebx, &miss);
2632 
2633   // Handle store cache miss.
2634   __ bind(&miss);
2635   __ DecrementCounter(counters->keyed_store_field(), 1);
2636   Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
2637   __ jmp(ic, RelocInfo::CODE_TARGET);
2638 
2639   // Return the generated code.
2640   return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
2641 }
2642 
2643 
CompileStoreElement(Handle<Map> receiver_map)2644 Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
2645     Handle<Map> receiver_map) {
2646   // ----------- S t a t e -------------
2647   //  -- eax    : value
2648   //  -- ecx    : key
2649   //  -- edx    : receiver
2650   //  -- esp[0] : return address
2651   // -----------------------------------
2652   ElementsKind elements_kind = receiver_map->elements_kind();
2653   bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
2654   Handle<Code> stub =
2655       KeyedStoreElementStub(is_jsarray, elements_kind, grow_mode_).GetCode();
2656 
2657   __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
2658 
2659   Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
2660   __ jmp(ic, RelocInfo::CODE_TARGET);
2661 
2662   // Return the generated code.
2663   return GetCode(NORMAL, factory()->empty_string());
2664 }
2665 
2666 
CompileStorePolymorphic(MapHandleList * receiver_maps,CodeHandleList * handler_stubs,MapHandleList * transitioned_maps)2667 Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2668     MapHandleList* receiver_maps,
2669     CodeHandleList* handler_stubs,
2670     MapHandleList* transitioned_maps) {
2671   // ----------- S t a t e -------------
2672   //  -- eax    : value
2673   //  -- ecx    : key
2674   //  -- edx    : receiver
2675   //  -- esp[0] : return address
2676   // -----------------------------------
2677   Label miss;
2678   __ JumpIfSmi(edx, &miss, Label::kNear);
2679   __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
2680   // ebx: receiver->map().
2681   for (int i = 0; i < receiver_maps->length(); ++i) {
2682     __ cmp(edi, receiver_maps->at(i));
2683     if (transitioned_maps->at(i).is_null()) {
2684       __ j(equal, handler_stubs->at(i));
2685     } else {
2686       Label next_map;
2687       __ j(not_equal, &next_map, Label::kNear);
2688       __ mov(ebx, Immediate(transitioned_maps->at(i)));
2689       __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
2690       __ bind(&next_map);
2691     }
2692   }
2693   __ bind(&miss);
2694   Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
2695   __ jmp(miss_ic, RelocInfo::CODE_TARGET);
2696 
2697   // Return the generated code.
2698   return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
2699 }
2700 
2701 
CompileLoadNonexistent(Handle<String> name,Handle<JSObject> object,Handle<JSObject> last)2702 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2703                                                       Handle<JSObject> object,
2704                                                       Handle<JSObject> last) {
2705   // ----------- S t a t e -------------
2706   //  -- eax    : receiver
2707   //  -- ecx    : name
2708   //  -- esp[0] : return address
2709   // -----------------------------------
2710   Label miss;
2711 
2712   // Check that the receiver isn't a smi.
2713   __ JumpIfSmi(eax, &miss);
2714 
2715   ASSERT(last->IsGlobalObject() || last->HasFastProperties());
2716 
2717   // Check the maps of the full prototype chain. Also check that
2718   // global property cells up to (but not including) the last object
2719   // in the prototype chain are empty.
2720   CheckPrototypes(object, eax, last, ebx, edx, edi, name, &miss);
2721 
2722   // If the last object in the prototype chain is a global object,
2723   // check that the global property cell is empty.
2724   if (last->IsGlobalObject()) {
2725     GenerateCheckPropertyCell(
2726         masm(), Handle<GlobalObject>::cast(last), name, edx, &miss);
2727   }
2728 
2729   // Return undefined if maps of the full prototype chain are still the
2730   // same and no global property with this name contains a value.
2731   __ mov(eax, isolate()->factory()->undefined_value());
2732   __ ret(0);
2733 
2734   __ bind(&miss);
2735   GenerateLoadMiss(masm(), Code::LOAD_IC);
2736 
2737   // Return the generated code.
2738   return GetCode(NONEXISTENT, factory()->empty_string());
2739 }
2740 
2741 
CompileLoadField(Handle<JSObject> object,Handle<JSObject> holder,int index,Handle<String> name)2742 Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2743                                                 Handle<JSObject> holder,
2744                                                 int index,
2745                                                 Handle<String> name) {
2746   // ----------- S t a t e -------------
2747   //  -- eax    : receiver
2748   //  -- ecx    : name
2749   //  -- esp[0] : return address
2750   // -----------------------------------
2751   Label miss;
2752 
2753   GenerateLoadField(object, holder, eax, ebx, edx, edi, index, name, &miss);
2754   __ bind(&miss);
2755   GenerateLoadMiss(masm(), Code::LOAD_IC);
2756 
2757   // Return the generated code.
2758   return GetCode(FIELD, name);
2759 }
2760 
2761 
CompileLoadCallback(Handle<String> name,Handle<JSObject> object,Handle<JSObject> holder,Handle<AccessorInfo> callback)2762 Handle<Code> LoadStubCompiler::CompileLoadCallback(
2763     Handle<String> name,
2764     Handle<JSObject> object,
2765     Handle<JSObject> holder,
2766     Handle<AccessorInfo> callback) {
2767   // ----------- S t a t e -------------
2768   //  -- eax    : receiver
2769   //  -- ecx    : name
2770   //  -- esp[0] : return address
2771   // -----------------------------------
2772   Label miss;
2773 
2774   GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, edi, callback,
2775                        name, &miss);
2776   __ bind(&miss);
2777   GenerateLoadMiss(masm(), Code::LOAD_IC);
2778 
2779   // Return the generated code.
2780   return GetCode(CALLBACKS, name);
2781 }
2782 
2783 
CompileLoadConstant(Handle<JSObject> object,Handle<JSObject> holder,Handle<JSFunction> value,Handle<String> name)2784 Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2785                                                    Handle<JSObject> holder,
2786                                                    Handle<JSFunction> value,
2787                                                    Handle<String> name) {
2788   // ----------- S t a t e -------------
2789   //  -- eax    : receiver
2790   //  -- ecx    : name
2791   //  -- esp[0] : return address
2792   // -----------------------------------
2793   Label miss;
2794 
2795   GenerateLoadConstant(object, holder, eax, ebx, edx, edi, value, name, &miss);
2796   __ bind(&miss);
2797   GenerateLoadMiss(masm(), Code::LOAD_IC);
2798 
2799   // Return the generated code.
2800   return GetCode(CONSTANT_FUNCTION, name);
2801 }
2802 
2803 
CompileLoadInterceptor(Handle<JSObject> receiver,Handle<JSObject> holder,Handle<String> name)2804 Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver,
2805                                                       Handle<JSObject> holder,
2806                                                       Handle<String> name) {
2807   // ----------- S t a t e -------------
2808   //  -- eax    : receiver
2809   //  -- ecx    : name
2810   //  -- esp[0] : return address
2811   // -----------------------------------
2812   Label miss;
2813 
2814   LookupResult lookup(isolate());
2815   LookupPostInterceptor(holder, name, &lookup);
2816 
2817   // TODO(368): Compile in the whole chain: all the interceptors in
2818   // prototypes and ultimate answer.
2819   GenerateLoadInterceptor(receiver, holder, &lookup, eax, ecx, edx, ebx, edi,
2820                           name, &miss);
2821 
2822   __ bind(&miss);
2823   GenerateLoadMiss(masm(), Code::LOAD_IC);
2824 
2825   // Return the generated code.
2826   return GetCode(INTERCEPTOR, name);
2827 }
2828 
2829 
CompileLoadGlobal(Handle<JSObject> object,Handle<GlobalObject> holder,Handle<JSGlobalPropertyCell> cell,Handle<String> name,bool is_dont_delete)2830 Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2831     Handle<JSObject> object,
2832     Handle<GlobalObject> holder,
2833     Handle<JSGlobalPropertyCell> cell,
2834     Handle<String> name,
2835     bool is_dont_delete) {
2836   // ----------- S t a t e -------------
2837   //  -- eax    : receiver
2838   //  -- ecx    : name
2839   //  -- esp[0] : return address
2840   // -----------------------------------
2841   Label miss;
2842 
2843   // Check that the maps haven't changed.
2844   __ JumpIfSmi(eax, &miss);
2845   CheckPrototypes(object, eax, holder, ebx, edx, edi, name, &miss);
2846 
2847   // Get the value from the cell.
2848   if (Serializer::enabled()) {
2849     __ mov(ebx, Immediate(cell));
2850     __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
2851   } else {
2852     __ mov(ebx, Operand::Cell(cell));
2853   }
2854 
2855   // Check for deleted property if property can actually be deleted.
2856   if (!is_dont_delete) {
2857     __ cmp(ebx, factory()->the_hole_value());
2858     __ j(equal, &miss);
2859   } else if (FLAG_debug_code) {
2860     __ cmp(ebx, factory()->the_hole_value());
2861     __ Check(not_equal, "DontDelete cells can't contain the hole");
2862   }
2863 
2864   Counters* counters = isolate()->counters();
2865   __ IncrementCounter(counters->named_load_global_stub(), 1);
2866   __ mov(eax, ebx);
2867   __ ret(0);
2868 
2869   __ bind(&miss);
2870   __ IncrementCounter(counters->named_load_global_stub_miss(), 1);
2871   GenerateLoadMiss(masm(), Code::LOAD_IC);
2872 
2873   // Return the generated code.
2874   return GetCode(NORMAL, name);
2875 }
2876 
2877 
CompileLoadField(Handle<String> name,Handle<JSObject> receiver,Handle<JSObject> holder,int index)2878 Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
2879                                                      Handle<JSObject> receiver,
2880                                                      Handle<JSObject> holder,
2881                                                      int index) {
2882   // ----------- S t a t e -------------
2883   //  -- eax    : key
2884   //  -- edx    : receiver
2885   //  -- esp[0] : return address
2886   // -----------------------------------
2887   Label miss;
2888 
2889   Counters* counters = isolate()->counters();
2890   __ IncrementCounter(counters->keyed_load_field(), 1);
2891 
2892   // Check that the name has not changed.
2893   __ cmp(eax, Immediate(name));
2894   __ j(not_equal, &miss);
2895 
2896   GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss);
2897 
2898   __ bind(&miss);
2899   __ DecrementCounter(counters->keyed_load_field(), 1);
2900   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2901 
2902   // Return the generated code.
2903   return GetCode(FIELD, name);
2904 }
2905 
2906 
CompileLoadCallback(Handle<String> name,Handle<JSObject> receiver,Handle<JSObject> holder,Handle<AccessorInfo> callback)2907 Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
2908     Handle<String> name,
2909     Handle<JSObject> receiver,
2910     Handle<JSObject> holder,
2911     Handle<AccessorInfo> callback) {
2912   // ----------- S t a t e -------------
2913   //  -- eax    : key
2914   //  -- edx    : receiver
2915   //  -- esp[0] : return address
2916   // -----------------------------------
2917   Label miss;
2918 
2919   Counters* counters = isolate()->counters();
2920   __ IncrementCounter(counters->keyed_load_callback(), 1);
2921 
2922   // Check that the name has not changed.
2923   __ cmp(eax, Immediate(name));
2924   __ j(not_equal, &miss);
2925 
2926   GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx, edi, callback,
2927                        name, &miss);
2928 
2929   __ bind(&miss);
2930   __ DecrementCounter(counters->keyed_load_callback(), 1);
2931   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2932 
2933   // Return the generated code.
2934   return GetCode(CALLBACKS, name);
2935 }
2936 
2937 
CompileLoadConstant(Handle<String> name,Handle<JSObject> receiver,Handle<JSObject> holder,Handle<JSFunction> value)2938 Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
2939     Handle<String> name,
2940     Handle<JSObject> receiver,
2941     Handle<JSObject> holder,
2942     Handle<JSFunction> value) {
2943   // ----------- S t a t e -------------
2944   //  -- eax    : key
2945   //  -- edx    : receiver
2946   //  -- esp[0] : return address
2947   // -----------------------------------
2948   Label miss;
2949 
2950   Counters* counters = isolate()->counters();
2951   __ IncrementCounter(counters->keyed_load_constant_function(), 1);
2952 
2953   // Check that the name has not changed.
2954   __ cmp(eax, Immediate(name));
2955   __ j(not_equal, &miss);
2956 
2957   GenerateLoadConstant(
2958       receiver, holder, edx, ebx, ecx, edi, value, name, &miss);
2959   __ bind(&miss);
2960   __ DecrementCounter(counters->keyed_load_constant_function(), 1);
2961   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2962 
2963   // Return the generated code.
2964   return GetCode(CONSTANT_FUNCTION, name);
2965 }
2966 
2967 
CompileLoadInterceptor(Handle<JSObject> receiver,Handle<JSObject> holder,Handle<String> name)2968 Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
2969     Handle<JSObject> receiver,
2970     Handle<JSObject> holder,
2971     Handle<String> name) {
2972   // ----------- S t a t e -------------
2973   //  -- eax    : key
2974   //  -- edx    : receiver
2975   //  -- esp[0] : return address
2976   // -----------------------------------
2977   Label miss;
2978 
2979   Counters* counters = isolate()->counters();
2980   __ IncrementCounter(counters->keyed_load_interceptor(), 1);
2981 
2982   // Check that the name has not changed.
2983   __ cmp(eax, Immediate(name));
2984   __ j(not_equal, &miss);
2985 
2986   LookupResult lookup(isolate());
2987   LookupPostInterceptor(holder, name, &lookup);
2988   GenerateLoadInterceptor(receiver, holder, &lookup, edx, eax, ecx, ebx, edi,
2989                           name, &miss);
2990   __ bind(&miss);
2991   __ DecrementCounter(counters->keyed_load_interceptor(), 1);
2992   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2993 
2994   // Return the generated code.
2995   return GetCode(INTERCEPTOR, name);
2996 }
2997 
2998 
CompileLoadArrayLength(Handle<String> name)2999 Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
3000     Handle<String> name) {
3001   // ----------- S t a t e -------------
3002   //  -- eax    : key
3003   //  -- edx    : receiver
3004   //  -- esp[0] : return address
3005   // -----------------------------------
3006   Label miss;
3007 
3008   Counters* counters = isolate()->counters();
3009   __ IncrementCounter(counters->keyed_load_array_length(), 1);
3010 
3011   // Check that the name has not changed.
3012   __ cmp(eax, Immediate(name));
3013   __ j(not_equal, &miss);
3014 
3015   GenerateLoadArrayLength(masm(), edx, ecx, &miss);
3016   __ bind(&miss);
3017   __ DecrementCounter(counters->keyed_load_array_length(), 1);
3018   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3019 
3020   // Return the generated code.
3021   return GetCode(CALLBACKS, name);
3022 }
3023 
3024 
CompileLoadStringLength(Handle<String> name)3025 Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
3026     Handle<String> name) {
3027   // ----------- S t a t e -------------
3028   //  -- eax    : key
3029   //  -- edx    : receiver
3030   //  -- esp[0] : return address
3031   // -----------------------------------
3032   Label miss;
3033 
3034   Counters* counters = isolate()->counters();
3035   __ IncrementCounter(counters->keyed_load_string_length(), 1);
3036 
3037   // Check that the name has not changed.
3038   __ cmp(eax, Immediate(name));
3039   __ j(not_equal, &miss);
3040 
3041   GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true);
3042   __ bind(&miss);
3043   __ DecrementCounter(counters->keyed_load_string_length(), 1);
3044   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3045 
3046   // Return the generated code.
3047   return GetCode(CALLBACKS, name);
3048 }
3049 
3050 
CompileLoadFunctionPrototype(Handle<String> name)3051 Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3052     Handle<String> name) {
3053   // ----------- S t a t e -------------
3054   //  -- eax    : key
3055   //  -- edx    : receiver
3056   //  -- esp[0] : return address
3057   // -----------------------------------
3058   Label miss;
3059 
3060   Counters* counters = isolate()->counters();
3061   __ IncrementCounter(counters->keyed_load_function_prototype(), 1);
3062 
3063   // Check that the name has not changed.
3064   __ cmp(eax, Immediate(name));
3065   __ j(not_equal, &miss);
3066 
3067   GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss);
3068   __ bind(&miss);
3069   __ DecrementCounter(counters->keyed_load_function_prototype(), 1);
3070   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3071 
3072   // Return the generated code.
3073   return GetCode(CALLBACKS, name);
3074 }
3075 
3076 
CompileLoadElement(Handle<Map> receiver_map)3077 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3078     Handle<Map> receiver_map) {
3079   // ----------- S t a t e -------------
3080   //  -- eax    : key
3081   //  -- edx    : receiver
3082   //  -- esp[0] : return address
3083   // -----------------------------------
3084 
3085   ElementsKind elements_kind = receiver_map->elements_kind();
3086   Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3087 
3088   __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
3089 
3090   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3091 
3092   // Return the generated code.
3093   return GetCode(NORMAL, factory()->empty_string());
3094 }
3095 
3096 
CompileLoadPolymorphic(MapHandleList * receiver_maps,CodeHandleList * handler_ics)3097 Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3098     MapHandleList* receiver_maps,
3099     CodeHandleList* handler_ics) {
3100   // ----------- S t a t e -------------
3101   //  -- eax    : key
3102   //  -- edx    : receiver
3103   //  -- esp[0] : return address
3104   // -----------------------------------
3105   Label miss;
3106   __ JumpIfSmi(edx, &miss);
3107 
3108   Register map_reg = ebx;
3109   __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
3110   int receiver_count = receiver_maps->length();
3111   for (int current = 0; current < receiver_count; ++current) {
3112     __ cmp(map_reg, receiver_maps->at(current));
3113     __ j(equal, handler_ics->at(current));
3114   }
3115 
3116   __ bind(&miss);
3117   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3118 
3119   // Return the generated code.
3120   return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
3121 }
3122 
3123 
3124 // Specialized stub for constructing objects from functions which only have only
3125 // simple assignments of the form this.x = ...; in their body.
CompileConstructStub(Handle<JSFunction> function)3126 Handle<Code> ConstructStubCompiler::CompileConstructStub(
3127     Handle<JSFunction> function) {
3128   // ----------- S t a t e -------------
3129   //  -- eax : argc
3130   //  -- edi : constructor
3131   //  -- esp[0] : return address
3132   //  -- esp[4] : last argument
3133   // -----------------------------------
3134   Label generic_stub_call;
3135 #ifdef ENABLE_DEBUGGER_SUPPORT
3136   // Check to see whether there are any break points in the function code. If
3137   // there are jump to the generic constructor stub which calls the actual
3138   // code for the function thereby hitting the break points.
3139   __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
3140   __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset));
3141   __ cmp(ebx, factory()->undefined_value());
3142   __ j(not_equal, &generic_stub_call);
3143 #endif
3144 
3145   // Load the initial map and verify that it is in fact a map.
3146   __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
3147   // Will both indicate a NULL and a Smi.
3148   __ JumpIfSmi(ebx, &generic_stub_call);
3149   __ CmpObjectType(ebx, MAP_TYPE, ecx);
3150   __ j(not_equal, &generic_stub_call);
3151 
3152 #ifdef DEBUG
3153   // Cannot construct functions this way.
3154   // edi: constructor
3155   // ebx: initial map
3156   __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
3157   __ Assert(not_equal, "Function constructed by construct stub.");
3158 #endif
3159 
3160   // Now allocate the JSObject on the heap by moving the new space allocation
3161   // top forward.
3162   // edi: constructor
3163   // ebx: initial map
3164   __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
3165   __ shl(ecx, kPointerSizeLog2);
3166   __ AllocateInNewSpace(ecx, edx, ecx, no_reg,
3167                         &generic_stub_call, NO_ALLOCATION_FLAGS);
3168 
3169   // Allocated the JSObject, now initialize the fields and add the heap tag.
3170   // ebx: initial map
3171   // edx: JSObject (untagged)
3172   __ mov(Operand(edx, JSObject::kMapOffset), ebx);
3173   __ mov(ebx, factory()->empty_fixed_array());
3174   __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
3175   __ mov(Operand(edx, JSObject::kElementsOffset), ebx);
3176 
3177   // Push the allocated object to the stack. This is the object that will be
3178   // returned (after it is tagged).
3179   __ push(edx);
3180 
3181   // eax: argc
3182   // edx: JSObject (untagged)
3183   // Load the address of the first in-object property into edx.
3184   __ lea(edx, Operand(edx, JSObject::kHeaderSize));
3185   // Calculate the location of the first argument. The stack contains the
3186   // allocated object and the return address on top of the argc arguments.
3187   __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
3188 
3189   // Use edi for holding undefined which is used in several places below.
3190   __ mov(edi, factory()->undefined_value());
3191 
3192   // eax: argc
3193   // ecx: first argument
3194   // edx: first in-object property of the JSObject
3195   // edi: undefined
3196   // Fill the initialized properties with a constant value or a passed argument
3197   // depending on the this.x = ...; assignment in the function.
3198   Handle<SharedFunctionInfo> shared(function->shared());
3199   for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3200     if (shared->IsThisPropertyAssignmentArgument(i)) {
3201       // Check if the argument assigned to the property is actually passed.
3202       // If argument is not passed the property is set to undefined,
3203       // otherwise find it on the stack.
3204       int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3205       __ mov(ebx, edi);
3206       __ cmp(eax, arg_number);
3207       if (CpuFeatures::IsSupported(CMOV)) {
3208         CpuFeatures::Scope use_cmov(CMOV);
3209         __ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize));
3210       } else {
3211         Label not_passed;
3212         __ j(below_equal, &not_passed);
3213         __ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
3214         __ bind(&not_passed);
3215       }
3216       // Store value in the property.
3217       __ mov(Operand(edx, i * kPointerSize), ebx);
3218     } else {
3219       // Set the property to the constant value.
3220       Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3221       __ mov(Operand(edx, i * kPointerSize), Immediate(constant));
3222     }
3223   }
3224 
3225   // Fill the unused in-object property fields with undefined.
3226   ASSERT(function->has_initial_map());
3227   for (int i = shared->this_property_assignments_count();
3228        i < function->initial_map()->inobject_properties();
3229        i++) {
3230     __ mov(Operand(edx, i * kPointerSize), edi);
3231   }
3232 
3233   // Move argc to ebx and retrieve and tag the JSObject to return.
3234   __ mov(ebx, eax);
3235   __ pop(eax);
3236   __ or_(eax, Immediate(kHeapObjectTag));
3237 
3238   // Remove caller arguments and receiver from the stack and return.
3239   __ pop(ecx);
3240   __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
3241   __ push(ecx);
3242   Counters* counters = isolate()->counters();
3243   __ IncrementCounter(counters->constructed_objects(), 1);
3244   __ IncrementCounter(counters->constructed_objects_stub(), 1);
3245   __ ret(0);
3246 
3247   // Jump to the generic stub in case the specialized code cannot handle the
3248   // construction.
3249   __ bind(&generic_stub_call);
3250   Handle<Code> code = isolate()->builtins()->JSConstructStubGeneric();
3251   __ jmp(code, RelocInfo::CODE_TARGET);
3252 
3253   // Return the generated code.
3254   return GetCode();
3255 }
3256 
3257 
3258 #undef __
3259 #define __ ACCESS_MASM(masm)
3260 
3261 
GenerateLoadDictionaryElement(MacroAssembler * masm)3262 void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3263     MacroAssembler* masm) {
3264   // ----------- S t a t e -------------
3265   //  -- eax    : key
3266   //  -- edx    : receiver
3267   //  -- esp[0] : return address
3268   // -----------------------------------
3269   Label slow, miss_force_generic;
3270 
3271   // This stub is meant to be tail-jumped to, the receiver must already
3272   // have been verified by the caller to not be a smi.
3273   __ JumpIfNotSmi(eax, &miss_force_generic);
3274   __ mov(ebx, eax);
3275   __ SmiUntag(ebx);
3276   __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
3277 
3278   // Push receiver on the stack to free up a register for the dictionary
3279   // probing.
3280   __ push(edx);
3281   __ LoadFromNumberDictionary(&slow,
3282                               ecx,
3283                               eax,
3284                               ebx,
3285                               edx,
3286                               edi,
3287                               eax);
3288   // Pop receiver before returning.
3289   __ pop(edx);
3290   __ ret(0);
3291 
3292   __ bind(&slow);
3293   __ pop(edx);
3294 
3295   // ----------- S t a t e -------------
3296   //  -- eax    : value
3297   //  -- ecx    : key
3298   //  -- edx    : receiver
3299   //  -- esp[0] : return address
3300   // -----------------------------------
3301 
3302   Handle<Code> slow_ic =
3303       masm->isolate()->builtins()->KeyedLoadIC_Slow();
3304   __ jmp(slow_ic, RelocInfo::CODE_TARGET);
3305 
3306   __ bind(&miss_force_generic);
3307   // ----------- S t a t e -------------
3308   //  -- eax    : value
3309   //  -- ecx    : key
3310   //  -- edx    : receiver
3311   //  -- esp[0] : return address
3312   // -----------------------------------
3313 
3314   Handle<Code> miss_force_generic_ic =
3315       masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3316   __ jmp(miss_force_generic_ic, RelocInfo::CODE_TARGET);
3317 }
3318 
3319 
GenerateLoadExternalArray(MacroAssembler * masm,ElementsKind elements_kind)3320 void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3321     MacroAssembler* masm,
3322     ElementsKind elements_kind) {
3323   // ----------- S t a t e -------------
3324   //  -- eax    : key
3325   //  -- edx    : receiver
3326   //  -- esp[0] : return address
3327   // -----------------------------------
3328   Label miss_force_generic, failed_allocation, slow;
3329 
3330   // This stub is meant to be tail-jumped to, the receiver must already
3331   // have been verified by the caller to not be a smi.
3332 
3333   // Check that the key is a smi.
3334   __ JumpIfNotSmi(eax, &miss_force_generic);
3335 
3336   // Check that the index is in range.
3337   __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
3338   __ cmp(eax, FieldOperand(ebx, ExternalArray::kLengthOffset));
3339   // Unsigned comparison catches both negative and too-large values.
3340   __ j(above_equal, &miss_force_generic);
3341   __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
3342   // ebx: base pointer of external storage
3343   switch (elements_kind) {
3344     case EXTERNAL_BYTE_ELEMENTS:
3345       __ SmiUntag(eax);  // Untag the index.
3346       __ movsx_b(eax, Operand(ebx, eax, times_1, 0));
3347       break;
3348     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3349     case EXTERNAL_PIXEL_ELEMENTS:
3350       __ SmiUntag(eax);  // Untag the index.
3351       __ movzx_b(eax, Operand(ebx, eax, times_1, 0));
3352       break;
3353     case EXTERNAL_SHORT_ELEMENTS:
3354       __ movsx_w(eax, Operand(ebx, eax, times_1, 0));
3355       break;
3356     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3357       __ movzx_w(eax, Operand(ebx, eax, times_1, 0));
3358       break;
3359     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3360     case EXTERNAL_INT_ELEMENTS:
3361       __ mov(ecx, Operand(ebx, eax, times_2, 0));
3362       break;
3363     case EXTERNAL_FLOAT_ELEMENTS:
3364       __ fld_s(Operand(ebx, eax, times_2, 0));
3365       break;
3366     case EXTERNAL_DOUBLE_ELEMENTS:
3367       __ fld_d(Operand(ebx, eax, times_4, 0));
3368       break;
3369     default:
3370       UNREACHABLE();
3371       break;
3372   }
3373 
3374   // For integer array types:
3375   // ecx: value
3376   // For floating-point array type:
3377   // FP(0): value
3378 
3379   if (elements_kind == EXTERNAL_INT_ELEMENTS ||
3380       elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
3381     // For the Int and UnsignedInt array types, we need to see whether
3382     // the value can be represented in a Smi. If not, we need to convert
3383     // it to a HeapNumber.
3384     Label box_int;
3385     if (elements_kind == EXTERNAL_INT_ELEMENTS) {
3386       __ cmp(ecx, 0xC0000000);
3387       __ j(sign, &box_int);
3388     } else {
3389       ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
3390       // The test is different for unsigned int values. Since we need
3391       // the value to be in the range of a positive smi, we can't
3392       // handle either of the top two bits being set in the value.
3393       __ test(ecx, Immediate(0xC0000000));
3394       __ j(not_zero, &box_int);
3395     }
3396 
3397     __ mov(eax, ecx);
3398     __ SmiTag(eax);
3399     __ ret(0);
3400 
3401     __ bind(&box_int);
3402 
3403     // Allocate a HeapNumber for the int and perform int-to-double
3404     // conversion.
3405     if (elements_kind == EXTERNAL_INT_ELEMENTS) {
3406       __ push(ecx);
3407       __ fild_s(Operand(esp, 0));
3408       __ pop(ecx);
3409     } else {
3410       ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
3411       // Need to zero-extend the value.
3412       // There's no fild variant for unsigned values, so zero-extend
3413       // to a 64-bit int manually.
3414       __ push(Immediate(0));
3415       __ push(ecx);
3416       __ fild_d(Operand(esp, 0));
3417       __ pop(ecx);
3418       __ pop(ecx);
3419     }
3420     // FP(0): value
3421     __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
3422     // Set the value.
3423     __ mov(eax, ecx);
3424     __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
3425     __ ret(0);
3426   } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
3427              elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3428     // For the floating-point array type, we need to always allocate a
3429     // HeapNumber.
3430     __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
3431     // Set the value.
3432     __ mov(eax, ecx);
3433     __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
3434     __ ret(0);
3435   } else {
3436     __ SmiTag(eax);
3437     __ ret(0);
3438   }
3439 
3440   // If we fail allocation of the HeapNumber, we still have a value on
3441   // top of the FPU stack. Remove it.
3442   __ bind(&failed_allocation);
3443   __ fstp(0);
3444   // Fall through to slow case.
3445 
3446   // Slow case: Jump to runtime.
3447   __ bind(&slow);
3448   Counters* counters = masm->isolate()->counters();
3449   __ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
3450 
3451   // ----------- S t a t e -------------
3452   //  -- eax    : key
3453   //  -- edx    : receiver
3454   //  -- esp[0] : return address
3455   // -----------------------------------
3456 
3457   Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Slow();
3458   __ jmp(ic, RelocInfo::CODE_TARGET);
3459 
3460   // ----------- S t a t e -------------
3461   //  -- eax    : key
3462   //  -- edx    : receiver
3463   //  -- esp[0] : return address
3464   // -----------------------------------
3465 
3466   // Miss case: Jump to runtime.
3467   __ bind(&miss_force_generic);
3468   Handle<Code> miss_ic =
3469       masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3470   __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3471 }
3472 
3473 
GenerateStoreExternalArray(MacroAssembler * masm,ElementsKind elements_kind)3474 void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3475     MacroAssembler* masm,
3476     ElementsKind elements_kind) {
3477   // ----------- S t a t e -------------
3478   //  -- eax    : key
3479   //  -- edx    : receiver
3480   //  -- esp[0] : return address
3481   // -----------------------------------
3482   Label miss_force_generic, slow, check_heap_number;
3483 
3484   // This stub is meant to be tail-jumped to, the receiver must already
3485   // have been verified by the caller to not be a smi.
3486 
3487   // Check that the key is a smi.
3488   __ JumpIfNotSmi(ecx, &miss_force_generic);
3489 
3490   // Check that the index is in range.
3491   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3492   __ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset));
3493   // Unsigned comparison catches both negative and too-large values.
3494   __ j(above_equal, &slow);
3495 
3496   // Handle both smis and HeapNumbers in the fast path. Go to the
3497   // runtime for all other kinds of values.
3498   // eax: value
3499   // edx: receiver
3500   // ecx: key
3501   // edi: elements array
3502   if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
3503     __ JumpIfNotSmi(eax, &slow);
3504   } else {
3505     __ JumpIfNotSmi(eax, &check_heap_number);
3506   }
3507 
3508   // smi case
3509   __ mov(ebx, eax);  // Preserve the value in eax as the return value.
3510   __ SmiUntag(ebx);
3511   __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
3512   // edi: base pointer of external storage
3513   switch (elements_kind) {
3514     case EXTERNAL_PIXEL_ELEMENTS:
3515       __ ClampUint8(ebx);
3516       __ SmiUntag(ecx);
3517       __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
3518       break;
3519     case EXTERNAL_BYTE_ELEMENTS:
3520     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3521       __ SmiUntag(ecx);
3522       __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
3523       break;
3524     case EXTERNAL_SHORT_ELEMENTS:
3525     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3526       __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
3527       break;
3528     case EXTERNAL_INT_ELEMENTS:
3529     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3530       __ mov(Operand(edi, ecx, times_2, 0), ebx);
3531       break;
3532     case EXTERNAL_FLOAT_ELEMENTS:
3533     case EXTERNAL_DOUBLE_ELEMENTS:
3534       // Need to perform int-to-float conversion.
3535       __ push(ebx);
3536       __ fild_s(Operand(esp, 0));
3537       __ pop(ebx);
3538       if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3539         __ fstp_s(Operand(edi, ecx, times_2, 0));
3540       } else {  // elements_kind == EXTERNAL_DOUBLE_ELEMENTS.
3541         __ fstp_d(Operand(edi, ecx, times_4, 0));
3542       }
3543       break;
3544     default:
3545       UNREACHABLE();
3546       break;
3547   }
3548   __ ret(0);  // Return the original value.
3549 
3550   // TODO(danno): handle heap number -> pixel array conversion
3551   if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
3552     __ bind(&check_heap_number);
3553     // eax: value
3554     // edx: receiver
3555     // ecx: key
3556     // edi: elements array
3557     __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3558            Immediate(masm->isolate()->factory()->heap_number_map()));
3559     __ j(not_equal, &slow);
3560 
3561     // The WebGL specification leaves the behavior of storing NaN and
3562     // +/-Infinity into integer arrays basically undefined. For more
3563     // reproducible behavior, convert these to zero.
3564     __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
3565     // edi: base pointer of external storage
3566     if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3567       __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
3568       __ fstp_s(Operand(edi, ecx, times_2, 0));
3569       __ ret(0);
3570     } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3571       __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
3572       __ fstp_d(Operand(edi, ecx, times_4, 0));
3573       __ ret(0);
3574     } else {
3575       // Perform float-to-int conversion with truncation (round-to-zero)
3576       // behavior.
3577 
3578       // For the moment we make the slow call to the runtime on
3579       // processors that don't support SSE2. The code in IntegerConvert
3580       // (code-stubs-ia32.cc) is roughly what is needed here though the
3581       // conversion failure case does not need to be handled.
3582       if (CpuFeatures::IsSupported(SSE2)) {
3583         if (elements_kind != EXTERNAL_INT_ELEMENTS &&
3584             elements_kind != EXTERNAL_UNSIGNED_INT_ELEMENTS) {
3585           ASSERT(CpuFeatures::IsSupported(SSE2));
3586           CpuFeatures::Scope scope(SSE2);
3587           __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
3588           // ecx: untagged integer value
3589           switch (elements_kind) {
3590             case EXTERNAL_PIXEL_ELEMENTS:
3591               __ ClampUint8(ebx);
3592               // Fall through.
3593             case EXTERNAL_BYTE_ELEMENTS:
3594             case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3595               __ SmiUntag(ecx);
3596               __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
3597               break;
3598             case EXTERNAL_SHORT_ELEMENTS:
3599             case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3600               __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
3601               break;
3602             default:
3603               UNREACHABLE();
3604               break;
3605           }
3606         } else {
3607           if (CpuFeatures::IsSupported(SSE3)) {
3608             CpuFeatures::Scope scope(SSE3);
3609             // fisttp stores values as signed integers. To represent the
3610             // entire range of int and unsigned int arrays, store as a
3611             // 64-bit int and discard the high 32 bits.
3612             // If the value is NaN or +/-infinity, the result is 0x80000000,
3613             // which is automatically zero when taken mod 2^n, n < 32.
3614             __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
3615             __ sub(esp, Immediate(2 * kPointerSize));
3616             __ fisttp_d(Operand(esp, 0));
3617             __ pop(ebx);
3618             __ add(esp, Immediate(kPointerSize));
3619           } else {
3620             ASSERT(CpuFeatures::IsSupported(SSE2));
3621             CpuFeatures::Scope scope(SSE2);
3622             // We can easily implement the correct rounding behavior for the
3623             // range [0, 2^31-1]. For the time being, to keep this code simple,
3624             // make the slow runtime call for values outside this range.
3625             // Note: we could do better for signed int arrays.
3626             __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
3627             // We will need the key if we have to make the slow runtime call.
3628             __ push(ebx);
3629             __ LoadPowerOf2(xmm1, ebx, 31);
3630             __ pop(ebx);
3631             __ ucomisd(xmm1, xmm0);
3632             __ j(above_equal, &slow);
3633             __ cvttsd2si(ebx, Operand(xmm0));
3634           }
3635           // ebx: untagged integer value
3636           __ mov(Operand(edi, ecx, times_2, 0), ebx);
3637         }
3638         __ ret(0);  // Return original value.
3639       }
3640     }
3641   }
3642 
3643   // Slow case: call runtime.
3644   __ bind(&slow);
3645   Counters* counters = masm->isolate()->counters();
3646   __ IncrementCounter(counters->keyed_store_external_array_slow(), 1);
3647 
3648   // ----------- S t a t e -------------
3649   //  -- eax    : value
3650   //  -- ecx    : key
3651   //  -- edx    : receiver
3652   //  -- esp[0] : return address
3653   // -----------------------------------
3654 
3655   Handle<Code> ic = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3656   __ jmp(ic, RelocInfo::CODE_TARGET);
3657 
3658   // ----------- S t a t e -------------
3659   //  -- eax    : value
3660   //  -- ecx    : key
3661   //  -- edx    : receiver
3662   //  -- esp[0] : return address
3663   // -----------------------------------
3664 
3665   __ bind(&miss_force_generic);
3666   Handle<Code> miss_ic =
3667       masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3668   __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3669 }
3670 
3671 
GenerateLoadFastElement(MacroAssembler * masm)3672 void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
3673   // ----------- S t a t e -------------
3674   //  -- eax    : key
3675   //  -- edx    : receiver
3676   //  -- esp[0] : return address
3677   // -----------------------------------
3678   Label miss_force_generic;
3679 
3680   // This stub is meant to be tail-jumped to, the receiver must already
3681   // have been verified by the caller to not be a smi.
3682 
3683   // Check that the key is a smi.
3684   __ JumpIfNotSmi(eax, &miss_force_generic);
3685 
3686   // Get the elements array.
3687   __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
3688   __ AssertFastElements(ecx);
3689 
3690   // Check that the key is within bounds.
3691   __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
3692   __ j(above_equal, &miss_force_generic);
3693 
3694   // Load the result and make sure it's not the hole.
3695   __ mov(ebx, Operand(ecx, eax, times_2,
3696                       FixedArray::kHeaderSize - kHeapObjectTag));
3697   __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
3698   __ j(equal, &miss_force_generic);
3699   __ mov(eax, ebx);
3700   __ ret(0);
3701 
3702   __ bind(&miss_force_generic);
3703   Handle<Code> miss_ic =
3704       masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3705   __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3706 }
3707 
3708 
GenerateLoadFastDoubleElement(MacroAssembler * masm)3709 void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
3710     MacroAssembler* masm) {
3711   // ----------- S t a t e -------------
3712   //  -- eax    : key
3713   //  -- edx    : receiver
3714   //  -- esp[0] : return address
3715   // -----------------------------------
3716   Label miss_force_generic, slow_allocate_heapnumber;
3717 
3718   // This stub is meant to be tail-jumped to, the receiver must already
3719   // have been verified by the caller to not be a smi.
3720 
3721   // Check that the key is a smi.
3722   __ JumpIfNotSmi(eax, &miss_force_generic);
3723 
3724   // Get the elements array.
3725   __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
3726   __ AssertFastElements(ecx);
3727 
3728   // Check that the key is within bounds.
3729   __ cmp(eax, FieldOperand(ecx, FixedDoubleArray::kLengthOffset));
3730   __ j(above_equal, &miss_force_generic);
3731 
3732   // Check for the hole
3733   uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
3734   __ cmp(FieldOperand(ecx, eax, times_4, offset), Immediate(kHoleNanUpper32));
3735   __ j(equal, &miss_force_generic);
3736 
3737   // Always allocate a heap number for the result.
3738   if (CpuFeatures::IsSupported(SSE2)) {
3739     CpuFeatures::Scope use_sse2(SSE2);
3740     __ movdbl(xmm0, FieldOperand(ecx, eax, times_4,
3741                                  FixedDoubleArray::kHeaderSize));
3742   } else {
3743     __ fld_d(FieldOperand(ecx, eax, times_4, FixedDoubleArray::kHeaderSize));
3744   }
3745   __ AllocateHeapNumber(ecx, ebx, edi, &slow_allocate_heapnumber);
3746   // Set the value.
3747   if (CpuFeatures::IsSupported(SSE2)) {
3748     CpuFeatures::Scope use_sse2(SSE2);
3749     __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0);
3750   } else {
3751     __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset));
3752   }
3753   __ mov(eax, ecx);
3754   __ ret(0);
3755 
3756   __ bind(&slow_allocate_heapnumber);
3757   // A value was pushed on the floating point stack before the allocation, if
3758   // the allocation fails it needs to be removed.
3759   if (!CpuFeatures::IsSupported(SSE2)) {
3760     __ fstp(0);
3761   }
3762   Handle<Code> slow_ic =
3763       masm->isolate()->builtins()->KeyedLoadIC_Slow();
3764   __ jmp(slow_ic, RelocInfo::CODE_TARGET);
3765 
3766   __ bind(&miss_force_generic);
3767   Handle<Code> miss_ic =
3768       masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3769   __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3770 }
3771 
3772 
GenerateStoreFastElement(MacroAssembler * masm,bool is_js_array,ElementsKind elements_kind,KeyedAccessGrowMode grow_mode)3773 void KeyedStoreStubCompiler::GenerateStoreFastElement(
3774     MacroAssembler* masm,
3775     bool is_js_array,
3776     ElementsKind elements_kind,
3777     KeyedAccessGrowMode grow_mode) {
3778   // ----------- S t a t e -------------
3779   //  -- eax    : value
3780   //  -- ecx    : key
3781   //  -- edx    : receiver
3782   //  -- esp[0] : return address
3783   // -----------------------------------
3784   Label miss_force_generic, grow, slow, transition_elements_kind;
3785   Label check_capacity, prepare_slow, finish_store, commit_backing_store;
3786 
3787   // This stub is meant to be tail-jumped to, the receiver must already
3788   // have been verified by the caller to not be a smi.
3789 
3790   // Check that the key is a smi.
3791   __ JumpIfNotSmi(ecx, &miss_force_generic);
3792 
3793   if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
3794     __ JumpIfNotSmi(eax, &transition_elements_kind);
3795   }
3796 
3797   // Get the elements array and make sure it is a fast element array, not 'cow'.
3798   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3799   if (is_js_array) {
3800     // Check that the key is within bounds.
3801     __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // smis.
3802     if (grow_mode == ALLOW_JSARRAY_GROWTH) {
3803       __ j(above_equal, &grow);
3804     } else {
3805       __ j(above_equal, &miss_force_generic);
3806     }
3807   } else {
3808     // Check that the key is within bounds.
3809     __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));  // smis.
3810     __ j(above_equal, &miss_force_generic);
3811   }
3812 
3813   __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
3814          Immediate(masm->isolate()->factory()->fixed_array_map()));
3815   __ j(not_equal, &miss_force_generic);
3816 
3817   __ bind(&finish_store);
3818   if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
3819     // ecx is a smi, use times_half_pointer_size instead of
3820     // times_pointer_size
3821     __ mov(FieldOperand(edi,
3822                         ecx,
3823                         times_half_pointer_size,
3824                         FixedArray::kHeaderSize), eax);
3825   } else {
3826     ASSERT(elements_kind == FAST_ELEMENTS);
3827     // Do the store and update the write barrier.
3828     // ecx is a smi, use times_half_pointer_size instead of
3829     // times_pointer_size
3830     __ lea(ecx, FieldOperand(edi,
3831                              ecx,
3832                              times_half_pointer_size,
3833                              FixedArray::kHeaderSize));
3834     __ mov(Operand(ecx, 0), eax);
3835     // Make sure to preserve the value in register eax.
3836     __ mov(ebx, eax);
3837     __ RecordWrite(edi, ecx, ebx, kDontSaveFPRegs);
3838   }
3839 
3840   // Done.
3841   __ ret(0);
3842 
3843   // Handle store cache miss, replacing the ic with the generic stub.
3844   __ bind(&miss_force_generic);
3845   Handle<Code> ic_force_generic =
3846       masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3847   __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
3848 
3849   // Handle transition to other elements kinds without using the generic stub.
3850   __ bind(&transition_elements_kind);
3851   Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
3852   __ jmp(ic_miss, RelocInfo::CODE_TARGET);
3853 
3854   if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3855     // Handle transition requiring the array to grow.
3856     __ bind(&grow);
3857 
3858     // Make sure the array is only growing by a single element, anything else
3859     // must be handled by the runtime. Flags are already set by previous
3860     // compare.
3861     __ j(not_equal, &miss_force_generic);
3862 
3863     // Check for the empty array, and preallocate a small backing store if
3864     // possible.
3865     __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3866     __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
3867     __ j(not_equal, &check_capacity);
3868 
3869     int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
3870     __ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
3871     // Restore the key, which is known to be the array length.
3872 
3873     // eax: value
3874     // ecx: key
3875     // edx: receiver
3876     // edi: elements
3877     // Make sure that the backing store can hold additional elements.
3878     __ mov(FieldOperand(edi, JSObject::kMapOffset),
3879            Immediate(masm->isolate()->factory()->fixed_array_map()));
3880     __ mov(FieldOperand(edi, FixedArray::kLengthOffset),
3881            Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3882     __ mov(ebx, Immediate(masm->isolate()->factory()->the_hole_value()));
3883     for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3884       __ mov(FieldOperand(edi, FixedArray::SizeFor(i)), ebx);
3885     }
3886 
3887     // Store the element at index zero.
3888     __ mov(FieldOperand(edi, FixedArray::SizeFor(0)), eax);
3889 
3890     // Install the new backing store in the JSArray.
3891     __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
3892     __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
3893                         kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3894 
3895     // Increment the length of the array.
3896     __ mov(FieldOperand(edx, JSArray::kLengthOffset),
3897            Immediate(Smi::FromInt(1)));
3898     __ ret(0);
3899 
3900     __ bind(&check_capacity);
3901     __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
3902            Immediate(masm->isolate()->factory()->fixed_cow_array_map()));
3903     __ j(equal, &miss_force_generic);
3904 
3905     // eax: value
3906     // ecx: key
3907     // edx: receiver
3908     // edi: elements
3909     // Make sure that the backing store can hold additional elements.
3910     __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
3911     __ j(above_equal, &slow);
3912 
3913     // Grow the array and finish the store.
3914     __ add(FieldOperand(edx, JSArray::kLengthOffset),
3915            Immediate(Smi::FromInt(1)));
3916     __ jmp(&finish_store);
3917 
3918     __ bind(&prepare_slow);
3919     // Restore the key, which is known to be the array length.
3920     __ mov(ecx, Immediate(0));
3921 
3922     __ bind(&slow);
3923     Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3924     __ jmp(ic_slow, RelocInfo::CODE_TARGET);
3925   }
3926 }
3927 
3928 
GenerateStoreFastDoubleElement(MacroAssembler * masm,bool is_js_array,KeyedAccessGrowMode grow_mode)3929 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3930     MacroAssembler* masm,
3931     bool is_js_array,
3932     KeyedAccessGrowMode grow_mode) {
3933   // ----------- S t a t e -------------
3934   //  -- eax    : value
3935   //  -- ecx    : key
3936   //  -- edx    : receiver
3937   //  -- esp[0] : return address
3938   // -----------------------------------
3939   Label miss_force_generic, transition_elements_kind, grow, slow;
3940   Label check_capacity, prepare_slow, finish_store, commit_backing_store;
3941 
3942   // This stub is meant to be tail-jumped to, the receiver must already
3943   // have been verified by the caller to not be a smi.
3944 
3945   // Check that the key is a smi.
3946   __ JumpIfNotSmi(ecx, &miss_force_generic);
3947 
3948   // Get the elements array.
3949   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3950   __ AssertFastElements(edi);
3951 
3952   if (is_js_array) {
3953     // Check that the key is within bounds.
3954     __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // smis.
3955     if (grow_mode == ALLOW_JSARRAY_GROWTH) {
3956       __ j(above_equal, &grow);
3957     } else {
3958       __ j(above_equal, &miss_force_generic);
3959     }
3960   } else {
3961     // Check that the key is within bounds.
3962     __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));  // smis.
3963     __ j(above_equal, &miss_force_generic);
3964   }
3965 
3966   __ bind(&finish_store);
3967   __ StoreNumberToDoubleElements(eax, edi, ecx, edx, xmm0,
3968                                  &transition_elements_kind, true);
3969   __ ret(0);
3970 
3971   // Handle store cache miss, replacing the ic with the generic stub.
3972   __ bind(&miss_force_generic);
3973   Handle<Code> ic_force_generic =
3974       masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3975   __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
3976 
3977   // Handle transition to other elements kinds without using the generic stub.
3978   __ bind(&transition_elements_kind);
3979   Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
3980   __ jmp(ic_miss, RelocInfo::CODE_TARGET);
3981 
3982   if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3983     // Handle transition requiring the array to grow.
3984     __ bind(&grow);
3985 
3986     // Make sure the array is only growing by a single element, anything else
3987     // must be handled by the runtime. Flags are already set by previous
3988     // compare.
3989     __ j(not_equal, &miss_force_generic);
3990 
3991     // Transition on values that can't be stored in a FixedDoubleArray.
3992     Label value_is_smi;
3993     __ JumpIfSmi(eax, &value_is_smi);
3994     __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3995            Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
3996     __ j(not_equal, &transition_elements_kind);
3997     __ bind(&value_is_smi);
3998 
3999     // Check for the empty array, and preallocate a small backing store if
4000     // possible.
4001     __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4002     __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
4003     __ j(not_equal, &check_capacity);
4004 
4005     int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4006     __ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
4007     // Restore the key, which is known to be the array length.
4008     __ mov(ecx, Immediate(0));
4009 
4010     // eax: value
4011     // ecx: key
4012     // edx: receiver
4013     // edi: elements
4014     // Initialize the new FixedDoubleArray. Leave elements unitialized for
4015     // efficiency, they are guaranteed to be initialized before use.
4016     __ mov(FieldOperand(edi, JSObject::kMapOffset),
4017            Immediate(masm->isolate()->factory()->fixed_double_array_map()));
4018     __ mov(FieldOperand(edi, FixedDoubleArray::kLengthOffset),
4019            Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4020 
4021     // Install the new backing store in the JSArray.
4022     __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
4023     __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
4024                         kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4025 
4026     // Increment the length of the array.
4027     __ add(FieldOperand(edx, JSArray::kLengthOffset),
4028            Immediate(Smi::FromInt(1)));
4029     __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4030     __ jmp(&finish_store);
4031 
4032     __ bind(&check_capacity);
4033     // eax: value
4034     // ecx: key
4035     // edx: receiver
4036     // edi: elements
4037     // Make sure that the backing store can hold additional elements.
4038     __ cmp(ecx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
4039     __ j(above_equal, &slow);
4040 
4041     // Grow the array and finish the store.
4042     __ add(FieldOperand(edx, JSArray::kLengthOffset),
4043            Immediate(Smi::FromInt(1)));
4044     __ jmp(&finish_store);
4045 
4046     __ bind(&prepare_slow);
4047     // Restore the key, which is known to be the array length.
4048     __ mov(ecx, Immediate(0));
4049 
4050     __ bind(&slow);
4051     Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4052     __ jmp(ic_slow, RelocInfo::CODE_TARGET);
4053   }
4054 }
4055 
4056 
4057 #undef __
4058 
4059 } }  // namespace v8::internal
4060 
4061 #endif  // V8_TARGET_ARCH_IA32
4062