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
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
42static 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.
145static 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
191void 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
263void 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
273void 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
292void 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.
311static 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
328void 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
361void 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.
375void 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
395static 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
412static 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.
427static 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.
434static 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.
448static 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.
464static 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
526class CallInterceptorCompiler BASE_EMBEDDED {
527 public:
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
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:
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
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
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
722void 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
731void 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.
740void 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.
830static 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.
852static 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
875Register 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
983void 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
1005void 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
1066void 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
1088void 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
1244void 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
1252void 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
1271void 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
1304void 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
1313Handle<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
1369Handle<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
1576Handle<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
1658Handle<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
1741Handle<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
1826Handle<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
1901Handle<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
2031Handle<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
2136Handle<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
2195Handle<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
2324Handle<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
2383Handle<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
2444Handle<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
2470Handle<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
2517Handle<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
2563Handle<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
2611Handle<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
2644Handle<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
2667Handle<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
2702Handle<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
2742Handle<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
2762Handle<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
2784Handle<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
2804Handle<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
2830Handle<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
2878Handle<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
2907Handle<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
2938Handle<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
2968Handle<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
2999Handle<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
3025Handle<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
3051Handle<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
3077Handle<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
3097Handle<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.
3126Handle<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
3262void 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
3320void 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
3474void 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
3672void 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
3709void 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
3773void 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
3929void 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