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 V8_TARGET_ARCH_MIPS
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 receiver,
47                       Register name,
48                       // Number of the cache entry, not scaled.
49                       Register offset,
50                       Register scratch,
51                       Register scratch2,
52                       Register offset_scratch) {
53  ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
54  ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
55  ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
56
57  uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
58  uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
59  uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
60
61  // Check the relative positions of the address fields.
62  ASSERT(value_off_addr > key_off_addr);
63  ASSERT((value_off_addr - key_off_addr) % 4 == 0);
64  ASSERT((value_off_addr - key_off_addr) < (256 * 4));
65  ASSERT(map_off_addr > key_off_addr);
66  ASSERT((map_off_addr - key_off_addr) % 4 == 0);
67  ASSERT((map_off_addr - key_off_addr) < (256 * 4));
68
69  Label miss;
70  Register base_addr = scratch;
71  scratch = no_reg;
72
73  // Multiply by 3 because there are 3 fields per entry (name, code, map).
74  __ sll(offset_scratch, offset, 1);
75  __ Addu(offset_scratch, offset_scratch, offset);
76
77  // Calculate the base address of the entry.
78  __ li(base_addr, Operand(key_offset));
79  __ sll(at, offset_scratch, kPointerSizeLog2);
80  __ Addu(base_addr, base_addr, at);
81
82  // Check that the key in the entry matches the name.
83  __ lw(at, MemOperand(base_addr, 0));
84  __ Branch(&miss, ne, name, Operand(at));
85
86  // Check the map matches.
87  __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr));
88  __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
89  __ Branch(&miss, ne, at, Operand(scratch2));
90
91  // Get the code entry from the cache.
92  Register code = scratch2;
93  scratch2 = no_reg;
94  __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr));
95
96  // Check that the flags match what we're looking for.
97  Register flags_reg = base_addr;
98  base_addr = no_reg;
99  __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
100  __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
101  __ Branch(&miss, ne, flags_reg, Operand(flags));
102
103#ifdef DEBUG
104    if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
105      __ jmp(&miss);
106    } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
107      __ jmp(&miss);
108    }
109#endif
110
111  // Jump to the first instruction in the code stub.
112  __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
113  __ Jump(at);
114
115  // Miss: fall through.
116  __ bind(&miss);
117}
118
119
120void StubCompiler::GenerateDictionaryNegativeLookup(MacroAssembler* masm,
121                                                    Label* miss_label,
122                                                    Register receiver,
123                                                    Handle<Name> name,
124                                                    Register scratch0,
125                                                    Register scratch1) {
126  ASSERT(name->IsUniqueName());
127  ASSERT(!receiver.is(scratch0));
128  Counters* counters = masm->isolate()->counters();
129  __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
130  __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
131
132  Label done;
133
134  const int kInterceptorOrAccessCheckNeededMask =
135      (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
136
137  // Bail out if the receiver has a named interceptor or requires access checks.
138  Register map = scratch1;
139  __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
140  __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
141  __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
142  __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
143
144  // Check that receiver is a JSObject.
145  __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
146  __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
147
148  // Load properties array.
149  Register properties = scratch0;
150  __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
151  // Check that the properties array is a dictionary.
152  __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
153  Register tmp = properties;
154  __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
155  __ Branch(miss_label, ne, map, Operand(tmp));
156
157  // Restore the temporarily used register.
158  __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
159
160
161  NameDictionaryLookupStub::GenerateNegativeLookup(masm,
162                                                   miss_label,
163                                                   &done,
164                                                   receiver,
165                                                   properties,
166                                                   name,
167                                                   scratch1);
168  __ bind(&done);
169  __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
170}
171
172
173void StubCache::GenerateProbe(MacroAssembler* masm,
174                              Code::Flags flags,
175                              Register receiver,
176                              Register name,
177                              Register scratch,
178                              Register extra,
179                              Register extra2,
180                              Register extra3) {
181  Isolate* isolate = masm->isolate();
182  Label miss;
183
184  // Make sure that code is valid. The multiplying code relies on the
185  // entry size being 12.
186  ASSERT(sizeof(Entry) == 12);
187
188  // Make sure the flags does not name a specific type.
189  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
190
191  // Make sure that there are no register conflicts.
192  ASSERT(!scratch.is(receiver));
193  ASSERT(!scratch.is(name));
194  ASSERT(!extra.is(receiver));
195  ASSERT(!extra.is(name));
196  ASSERT(!extra.is(scratch));
197  ASSERT(!extra2.is(receiver));
198  ASSERT(!extra2.is(name));
199  ASSERT(!extra2.is(scratch));
200  ASSERT(!extra2.is(extra));
201
202  // Check register validity.
203  ASSERT(!scratch.is(no_reg));
204  ASSERT(!extra.is(no_reg));
205  ASSERT(!extra2.is(no_reg));
206  ASSERT(!extra3.is(no_reg));
207
208  Counters* counters = masm->isolate()->counters();
209  __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
210                      extra2, extra3);
211
212  // Check that the receiver isn't a smi.
213  __ JumpIfSmi(receiver, &miss);
214
215  // Get the map of the receiver and compute the hash.
216  __ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
217  __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
218  __ Addu(scratch, scratch, at);
219  uint32_t mask = kPrimaryTableSize - 1;
220  // We shift out the last two bits because they are not part of the hash and
221  // they are always 01 for maps.
222  __ srl(scratch, scratch, kHeapObjectTagSize);
223  __ Xor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
224  __ And(scratch, scratch, Operand(mask));
225
226  // Probe the primary table.
227  ProbeTable(isolate,
228             masm,
229             flags,
230             kPrimary,
231             receiver,
232             name,
233             scratch,
234             extra,
235             extra2,
236             extra3);
237
238  // Primary miss: Compute hash for secondary probe.
239  __ srl(at, name, kHeapObjectTagSize);
240  __ Subu(scratch, scratch, at);
241  uint32_t mask2 = kSecondaryTableSize - 1;
242  __ Addu(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
243  __ And(scratch, scratch, Operand(mask2));
244
245  // Probe the secondary table.
246  ProbeTable(isolate,
247             masm,
248             flags,
249             kSecondary,
250             receiver,
251             name,
252             scratch,
253             extra,
254             extra2,
255             extra3);
256
257  // Cache miss: Fall-through and let caller handle the miss by
258  // entering the runtime system.
259  __ bind(&miss);
260  __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
261                      extra2, extra3);
262}
263
264
265void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
266                                                       int index,
267                                                       Register prototype) {
268  // Load the global or builtins object from the current context.
269  __ lw(prototype,
270        MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
271  // Load the native context from the global or builtins object.
272  __ lw(prototype,
273         FieldMemOperand(prototype, GlobalObject::kNativeContextOffset));
274  // Load the function from the native context.
275  __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
276  // Load the initial map.  The global functions all have initial maps.
277  __ lw(prototype,
278         FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
279  // Load the prototype from the initial map.
280  __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
281}
282
283
284void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
285    MacroAssembler* masm,
286    int index,
287    Register prototype,
288    Label* miss) {
289  Isolate* isolate = masm->isolate();
290  // Check we're still in the same context.
291  __ lw(prototype,
292        MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
293  ASSERT(!prototype.is(at));
294  __ li(at, isolate->global_object());
295  __ Branch(miss, ne, prototype, Operand(at));
296  // Get the global function with the given index.
297  Handle<JSFunction> function(
298      JSFunction::cast(isolate->native_context()->get(index)));
299  // Load its initial map. The global functions all have initial maps.
300  __ li(prototype, Handle<Map>(function->initial_map()));
301  // Load the prototype from the initial map.
302  __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
303}
304
305
306void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
307                                            Register dst,
308                                            Register src,
309                                            bool inobject,
310                                            int index,
311                                            Representation representation) {
312  ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
313  int offset = index * kPointerSize;
314  if (!inobject) {
315    // Calculate the offset into the properties array.
316    offset = offset + FixedArray::kHeaderSize;
317    __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
318    src = dst;
319  }
320  __ lw(dst, FieldMemOperand(src, offset));
321}
322
323
324void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
325                                           Register receiver,
326                                           Register scratch,
327                                           Label* miss_label) {
328  // Check that the receiver isn't a smi.
329  __ JumpIfSmi(receiver, miss_label);
330
331  // Check that the object is a JS array.
332  __ GetObjectType(receiver, scratch, scratch);
333  __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
334
335  // Load length directly from the JS array.
336  __ Ret(USE_DELAY_SLOT);
337  __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
338}
339
340
341// Generate code to check if an object is a string.  If the object is a
342// heap object, its map's instance type is left in the scratch1 register.
343// If this is not needed, scratch1 and scratch2 may be the same register.
344static void GenerateStringCheck(MacroAssembler* masm,
345                                Register receiver,
346                                Register scratch1,
347                                Register scratch2,
348                                Label* smi,
349                                Label* non_string_object) {
350  // Check that the receiver isn't a smi.
351  __ JumpIfSmi(receiver, smi, t0);
352
353  // Check that the object is a string.
354  __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
355  __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
356  __ And(scratch2, scratch1, Operand(kIsNotStringMask));
357  // The cast is to resolve the overload for the argument of 0x0.
358  __ Branch(non_string_object,
359            ne,
360            scratch2,
361            Operand(static_cast<int32_t>(kStringTag)));
362}
363
364
365// Generate code to load the length from a string object and return the length.
366// If the receiver object is not a string or a wrapped string object the
367// execution continues at the miss label. The register containing the
368// receiver is potentially clobbered.
369void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
370                                            Register receiver,
371                                            Register scratch1,
372                                            Register scratch2,
373                                            Label* miss) {
374  Label check_wrapper;
375
376  // Check if the object is a string leaving the instance type in the
377  // scratch1 register.
378  GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
379
380  // Load length directly from the string.
381  __ Ret(USE_DELAY_SLOT);
382  __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
383
384  // Check if the object is a JSValue wrapper.
385  __ bind(&check_wrapper);
386  __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
387
388  // Unwrap the value and check if the wrapped value is a string.
389  __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
390  GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
391  __ Ret(USE_DELAY_SLOT);
392  __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
393}
394
395
396void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
397                                                 Register receiver,
398                                                 Register scratch1,
399                                                 Register scratch2,
400                                                 Label* miss_label) {
401  __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
402  __ Ret(USE_DELAY_SLOT);
403  __ mov(v0, scratch1);
404}
405
406
407void StubCompiler::GenerateCheckPropertyCell(MacroAssembler* masm,
408                                             Handle<JSGlobalObject> global,
409                                             Handle<Name> name,
410                                             Register scratch,
411                                             Label* miss) {
412  Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
413  ASSERT(cell->value()->IsTheHole());
414  __ li(scratch, Operand(cell));
415  __ lw(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
416  __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
417  __ Branch(miss, ne, scratch, Operand(at));
418}
419
420
421void StoreStubCompiler::GenerateNegativeHolderLookup(
422    MacroAssembler* masm,
423    Handle<JSObject> holder,
424    Register holder_reg,
425    Handle<Name> name,
426    Label* miss) {
427  if (holder->IsJSGlobalObject()) {
428    GenerateCheckPropertyCell(
429        masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss);
430  } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
431    GenerateDictionaryNegativeLookup(
432        masm, miss, holder_reg, name, scratch1(), scratch2());
433  }
434}
435
436
437// Generate StoreTransition code, value is passed in a0 register.
438// After executing generated code, the receiver_reg and name_reg
439// may be clobbered.
440void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
441                                                Handle<JSObject> object,
442                                                LookupResult* lookup,
443                                                Handle<Map> transition,
444                                                Handle<Name> name,
445                                                Register receiver_reg,
446                                                Register storage_reg,
447                                                Register value_reg,
448                                                Register scratch1,
449                                                Register scratch2,
450                                                Register scratch3,
451                                                Label* miss_label,
452                                                Label* slow) {
453  // a0 : value.
454  Label exit;
455
456  int descriptor = transition->LastAdded();
457  DescriptorArray* descriptors = transition->instance_descriptors();
458  PropertyDetails details = descriptors->GetDetails(descriptor);
459  Representation representation = details.representation();
460  ASSERT(!representation.IsNone());
461
462  if (details.type() == CONSTANT) {
463    Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate());
464    __ li(scratch1, constant);
465    __ Branch(miss_label, ne, value_reg, Operand(scratch1));
466  } else if (FLAG_track_fields && representation.IsSmi()) {
467    __ JumpIfNotSmi(value_reg, miss_label);
468  } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
469    __ JumpIfSmi(value_reg, miss_label);
470  } else if (FLAG_track_double_fields && representation.IsDouble()) {
471    Label do_store, heap_number;
472    __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
473    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow);
474
475    __ JumpIfNotSmi(value_reg, &heap_number);
476    __ SmiUntag(scratch1, value_reg);
477    __ mtc1(scratch1, f6);
478    __ cvt_d_w(f4, f6);
479    __ jmp(&do_store);
480
481    __ bind(&heap_number);
482    __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
483                miss_label, DONT_DO_SMI_CHECK);
484    __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
485
486    __ bind(&do_store);
487    __ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
488  }
489
490  // Stub never generated for non-global objects that require access
491  // checks.
492  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
493
494  // Perform map transition for the receiver if necessary.
495  if (details.type() == FIELD &&
496      object->map()->unused_property_fields() == 0) {
497    // The properties must be extended before we can store the value.
498    // We jump to a runtime call that extends the properties array.
499    __ push(receiver_reg);
500    __ li(a2, Operand(transition));
501    __ Push(a2, a0);
502    __ TailCallExternalReference(
503           ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
504                             masm->isolate()),
505           3, 1);
506    return;
507  }
508
509  // Update the map of the object.
510  __ li(scratch1, Operand(transition));
511  __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
512
513  // Update the write barrier for the map field.
514  __ RecordWriteField(receiver_reg,
515                      HeapObject::kMapOffset,
516                      scratch1,
517                      scratch2,
518                      kRAHasNotBeenSaved,
519                      kDontSaveFPRegs,
520                      OMIT_REMEMBERED_SET,
521                      OMIT_SMI_CHECK);
522
523  if (details.type() == CONSTANT) {
524    ASSERT(value_reg.is(a0));
525    __ Ret(USE_DELAY_SLOT);
526    __ mov(v0, a0);
527    return;
528  }
529
530  int index = transition->instance_descriptors()->GetFieldIndex(
531      transition->LastAdded());
532
533  // Adjust for the number of properties stored in the object. Even in the
534  // face of a transition we can use the old map here because the size of the
535  // object and the number of in-object properties is not going to change.
536  index -= object->map()->inobject_properties();
537
538  // TODO(verwaest): Share this code as a code stub.
539  SmiCheck smi_check = representation.IsTagged()
540      ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
541  if (index < 0) {
542    // Set the property straight into the object.
543    int offset = object->map()->instance_size() + (index * kPointerSize);
544    if (FLAG_track_double_fields && representation.IsDouble()) {
545      __ sw(storage_reg, FieldMemOperand(receiver_reg, offset));
546    } else {
547      __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
548    }
549
550    if (!FLAG_track_fields || !representation.IsSmi()) {
551      // Update the write barrier for the array address.
552      if (!FLAG_track_double_fields || !representation.IsDouble()) {
553        __ mov(storage_reg, value_reg);
554      }
555      __ RecordWriteField(receiver_reg,
556                          offset,
557                          storage_reg,
558                          scratch1,
559                          kRAHasNotBeenSaved,
560                          kDontSaveFPRegs,
561                          EMIT_REMEMBERED_SET,
562                          smi_check);
563    }
564  } else {
565    // Write to the properties array.
566    int offset = index * kPointerSize + FixedArray::kHeaderSize;
567    // Get the properties array
568    __ lw(scratch1,
569          FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
570    if (FLAG_track_double_fields && representation.IsDouble()) {
571      __ sw(storage_reg, FieldMemOperand(scratch1, offset));
572    } else {
573      __ sw(value_reg, FieldMemOperand(scratch1, offset));
574    }
575
576    if (!FLAG_track_fields || !representation.IsSmi()) {
577      // Update the write barrier for the array address.
578      if (!FLAG_track_double_fields || !representation.IsDouble()) {
579        __ mov(storage_reg, value_reg);
580      }
581      __ RecordWriteField(scratch1,
582                          offset,
583                          storage_reg,
584                          receiver_reg,
585                          kRAHasNotBeenSaved,
586                          kDontSaveFPRegs,
587                          EMIT_REMEMBERED_SET,
588                          smi_check);
589    }
590  }
591
592  // Return the value (register v0).
593  ASSERT(value_reg.is(a0));
594  __ bind(&exit);
595  __ Ret(USE_DELAY_SLOT);
596  __ mov(v0, a0);
597}
598
599
600// Generate StoreField code, value is passed in a0 register.
601// When leaving generated code after success, the receiver_reg and name_reg
602// may be clobbered.  Upon branch to miss_label, the receiver and name
603// registers have their original values.
604void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
605                                           Handle<JSObject> object,
606                                           LookupResult* lookup,
607                                           Register receiver_reg,
608                                           Register name_reg,
609                                           Register value_reg,
610                                           Register scratch1,
611                                           Register scratch2,
612                                           Label* miss_label) {
613  // a0 : value
614  Label exit;
615
616  // Stub never generated for non-global objects that require access
617  // checks.
618  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
619
620  int index = lookup->GetFieldIndex().field_index();
621
622  // Adjust for the number of properties stored in the object. Even in the
623  // face of a transition we can use the old map here because the size of the
624  // object and the number of in-object properties is not going to change.
625  index -= object->map()->inobject_properties();
626
627  Representation representation = lookup->representation();
628  ASSERT(!representation.IsNone());
629  if (FLAG_track_fields && representation.IsSmi()) {
630    __ JumpIfNotSmi(value_reg, miss_label);
631  } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
632    __ JumpIfSmi(value_reg, miss_label);
633  } else if (FLAG_track_double_fields && representation.IsDouble()) {
634    // Load the double storage.
635    if (index < 0) {
636      int offset = object->map()->instance_size() + (index * kPointerSize);
637      __ lw(scratch1, FieldMemOperand(receiver_reg, offset));
638    } else {
639      __ lw(scratch1,
640            FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
641      int offset = index * kPointerSize + FixedArray::kHeaderSize;
642      __ lw(scratch1, FieldMemOperand(scratch1, offset));
643    }
644
645    // Store the value into the storage.
646    Label do_store, heap_number;
647    __ JumpIfNotSmi(value_reg, &heap_number);
648    __ SmiUntag(scratch2, value_reg);
649    __ mtc1(scratch2, f6);
650    __ cvt_d_w(f4, f6);
651    __ jmp(&do_store);
652
653    __ bind(&heap_number);
654    __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
655                miss_label, DONT_DO_SMI_CHECK);
656    __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
657
658    __ bind(&do_store);
659    __ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
660    // Return the value (register v0).
661    ASSERT(value_reg.is(a0));
662    __ Ret(USE_DELAY_SLOT);
663    __ mov(v0, a0);
664    return;
665  }
666
667  // TODO(verwaest): Share this code as a code stub.
668  SmiCheck smi_check = representation.IsTagged()
669      ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
670  if (index < 0) {
671    // Set the property straight into the object.
672    int offset = object->map()->instance_size() + (index * kPointerSize);
673    __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
674
675    if (!FLAG_track_fields || !representation.IsSmi()) {
676      // Skip updating write barrier if storing a smi.
677      __ JumpIfSmi(value_reg, &exit);
678
679      // Update the write barrier for the array address.
680      // Pass the now unused name_reg as a scratch register.
681      __ mov(name_reg, value_reg);
682      __ RecordWriteField(receiver_reg,
683                          offset,
684                          name_reg,
685                          scratch1,
686                          kRAHasNotBeenSaved,
687                          kDontSaveFPRegs,
688                          EMIT_REMEMBERED_SET,
689                          smi_check);
690    }
691  } else {
692    // Write to the properties array.
693    int offset = index * kPointerSize + FixedArray::kHeaderSize;
694    // Get the properties array.
695    __ lw(scratch1,
696          FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
697    __ sw(value_reg, FieldMemOperand(scratch1, offset));
698
699    if (!FLAG_track_fields || !representation.IsSmi()) {
700      // Skip updating write barrier if storing a smi.
701      __ JumpIfSmi(value_reg, &exit);
702
703      // Update the write barrier for the array address.
704      // Ok to clobber receiver_reg and name_reg, since we return.
705      __ mov(name_reg, value_reg);
706      __ RecordWriteField(scratch1,
707                          offset,
708                          name_reg,
709                          receiver_reg,
710                          kRAHasNotBeenSaved,
711                          kDontSaveFPRegs,
712                          EMIT_REMEMBERED_SET,
713                          smi_check);
714    }
715  }
716
717  // Return the value (register v0).
718  ASSERT(value_reg.is(a0));
719  __ bind(&exit);
720  __ Ret(USE_DELAY_SLOT);
721  __ mov(v0, a0);
722}
723
724
725void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
726                                            Label* label,
727                                            Handle<Name> name) {
728  if (!label->is_unused()) {
729    __ bind(label);
730    __ li(this->name(), Operand(name));
731  }
732}
733
734
735static void PushInterceptorArguments(MacroAssembler* masm,
736                                     Register receiver,
737                                     Register holder,
738                                     Register name,
739                                     Handle<JSObject> holder_obj) {
740  STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
741  STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
742  STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
743  STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
744  STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
745  __ push(name);
746  Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
747  ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
748  Register scratch = name;
749  __ li(scratch, Operand(interceptor));
750  __ Push(scratch, receiver, holder);
751}
752
753
754static void CompileCallLoadPropertyWithInterceptor(
755    MacroAssembler* masm,
756    Register receiver,
757    Register holder,
758    Register name,
759    Handle<JSObject> holder_obj,
760    IC::UtilityId id) {
761  PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
762  __ CallExternalReference(
763      ExternalReference(IC_Utility(id), masm->isolate()),
764      StubCache::kInterceptorArgsLength);
765}
766
767
768static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
769
770// Reserves space for the extra arguments to API function in the
771// caller's frame.
772//
773// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
774static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
775                                       Register scratch) {
776  ASSERT(Smi::FromInt(0) == 0);
777  for (int i = 0; i < kFastApiCallArguments; i++) {
778    __ push(zero_reg);
779  }
780}
781
782
783// Undoes the effects of ReserveSpaceForFastApiCall.
784static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
785  __ Drop(kFastApiCallArguments);
786}
787
788
789static void GenerateFastApiDirectCall(MacroAssembler* masm,
790                                      const CallOptimization& optimization,
791                                      int argc,
792                                      bool restore_context) {
793  // ----------- S t a t e -------------
794  //  -- sp[0] - sp[24]     : FunctionCallbackInfo, incl.
795  //                        :  holder (set by CheckPrototypes)
796  //  -- sp[28]             : last JS argument
797  //  -- ...
798  //  -- sp[(argc + 6) * 4] : first JS argument
799  //  -- sp[(argc + 7) * 4] : receiver
800  // -----------------------------------
801  typedef FunctionCallbackArguments FCA;
802  // Save calling context.
803  __ sw(cp, MemOperand(sp, FCA::kContextSaveIndex * kPointerSize));
804  // Get the function and setup the context.
805  Handle<JSFunction> function = optimization.constant_function();
806  __ li(t1, function);
807  __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
808  __ sw(t1, MemOperand(sp, FCA::kCalleeIndex * kPointerSize));
809
810  // Construct the FunctionCallbackInfo.
811  Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
812  Handle<Object> call_data(api_call_info->data(), masm->isolate());
813  if (masm->isolate()->heap()->InNewSpace(*call_data)) {
814    __ li(a0, api_call_info);
815    __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
816  } else {
817    __ li(t2, call_data);
818  }
819  // Store call data.
820  __ sw(t2, MemOperand(sp, FCA::kDataIndex * kPointerSize));
821  // Store isolate.
822  __ li(t3, Operand(ExternalReference::isolate_address(masm->isolate())));
823  __ sw(t3, MemOperand(sp, FCA::kIsolateIndex * kPointerSize));
824  // Store ReturnValue default and ReturnValue.
825  __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
826  __ sw(t1, MemOperand(sp, FCA::kReturnValueOffset * kPointerSize));
827  __ sw(t1, MemOperand(sp, FCA::kReturnValueDefaultValueIndex * kPointerSize));
828
829  // Prepare arguments.
830  __ Move(a2, sp);
831
832  // Allocate the v8::Arguments structure in the arguments' space since
833  // it's not controlled by GC.
834  const int kApiStackSpace = 4;
835
836  FrameScope frame_scope(masm, StackFrame::MANUAL);
837  __ EnterExitFrame(false, kApiStackSpace);
838
839  // a0 = FunctionCallbackInfo&
840  // Arguments is built at sp + 1 (sp is a reserved spot for ra).
841  __ Addu(a0, sp, kPointerSize);
842  // FunctionCallbackInfo::implicit_args_
843  __ sw(a2, MemOperand(a0, 0 * kPointerSize));
844  // FunctionCallbackInfo::values_
845  __ Addu(t0, a2, Operand((kFastApiCallArguments - 1 + argc) * kPointerSize));
846  __ sw(t0, MemOperand(a0, 1 * kPointerSize));
847  // FunctionCallbackInfo::length_ = argc
848  __ li(t0, Operand(argc));
849  __ sw(t0, MemOperand(a0, 2 * kPointerSize));
850  // FunctionCallbackInfo::is_construct_call = 0
851  __ sw(zero_reg, MemOperand(a0, 3 * kPointerSize));
852
853  const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
854  Address function_address = v8::ToCData<Address>(api_call_info->callback());
855  ApiFunction fun(function_address);
856  ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
857  ExternalReference ref =
858      ExternalReference(&fun,
859                        type,
860                        masm->isolate());
861  Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
862  ExternalReference::Type thunk_type = ExternalReference::PROFILING_API_CALL;
863  ApiFunction thunk_fun(thunk_address);
864  ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
865      masm->isolate());
866
867  AllowExternalCallThatCantCauseGC scope(masm);
868  MemOperand context_restore_operand(
869      fp, (2 + FCA::kContextSaveIndex) * kPointerSize);
870  MemOperand return_value_operand(
871      fp, (2 + FCA::kReturnValueOffset) * kPointerSize);
872
873  __ CallApiFunctionAndReturn(ref,
874                              function_address,
875                              thunk_ref,
876                              a1,
877                              kStackUnwindSpace,
878                              return_value_operand,
879                              restore_context ?
880                                  &context_restore_operand : NULL);
881}
882
883
884// Generate call to api function.
885static void GenerateFastApiCall(MacroAssembler* masm,
886                                const CallOptimization& optimization,
887                                Register receiver,
888                                Register scratch,
889                                int argc,
890                                Register* values) {
891  ASSERT(optimization.is_simple_api_call());
892  ASSERT(!receiver.is(scratch));
893
894  typedef FunctionCallbackArguments FCA;
895  const int stack_space = kFastApiCallArguments + argc + 1;
896  // Assign stack space for the call arguments.
897  __ Subu(sp, sp, Operand(stack_space * kPointerSize));
898  // Write holder to stack frame.
899  __ sw(receiver, MemOperand(sp, FCA::kHolderIndex * kPointerSize));
900  // Write receiver to stack frame.
901  int index = stack_space - 1;
902  __ sw(receiver, MemOperand(sp, index * kPointerSize));
903  // Write the arguments to stack frame.
904  for (int i = 0; i < argc; i++) {
905    ASSERT(!receiver.is(values[i]));
906    ASSERT(!scratch.is(values[i]));
907    __ sw(receiver, MemOperand(sp, index-- * kPointerSize));
908  }
909
910  GenerateFastApiDirectCall(masm, optimization, argc, true);
911}
912
913
914class CallInterceptorCompiler BASE_EMBEDDED {
915 public:
916  CallInterceptorCompiler(CallStubCompiler* stub_compiler,
917                          const ParameterCount& arguments,
918                          Register name,
919                          ExtraICState extra_ic_state)
920      : stub_compiler_(stub_compiler),
921        arguments_(arguments),
922        name_(name),
923        extra_ic_state_(extra_ic_state) {}
924
925  void Compile(MacroAssembler* masm,
926               Handle<JSObject> object,
927               Handle<JSObject> holder,
928               Handle<Name> name,
929               LookupResult* lookup,
930               Register receiver,
931               Register scratch1,
932               Register scratch2,
933               Register scratch3,
934               Label* miss) {
935    ASSERT(holder->HasNamedInterceptor());
936    ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
937
938    // Check that the receiver isn't a smi.
939    __ JumpIfSmi(receiver, miss);
940    CallOptimization optimization(lookup);
941    if (optimization.is_constant_call()) {
942      CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
943                       holder, lookup, name, optimization, miss);
944    } else {
945      CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
946                     name, holder, miss);
947    }
948  }
949
950 private:
951  void CompileCacheable(MacroAssembler* masm,
952                        Handle<JSObject> object,
953                        Register receiver,
954                        Register scratch1,
955                        Register scratch2,
956                        Register scratch3,
957                        Handle<JSObject> interceptor_holder,
958                        LookupResult* lookup,
959                        Handle<Name> name,
960                        const CallOptimization& optimization,
961                        Label* miss_label) {
962    ASSERT(optimization.is_constant_call());
963    ASSERT(!lookup->holder()->IsGlobalObject());
964    Counters* counters = masm->isolate()->counters();
965    int depth1 = kInvalidProtoDepth;
966    int depth2 = kInvalidProtoDepth;
967    bool can_do_fast_api_call = false;
968    if (optimization.is_simple_api_call() &&
969          !lookup->holder()->IsGlobalObject()) {
970      depth1 = optimization.GetPrototypeDepthOfExpectedType(
971          object, interceptor_holder);
972      if (depth1 == kInvalidProtoDepth) {
973        depth2 = optimization.GetPrototypeDepthOfExpectedType(
974            interceptor_holder, Handle<JSObject>(lookup->holder()));
975      }
976      can_do_fast_api_call =
977          depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
978    }
979
980    __ IncrementCounter(counters->call_const_interceptor(), 1,
981                        scratch1, scratch2);
982
983    if (can_do_fast_api_call) {
984      __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
985                          scratch1, scratch2);
986      ReserveSpaceForFastApiCall(masm, scratch1);
987    }
988
989    // Check that the maps from receiver to interceptor's holder
990    // haven't changed and thus we can invoke interceptor.
991    Label miss_cleanup;
992    Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
993    Register holder =
994        stub_compiler_->CheckPrototypes(
995            IC::CurrentTypeOf(object, masm->isolate()), receiver,
996            interceptor_holder, scratch1, scratch2, scratch3,
997            name, depth1, miss);
998
999    // Invoke an interceptor and if it provides a value,
1000    // branch to |regular_invoke|.
1001    Label regular_invoke;
1002    LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
1003                        &regular_invoke);
1004
1005    // Interceptor returned nothing for this property.  Try to use cached
1006    // constant function.
1007
1008    // Check that the maps from interceptor's holder to constant function's
1009    // holder haven't changed and thus we can use cached constant function.
1010    if (*interceptor_holder != lookup->holder()) {
1011      stub_compiler_->CheckPrototypes(
1012          IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder,
1013          handle(lookup->holder()), scratch1, scratch2, scratch3,
1014          name, depth2, miss);
1015    } else {
1016      // CheckPrototypes has a side effect of fetching a 'holder'
1017      // for API (object which is instanceof for the signature).  It's
1018      // safe to omit it here, as if present, it should be fetched
1019      // by the previous CheckPrototypes.
1020      ASSERT(depth2 == kInvalidProtoDepth);
1021    }
1022
1023    // Invoke function.
1024    if (can_do_fast_api_call) {
1025      GenerateFastApiDirectCall(
1026          masm, optimization, arguments_.immediate(), false);
1027    } else {
1028      Handle<JSFunction> function = optimization.constant_function();
1029      __ Move(a0, receiver);
1030      stub_compiler_->GenerateJumpFunction(object, function);
1031    }
1032
1033    // Deferred code for fast API call case---clean preallocated space.
1034    if (can_do_fast_api_call) {
1035      __ bind(&miss_cleanup);
1036      FreeSpaceForFastApiCall(masm);
1037      __ Branch(miss_label);
1038    }
1039
1040    // Invoke a regular function.
1041    __ bind(&regular_invoke);
1042    if (can_do_fast_api_call) {
1043      FreeSpaceForFastApiCall(masm);
1044    }
1045  }
1046
1047  void CompileRegular(MacroAssembler* masm,
1048                      Handle<JSObject> object,
1049                      Register receiver,
1050                      Register scratch1,
1051                      Register scratch2,
1052                      Register scratch3,
1053                      Handle<Name> name,
1054                      Handle<JSObject> interceptor_holder,
1055                      Label* miss_label) {
1056    Register holder =
1057        stub_compiler_->CheckPrototypes(
1058            IC::CurrentTypeOf(object, masm->isolate()), receiver,
1059            interceptor_holder, scratch1, scratch2, scratch3, name, miss_label);
1060
1061    // Call a runtime function to load the interceptor property.
1062    FrameScope scope(masm, StackFrame::INTERNAL);
1063    // Save the name_ register across the call.
1064    __ push(name_);
1065
1066    CompileCallLoadPropertyWithInterceptor(
1067        masm, receiver, holder, name_, interceptor_holder,
1068        IC::kLoadPropertyWithInterceptorForCall);
1069
1070    // Restore the name_ register.
1071    __ pop(name_);
1072    // Leave the internal frame.
1073  }
1074
1075  void LoadWithInterceptor(MacroAssembler* masm,
1076                           Register receiver,
1077                           Register holder,
1078                           Handle<JSObject> holder_obj,
1079                           Register scratch,
1080                           Label* interceptor_succeeded) {
1081    {
1082      FrameScope scope(masm, StackFrame::INTERNAL);
1083
1084      __ Push(receiver, holder, name_);
1085      CompileCallLoadPropertyWithInterceptor(
1086          masm, receiver, holder, name_, holder_obj,
1087          IC::kLoadPropertyWithInterceptorOnly);
1088      __ pop(name_);
1089      __ pop(holder);
1090      __ pop(receiver);
1091    }
1092    // If interceptor returns no-result sentinel, call the constant function.
1093    __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1094    __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
1095  }
1096
1097  CallStubCompiler* stub_compiler_;
1098  const ParameterCount& arguments_;
1099  Register name_;
1100  ExtraICState extra_ic_state_;
1101};
1102
1103
1104void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
1105  __ Jump(code, RelocInfo::CODE_TARGET);
1106}
1107
1108
1109#undef __
1110#define __ ACCESS_MASM(masm())
1111
1112
1113Register StubCompiler::CheckPrototypes(Handle<Type> type,
1114                                       Register object_reg,
1115                                       Handle<JSObject> holder,
1116                                       Register holder_reg,
1117                                       Register scratch1,
1118                                       Register scratch2,
1119                                       Handle<Name> name,
1120                                       int save_at_depth,
1121                                       Label* miss,
1122                                       PrototypeCheckType check) {
1123  Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
1124  // Make sure that the type feedback oracle harvests the receiver map.
1125  // TODO(svenpanne) Remove this hack when all ICs are reworked.
1126  __ li(scratch1, Operand(receiver_map));
1127
1128  // Make sure there's no overlap between holder and object registers.
1129  ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1130  ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1131         && !scratch2.is(scratch1));
1132
1133  // Keep track of the current object in register reg.
1134  Register reg = object_reg;
1135  int depth = 0;
1136
1137  typedef FunctionCallbackArguments FCA;
1138  if (save_at_depth == depth) {
1139    __ sw(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize));
1140  }
1141
1142  Handle<JSObject> current = Handle<JSObject>::null();
1143  if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant());
1144  Handle<JSObject> prototype = Handle<JSObject>::null();
1145  Handle<Map> current_map = receiver_map;
1146  Handle<Map> holder_map(holder->map());
1147  // Traverse the prototype chain and check the maps in the prototype chain for
1148  // fast and global objects or do negative lookup for normal objects.
1149  while (!current_map.is_identical_to(holder_map)) {
1150    ++depth;
1151
1152    // Only global objects and objects that do not require access
1153    // checks are allowed in stubs.
1154    ASSERT(current_map->IsJSGlobalProxyMap() ||
1155           !current_map->is_access_check_needed());
1156
1157    prototype = handle(JSObject::cast(current_map->prototype()));
1158    if (current_map->is_dictionary_map() &&
1159        !current_map->IsJSGlobalObjectMap() &&
1160        !current_map->IsJSGlobalProxyMap()) {
1161      if (!name->IsUniqueName()) {
1162        ASSERT(name->IsString());
1163        name = factory()->InternalizeString(Handle<String>::cast(name));
1164      }
1165      ASSERT(current.is_null() ||
1166             current->property_dictionary()->FindEntry(*name) ==
1167             NameDictionary::kNotFound);
1168
1169      GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1170                                       scratch1, scratch2);
1171
1172      __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1173      reg = holder_reg;  // From now on the object will be in holder_reg.
1174      __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1175    } else {
1176      Register map_reg = scratch1;
1177      if (depth != 1 || check == CHECK_ALL_MAPS) {
1178        // CheckMap implicitly loads the map of |reg| into |map_reg|.
1179        __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
1180      } else {
1181        __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1182      }
1183
1184      // Check access rights to the global object.  This has to happen after
1185      // the map check so that we know that the object is actually a global
1186      // object.
1187      if (current_map->IsJSGlobalProxyMap()) {
1188        __ CheckAccessGlobalProxy(reg, scratch2, miss);
1189      } else if (current_map->IsJSGlobalObjectMap()) {
1190        GenerateCheckPropertyCell(
1191            masm(), Handle<JSGlobalObject>::cast(current), name,
1192            scratch2, miss);
1193      }
1194
1195      reg = holder_reg;  // From now on the object will be in holder_reg.
1196
1197      if (heap()->InNewSpace(*prototype)) {
1198        // The prototype is in new space; we cannot store a reference to it
1199        // in the code.  Load it from the map.
1200        __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
1201      } else {
1202        // The prototype is in old space; load it directly.
1203        __ li(reg, Operand(prototype));
1204      }
1205    }
1206
1207    if (save_at_depth == depth) {
1208      __ sw(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize));
1209    }
1210
1211    // Go to the next object in the prototype chain.
1212    current = prototype;
1213    current_map = handle(current->map());
1214  }
1215
1216  // Log the check depth.
1217  LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1218
1219  if (depth != 0 || check == CHECK_ALL_MAPS) {
1220    // Check the holder map.
1221    __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK);
1222  }
1223
1224  // Perform security check for access to the global object.
1225  ASSERT(current_map->IsJSGlobalProxyMap() ||
1226         !current_map->is_access_check_needed());
1227  if (current_map->IsJSGlobalProxyMap()) {
1228    __ CheckAccessGlobalProxy(reg, scratch1, miss);
1229  }
1230
1231  // Return the register containing the holder.
1232  return reg;
1233}
1234
1235
1236void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
1237  if (!miss->is_unused()) {
1238    Label success;
1239    __ Branch(&success);
1240    __ bind(miss);
1241    TailCallBuiltin(masm(), MissBuiltin(kind()));
1242    __ bind(&success);
1243  }
1244}
1245
1246
1247void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
1248  if (!miss->is_unused()) {
1249    Label success;
1250    __ Branch(&success);
1251    GenerateRestoreName(masm(), miss, name);
1252    TailCallBuiltin(masm(), MissBuiltin(kind()));
1253    __ bind(&success);
1254  }
1255}
1256
1257
1258Register LoadStubCompiler::CallbackHandlerFrontend(
1259    Handle<Type> type,
1260    Register object_reg,
1261    Handle<JSObject> holder,
1262    Handle<Name> name,
1263    Handle<Object> callback) {
1264  Label miss;
1265
1266  Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss);
1267
1268  if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1269    ASSERT(!reg.is(scratch2()));
1270    ASSERT(!reg.is(scratch3()));
1271    ASSERT(!reg.is(scratch4()));
1272
1273    // Load the properties dictionary.
1274    Register dictionary = scratch4();
1275    __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1276
1277    // Probe the dictionary.
1278    Label probe_done;
1279    NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1280                                                     &miss,
1281                                                     &probe_done,
1282                                                     dictionary,
1283                                                     this->name(),
1284                                                     scratch2(),
1285                                                     scratch3());
1286    __ bind(&probe_done);
1287
1288    // If probing finds an entry in the dictionary, scratch3 contains the
1289    // pointer into the dictionary. Check that the value is the callback.
1290    Register pointer = scratch3();
1291    const int kElementsStartOffset = NameDictionary::kHeaderSize +
1292        NameDictionary::kElementsStartIndex * kPointerSize;
1293    const int kValueOffset = kElementsStartOffset + kPointerSize;
1294    __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1295    __ Branch(&miss, ne, scratch2(), Operand(callback));
1296  }
1297
1298  HandlerFrontendFooter(name, &miss);
1299  return reg;
1300}
1301
1302
1303void LoadStubCompiler::GenerateLoadField(Register reg,
1304                                         Handle<JSObject> holder,
1305                                         PropertyIndex field,
1306                                         Representation representation) {
1307  if (!reg.is(receiver())) __ mov(receiver(), reg);
1308  if (kind() == Code::LOAD_IC) {
1309    LoadFieldStub stub(field.is_inobject(holder),
1310                       field.translate(holder),
1311                       representation);
1312    GenerateTailCall(masm(), stub.GetCode(isolate()));
1313  } else {
1314    KeyedLoadFieldStub stub(field.is_inobject(holder),
1315                            field.translate(holder),
1316                            representation);
1317    GenerateTailCall(masm(), stub.GetCode(isolate()));
1318  }
1319}
1320
1321
1322void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
1323  // Return the constant value.
1324  __ li(v0, value);
1325  __ Ret();
1326}
1327
1328
1329void LoadStubCompiler::GenerateLoadCallback(
1330    const CallOptimization& call_optimization) {
1331  GenerateFastApiCall(
1332      masm(), call_optimization, receiver(), scratch3(), 0, NULL);
1333}
1334
1335
1336void LoadStubCompiler::GenerateLoadCallback(
1337    Register reg,
1338    Handle<ExecutableAccessorInfo> callback) {
1339  // Build AccessorInfo::args_ list on the stack and push property name below
1340  // the exit frame to make GC aware of them and store pointers to them.
1341  STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
1342  STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
1343  STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
1344  STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
1345  STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
1346  STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
1347  STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
1348  ASSERT(!scratch2().is(reg));
1349  ASSERT(!scratch3().is(reg));
1350  ASSERT(!scratch4().is(reg));
1351  __ push(receiver());
1352  if (heap()->InNewSpace(callback->data())) {
1353    __ li(scratch3(), callback);
1354    __ lw(scratch3(), FieldMemOperand(scratch3(),
1355                                      ExecutableAccessorInfo::kDataOffset));
1356  } else {
1357    __ li(scratch3(), Handle<Object>(callback->data(), isolate()));
1358  }
1359  __ Subu(sp, sp, 6 * kPointerSize);
1360  __ sw(scratch3(), MemOperand(sp, 5 * kPointerSize));
1361  __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
1362  __ sw(scratch3(), MemOperand(sp, 4 * kPointerSize));
1363  __ sw(scratch3(), MemOperand(sp, 3 * kPointerSize));
1364  __ li(scratch4(),
1365        Operand(ExternalReference::isolate_address(isolate())));
1366  __ sw(scratch4(), MemOperand(sp, 2 * kPointerSize));
1367  __ sw(reg, MemOperand(sp, 1 * kPointerSize));
1368  __ sw(name(), MemOperand(sp, 0 * kPointerSize));
1369  __ Addu(scratch2(), sp, 1 * kPointerSize);
1370
1371  __ mov(a2, scratch2());  // Saved in case scratch2 == a1.
1372  __ mov(a0, sp);  // (first argument - a0) = Handle<Name>
1373
1374  const int kApiStackSpace = 1;
1375  FrameScope frame_scope(masm(), StackFrame::MANUAL);
1376  __ EnterExitFrame(false, kApiStackSpace);
1377
1378  // Create PropertyAccessorInfo instance on the stack above the exit frame with
1379  // scratch2 (internal::Object** args_) as the data.
1380  __ sw(a2, MemOperand(sp, kPointerSize));
1381  // (second argument - a1) = AccessorInfo&
1382  __ Addu(a1, sp, kPointerSize);
1383
1384  const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
1385  Address getter_address = v8::ToCData<Address>(callback->getter());
1386  ApiFunction fun(getter_address);
1387  ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1388  ExternalReference ref = ExternalReference(&fun, type, isolate());
1389
1390  Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
1391  ExternalReference::Type thunk_type =
1392      ExternalReference::PROFILING_GETTER_CALL;
1393  ApiFunction thunk_fun(thunk_address);
1394  ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
1395      isolate());
1396  __ CallApiFunctionAndReturn(ref,
1397                              getter_address,
1398                              thunk_ref,
1399                              a2,
1400                              kStackUnwindSpace,
1401                              MemOperand(fp, 6 * kPointerSize),
1402                              NULL);
1403}
1404
1405
1406void LoadStubCompiler::GenerateLoadInterceptor(
1407    Register holder_reg,
1408    Handle<Object> object,
1409    Handle<JSObject> interceptor_holder,
1410    LookupResult* lookup,
1411    Handle<Name> name) {
1412  ASSERT(interceptor_holder->HasNamedInterceptor());
1413  ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1414
1415  // So far the most popular follow ups for interceptor loads are FIELD
1416  // and CALLBACKS, so inline only them, other cases may be added
1417  // later.
1418  bool compile_followup_inline = false;
1419  if (lookup->IsFound() && lookup->IsCacheable()) {
1420    if (lookup->IsField()) {
1421      compile_followup_inline = true;
1422    } else if (lookup->type() == CALLBACKS &&
1423        lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1424      ExecutableAccessorInfo* callback =
1425          ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
1426      compile_followup_inline = callback->getter() != NULL &&
1427          callback->IsCompatibleReceiver(*object);
1428    }
1429  }
1430
1431  if (compile_followup_inline) {
1432    // Compile the interceptor call, followed by inline code to load the
1433    // property from further up the prototype chain if the call fails.
1434    // Check that the maps haven't changed.
1435    ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
1436
1437    // Preserve the receiver register explicitly whenever it is different from
1438    // the holder and it is needed should the interceptor return without any
1439    // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1440    // the FIELD case might cause a miss during the prototype check.
1441    bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1442    bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
1443        (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1444
1445    // Save necessary data before invoking an interceptor.
1446    // Requires a frame to make GC aware of pushed pointers.
1447    {
1448      FrameScope frame_scope(masm(), StackFrame::INTERNAL);
1449      if (must_preserve_receiver_reg) {
1450        __ Push(receiver(), holder_reg, this->name());
1451      } else {
1452        __ Push(holder_reg, this->name());
1453      }
1454      // Invoke an interceptor.  Note: map checks from receiver to
1455      // interceptor's holder has been compiled before (see a caller
1456      // of this method).
1457      CompileCallLoadPropertyWithInterceptor(
1458          masm(), receiver(), holder_reg, this->name(), interceptor_holder,
1459          IC::kLoadPropertyWithInterceptorOnly);
1460
1461      // Check if interceptor provided a value for property.  If it's
1462      // the case, return immediately.
1463      Label interceptor_failed;
1464      __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1465      __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
1466      frame_scope.GenerateLeaveFrame();
1467      __ Ret();
1468
1469      __ bind(&interceptor_failed);
1470      __ pop(this->name());
1471      __ pop(holder_reg);
1472      if (must_preserve_receiver_reg) {
1473        __ pop(receiver());
1474      }
1475      // Leave the internal frame.
1476    }
1477    GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
1478  } else {  // !compile_followup_inline
1479    // Call the runtime system to load the interceptor.
1480    // Check that the maps haven't changed.
1481    PushInterceptorArguments(masm(), receiver(), holder_reg,
1482                             this->name(), interceptor_holder);
1483
1484    ExternalReference ref = ExternalReference(
1485        IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
1486    __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
1487  }
1488}
1489
1490
1491void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
1492  if (kind_ == Code::KEYED_CALL_IC) {
1493    __ Branch(miss, ne, a2, Operand(name));
1494  }
1495}
1496
1497
1498void CallStubCompiler::GenerateFunctionCheck(Register function,
1499                                             Register scratch,
1500                                             Label* miss) {
1501  __ JumpIfSmi(function, miss);
1502  __ GetObjectType(function, scratch, scratch);
1503  __ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
1504}
1505
1506
1507void CallStubCompiler::GenerateLoadFunctionFromCell(
1508    Handle<Cell> cell,
1509    Handle<JSFunction> function,
1510    Label* miss) {
1511  // Get the value from the cell.
1512  __ li(a3, Operand(cell));
1513  __ lw(a1, FieldMemOperand(a3, Cell::kValueOffset));
1514
1515  // Check that the cell contains the same function.
1516  if (heap()->InNewSpace(*function)) {
1517    // We can't embed a pointer to a function in new space so we have
1518    // to verify that the shared function info is unchanged. This has
1519    // the nice side effect that multiple closures based on the same
1520    // function can all use this call IC. Before we load through the
1521    // function, we have to verify that it still is a function.
1522    GenerateFunctionCheck(a1, a3, miss);
1523
1524    // Check the shared function info. Make sure it hasn't changed.
1525    __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1526    __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1527    __ Branch(miss, ne, t0, Operand(a3));
1528  } else {
1529    __ Branch(miss, ne, a1, Operand(function));
1530  }
1531}
1532
1533
1534void CallStubCompiler::GenerateMissBranch() {
1535  Handle<Code> code =
1536      isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1537                                               kind_,
1538                                               extra_state());
1539  __ Jump(code, RelocInfo::CODE_TARGET);
1540}
1541
1542
1543Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1544                                                Handle<JSObject> holder,
1545                                                PropertyIndex index,
1546                                                Handle<Name> name) {
1547  Label miss;
1548
1549  Register reg = HandlerFrontendHeader(
1550      object, holder, name, RECEIVER_MAP_CHECK, &miss);
1551  GenerateFastPropertyLoad(masm(), a1, reg, index.is_inobject(holder),
1552                           index.translate(holder), Representation::Tagged());
1553  GenerateJumpFunction(object, a1, &miss);
1554
1555  HandlerFrontendFooter(&miss);
1556
1557  // Return the generated code.
1558  return GetCode(Code::FAST, name);
1559}
1560
1561
1562Handle<Code> CallStubCompiler::CompileArrayCodeCall(
1563    Handle<Object> object,
1564    Handle<JSObject> holder,
1565    Handle<Cell> cell,
1566    Handle<JSFunction> function,
1567    Handle<String> name,
1568    Code::StubType type) {
1569  Label miss;
1570
1571  HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
1572  if (!cell.is_null()) {
1573    ASSERT(cell->value() == *function);
1574    GenerateLoadFunctionFromCell(cell, function, &miss);
1575  }
1576
1577  Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
1578  site->SetElementsKind(GetInitialFastElementsKind());
1579  Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
1580  const int argc = arguments().immediate();
1581  __ li(a0, Operand(argc));
1582  __ li(a2, Operand(site_feedback_cell));
1583  __ li(a1, Operand(function));
1584
1585  ArrayConstructorStub stub(isolate());
1586  __ TailCallStub(&stub);
1587
1588  HandlerFrontendFooter(&miss);
1589
1590  // Return the generated code.
1591  return GetCode(type, name);
1592}
1593
1594
1595Handle<Code> CallStubCompiler::CompileArrayPushCall(
1596    Handle<Object> object,
1597    Handle<JSObject> holder,
1598    Handle<Cell> cell,
1599    Handle<JSFunction> function,
1600    Handle<String> name,
1601    Code::StubType type) {
1602  // If object is not an array or is observed or sealed, bail out to regular
1603  // call.
1604  if (!object->IsJSArray() ||
1605      !cell.is_null() ||
1606      Handle<JSArray>::cast(object)->map()->is_observed() ||
1607      !Handle<JSArray>::cast(object)->map()->is_extensible()) {
1608    return Handle<Code>::null();
1609  }
1610
1611  Label miss;
1612  HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
1613  Register receiver = a0;
1614  Register scratch = a1;
1615
1616  const int argc = arguments().immediate();
1617
1618  if (argc == 0) {
1619    // Nothing to do, just return the length.
1620    __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1621    __ DropAndRet(argc + 1);
1622  } else {
1623    Label call_builtin;
1624    if (argc == 1) {  // Otherwise fall through to call the builtin.
1625      Label attempt_to_grow_elements, with_write_barrier, check_double;
1626
1627      Register elements = t2;
1628      Register end_elements = t1;
1629      // Get the elements array of the object.
1630      __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1631
1632      // Check that the elements are in fast mode and writable.
1633      __ CheckMap(elements,
1634                  scratch,
1635                  Heap::kFixedArrayMapRootIndex,
1636                  &check_double,
1637                  DONT_DO_SMI_CHECK);
1638
1639      // Get the array's length into scratch and calculate new length.
1640      __ lw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
1641      STATIC_ASSERT(kSmiTagSize == 1);
1642      STATIC_ASSERT(kSmiTag == 0);
1643      __ Addu(scratch, scratch, Operand(Smi::FromInt(argc)));
1644
1645      // Get the elements' length.
1646      __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1647
1648      // Check if we could survive without allocation.
1649      __ Branch(&attempt_to_grow_elements, gt, scratch, Operand(t0));
1650
1651      // Check if value is a smi.
1652      __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1653      __ JumpIfNotSmi(t0, &with_write_barrier);
1654
1655      // Save new length.
1656      __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
1657
1658      // Store the value.
1659      // We may need a register containing the address end_elements below,
1660      // so write back the value in end_elements.
1661      __ sll(end_elements, scratch, kPointerSizeLog2 - kSmiTagSize);
1662      __ Addu(end_elements, elements, end_elements);
1663      const int kEndElementsOffset =
1664          FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
1665      __ Addu(end_elements, end_elements, kEndElementsOffset);
1666      __ sw(t0, MemOperand(end_elements));
1667
1668      // Check for a smi.
1669      __ mov(v0, scratch);
1670      __ DropAndRet(argc + 1);
1671
1672      __ bind(&check_double);
1673
1674      // Check that the elements are in fast mode and writable.
1675      __ CheckMap(elements,
1676                  scratch,
1677                  Heap::kFixedDoubleArrayMapRootIndex,
1678                  &call_builtin,
1679                  DONT_DO_SMI_CHECK);
1680
1681      // Get the array's length into scratch and calculate new length.
1682      __ lw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
1683      STATIC_ASSERT(kSmiTagSize == 1);
1684      STATIC_ASSERT(kSmiTag == 0);
1685      __ Addu(scratch, scratch, Operand(Smi::FromInt(argc)));
1686
1687      // Get the elements' length.
1688      __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1689
1690      // Check if we could survive without allocation.
1691      __ Branch(&call_builtin, gt, scratch, Operand(t0));
1692
1693      __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1694      __ StoreNumberToDoubleElements(
1695          t0, scratch, elements, a3, t1, a2,
1696          &call_builtin, argc * kDoubleSize);
1697
1698      // Save new length.
1699      __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
1700
1701      __ mov(v0, scratch);
1702      __ DropAndRet(argc + 1);
1703
1704      __ bind(&with_write_barrier);
1705
1706      __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1707
1708      if (FLAG_smi_only_arrays  && !FLAG_trace_elements_transitions) {
1709        Label fast_object, not_fast_object;
1710        __ CheckFastObjectElements(a3, t3, &not_fast_object);
1711        __ jmp(&fast_object);
1712        // In case of fast smi-only, convert to fast object, otherwise bail out.
1713        __ bind(&not_fast_object);
1714        __ CheckFastSmiElements(a3, t3, &call_builtin);
1715
1716        __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1717        __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1718        __ Branch(&call_builtin, eq, t3, Operand(at));
1719        // edx: receiver
1720        // a3: map
1721        Label try_holey_map;
1722        __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
1723                                               FAST_ELEMENTS,
1724                                               a3,
1725                                               t3,
1726                                               &try_holey_map);
1727        __ mov(a2, receiver);
1728        ElementsTransitionGenerator::
1729            GenerateMapChangeElementsTransition(masm(),
1730                                                DONT_TRACK_ALLOCATION_SITE,
1731                                                NULL);
1732        __ jmp(&fast_object);
1733
1734        __ bind(&try_holey_map);
1735        __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1736                                               FAST_HOLEY_ELEMENTS,
1737                                               a3,
1738                                               t3,
1739                                               &call_builtin);
1740        __ mov(a2, receiver);
1741        ElementsTransitionGenerator::
1742            GenerateMapChangeElementsTransition(masm(),
1743                                                DONT_TRACK_ALLOCATION_SITE,
1744                                                NULL);
1745        __ bind(&fast_object);
1746      } else {
1747        __ CheckFastObjectElements(a3, a3, &call_builtin);
1748      }
1749
1750      // Save new length.
1751      __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
1752
1753      // Store the value.
1754      // We may need a register containing the address end_elements below,
1755      // so write back the value in end_elements.
1756      __ sll(end_elements, scratch, kPointerSizeLog2 - kSmiTagSize);
1757      __ Addu(end_elements, elements, end_elements);
1758      __ Addu(end_elements, end_elements, kEndElementsOffset);
1759      __ sw(t0, MemOperand(end_elements));
1760
1761      __ RecordWrite(elements,
1762                     end_elements,
1763                     t0,
1764                     kRAHasNotBeenSaved,
1765                     kDontSaveFPRegs,
1766                     EMIT_REMEMBERED_SET,
1767                     OMIT_SMI_CHECK);
1768      __ mov(v0, scratch);
1769      __ DropAndRet(argc + 1);
1770
1771      __ bind(&attempt_to_grow_elements);
1772      // scratch: array's length + 1.
1773      // t0: elements' length.
1774
1775      if (!FLAG_inline_new) {
1776        __ Branch(&call_builtin);
1777      }
1778
1779      __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1780      // Growing elements that are SMI-only requires special handling in case
1781      // the new element is non-Smi. For now, delegate to the builtin.
1782      Label no_fast_elements_check;
1783      __ JumpIfSmi(a2, &no_fast_elements_check);
1784      __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1785      __ CheckFastObjectElements(t3, t3, &call_builtin);
1786      __ bind(&no_fast_elements_check);
1787
1788      ExternalReference new_space_allocation_top =
1789          ExternalReference::new_space_allocation_top_address(isolate());
1790      ExternalReference new_space_allocation_limit =
1791          ExternalReference::new_space_allocation_limit_address(isolate());
1792
1793      const int kAllocationDelta = 4;
1794      // Load top and check if it is the end of elements.
1795      __ sll(end_elements, scratch, kPointerSizeLog2 - kSmiTagSize);
1796      __ Addu(end_elements, elements, end_elements);
1797      __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1798      __ li(t3, Operand(new_space_allocation_top));
1799      __ lw(a3, MemOperand(t3));
1800      __ Branch(&call_builtin, ne, end_elements, Operand(a3));
1801
1802      __ li(t5, Operand(new_space_allocation_limit));
1803      __ lw(t5, MemOperand(t5));
1804      __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1805      __ Branch(&call_builtin, hi, a3, Operand(t5));
1806
1807      // We fit and could grow elements.
1808      // Update new_space_allocation_top.
1809      __ sw(a3, MemOperand(t3));
1810      // Push the argument.
1811      __ sw(a2, MemOperand(end_elements));
1812      // Fill the rest with holes.
1813      __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
1814      for (int i = 1; i < kAllocationDelta; i++) {
1815        __ sw(a3, MemOperand(end_elements, i * kPointerSize));
1816      }
1817
1818      // Update elements' and array's sizes.
1819      __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
1820      __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1821      __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1822
1823      // Elements are in new space, so write barrier is not required.
1824      __ mov(v0, scratch);
1825      __ DropAndRet(argc + 1);
1826    }
1827    __ bind(&call_builtin);
1828    __ TailCallExternalReference(
1829        ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1);
1830  }
1831
1832  HandlerFrontendFooter(&miss);
1833
1834  // Return the generated code.
1835  return GetCode(type, name);
1836}
1837
1838
1839Handle<Code> CallStubCompiler::CompileArrayPopCall(
1840    Handle<Object> object,
1841    Handle<JSObject> holder,
1842    Handle<Cell> cell,
1843    Handle<JSFunction> function,
1844    Handle<String> name,
1845    Code::StubType type) {
1846  // If object is not an array or is observed or sealed, bail out to regular
1847  // call.
1848  if (!object->IsJSArray() ||
1849      !cell.is_null() ||
1850      Handle<JSArray>::cast(object)->map()->is_observed() ||
1851      !Handle<JSArray>::cast(object)->map()->is_extensible()) {
1852    return Handle<Code>::null();
1853  }
1854
1855  Label miss, return_undefined, call_builtin;
1856  Register receiver = a0;
1857  Register scratch = a1;
1858  Register elements = a3;
1859  HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
1860
1861  // Get the elements array of the object.
1862  __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1863
1864  // Check that the elements are in fast mode and writable.
1865  __ CheckMap(elements,
1866              scratch,
1867              Heap::kFixedArrayMapRootIndex,
1868              &call_builtin,
1869              DONT_DO_SMI_CHECK);
1870
1871  // Get the array's length into t0 and calculate new length.
1872  __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1873  __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1874  __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1875
1876  // Get the last element.
1877  __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1878  STATIC_ASSERT(kSmiTagSize == 1);
1879  STATIC_ASSERT(kSmiTag == 0);
1880  // We can't address the last element in one operation. Compute the more
1881  // expensive shift first, and use an offset later on.
1882  __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1883  __ Addu(elements, elements, t1);
1884  __ lw(scratch, FieldMemOperand(elements, FixedArray::kHeaderSize));
1885  __ Branch(&call_builtin, eq, scratch, Operand(t2));
1886
1887  // Set the array's length.
1888  __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1889
1890  // Fill with the hole.
1891  __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
1892  const int argc = arguments().immediate();
1893  __ mov(v0, scratch);
1894  __ DropAndRet(argc + 1);
1895
1896  __ bind(&return_undefined);
1897  __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1898  __ DropAndRet(argc + 1);
1899
1900  __ bind(&call_builtin);
1901  __ TailCallExternalReference(
1902      ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1);
1903
1904  HandlerFrontendFooter(&miss);
1905
1906  // Return the generated code.
1907  return GetCode(type, name);
1908}
1909
1910
1911Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1912    Handle<Object> object,
1913    Handle<JSObject> holder,
1914    Handle<Cell> cell,
1915    Handle<JSFunction> function,
1916    Handle<String> name,
1917    Code::StubType type) {
1918  // If object is not a string, bail out to regular call.
1919  if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
1920
1921  Label miss;
1922  Label name_miss;
1923  Label index_out_of_range;
1924
1925  Label* index_out_of_range_label = &index_out_of_range;
1926
1927  if (kind_ == Code::CALL_IC &&
1928      (CallICBase::StringStubState::decode(extra_state()) ==
1929       DEFAULT_STRING_STUB)) {
1930    index_out_of_range_label = &miss;
1931  }
1932
1933  HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss);
1934
1935  Register receiver = a0;
1936  Register index = t1;
1937  Register result = a1;
1938  const int argc = arguments().immediate();
1939  __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1940  if (argc > 0) {
1941    __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1942  } else {
1943    __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1944  }
1945
1946  StringCharCodeAtGenerator generator(receiver,
1947                                      index,
1948                                      result,
1949                                      &miss,  // When not a string.
1950                                      &miss,  // When not a number.
1951                                      index_out_of_range_label,
1952                                      STRING_INDEX_IS_NUMBER);
1953  generator.GenerateFast(masm());
1954  __ mov(v0, result);
1955  __ DropAndRet(argc + 1);
1956
1957  StubRuntimeCallHelper call_helper;
1958  generator.GenerateSlow(masm(), call_helper);
1959
1960  if (index_out_of_range.is_linked()) {
1961    __ bind(&index_out_of_range);
1962    __ LoadRoot(v0, Heap::kNanValueRootIndex);
1963    __ DropAndRet(argc + 1);
1964  }
1965
1966  __ bind(&miss);
1967  // Restore function name in a2.
1968  __ li(a2, name);
1969  HandlerFrontendFooter(&name_miss);
1970
1971  // Return the generated code.
1972  return GetCode(type, name);
1973}
1974
1975
1976Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1977    Handle<Object> object,
1978    Handle<JSObject> holder,
1979    Handle<Cell> cell,
1980    Handle<JSFunction> function,
1981    Handle<String> name,
1982    Code::StubType type) {
1983  // If object is not a string, bail out to regular call.
1984  if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
1985
1986  const int argc = arguments().immediate();
1987  Label miss;
1988  Label name_miss;
1989  Label index_out_of_range;
1990  Label* index_out_of_range_label = &index_out_of_range;
1991  if (kind_ == Code::CALL_IC &&
1992      (CallICBase::StringStubState::decode(extra_state()) ==
1993       DEFAULT_STRING_STUB)) {
1994    index_out_of_range_label = &miss;
1995  }
1996
1997  HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss);
1998
1999  Register receiver = a0;
2000  Register index = t1;
2001  Register scratch = a3;
2002  Register result = a1;
2003  if (argc > 0) {
2004    __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2005  } else {
2006    __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2007  }
2008
2009  StringCharAtGenerator generator(receiver,
2010                                  index,
2011                                  scratch,
2012                                  result,
2013                                  &miss,  // When not a string.
2014                                  &miss,  // When not a number.
2015                                  index_out_of_range_label,
2016                                  STRING_INDEX_IS_NUMBER);
2017  generator.GenerateFast(masm());
2018  __ mov(v0, result);
2019  __ DropAndRet(argc + 1);
2020
2021  StubRuntimeCallHelper call_helper;
2022  generator.GenerateSlow(masm(), call_helper);
2023
2024  if (index_out_of_range.is_linked()) {
2025    __ bind(&index_out_of_range);
2026    __ LoadRoot(v0, Heap::kempty_stringRootIndex);
2027    __ DropAndRet(argc + 1);
2028  }
2029
2030  __ bind(&miss);
2031  // Restore function name in a2.
2032  __ li(a2, name);
2033  HandlerFrontendFooter(&name_miss);
2034
2035  // Return the generated code.
2036  return GetCode(type, name);
2037}
2038
2039
2040Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2041    Handle<Object> object,
2042    Handle<JSObject> holder,
2043    Handle<Cell> cell,
2044    Handle<JSFunction> function,
2045    Handle<String> name,
2046    Code::StubType type) {
2047  const int argc = arguments().immediate();
2048
2049  // If the object is not a JSObject or we got an unexpected number of
2050  // arguments, bail out to the regular call.
2051  if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
2052
2053  Label miss;
2054  HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2055  if (!cell.is_null()) {
2056    ASSERT(cell->value() == *function);
2057    GenerateLoadFunctionFromCell(cell, function, &miss);
2058  }
2059
2060  // Load the char code argument.
2061  Register code = a1;
2062  __ lw(code, MemOperand(sp, 0 * kPointerSize));
2063
2064  // Check the code is a smi.
2065  Label slow;
2066  STATIC_ASSERT(kSmiTag == 0);
2067  __ JumpIfNotSmi(code, &slow);
2068
2069  // Convert the smi code to uint16.
2070  __ And(code, code, Operand(Smi::FromInt(0xffff)));
2071
2072  StringCharFromCodeGenerator generator(code, v0);
2073  generator.GenerateFast(masm());
2074  __ DropAndRet(argc + 1);
2075
2076  StubRuntimeCallHelper call_helper;
2077  generator.GenerateSlow(masm(), call_helper);
2078
2079  __ bind(&slow);
2080  // We do not have to patch the receiver because the function makes no use of
2081  // it.
2082  GenerateJumpFunctionIgnoreReceiver(function);
2083
2084  HandlerFrontendFooter(&miss);
2085
2086  // Return the generated code.
2087  return GetCode(type, name);
2088}
2089
2090
2091Handle<Code> CallStubCompiler::CompileMathFloorCall(
2092    Handle<Object> object,
2093    Handle<JSObject> holder,
2094    Handle<Cell> cell,
2095    Handle<JSFunction> function,
2096    Handle<String> name,
2097    Code::StubType type) {
2098  const int argc = arguments().immediate();
2099  // If the object is not a JSObject or we got an unexpected number of
2100  // arguments, bail out to the regular call.
2101  if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
2102
2103  Label miss, slow;
2104  HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2105  if (!cell.is_null()) {
2106    ASSERT(cell->value() == *function);
2107    GenerateLoadFunctionFromCell(cell, function, &miss);
2108  }
2109
2110  // Load the (only) argument into v0.
2111  __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2112
2113  // If the argument is a smi, just return.
2114  STATIC_ASSERT(kSmiTag == 0);
2115  __ SmiTst(v0, t0);
2116  __ DropAndRet(argc + 1, eq, t0, Operand(zero_reg));
2117
2118  __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
2119
2120  Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2121
2122  // If fpu is enabled, we use the floor instruction.
2123
2124  // Load the HeapNumber value.
2125  __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2126
2127  // Backup FCSR.
2128  __ cfc1(a3, FCSR);
2129  // Clearing FCSR clears the exception mask with no side-effects.
2130  __ ctc1(zero_reg, FCSR);
2131  // Convert the argument to an integer.
2132  __ floor_w_d(f0, f0);
2133
2134  // Start checking for special cases.
2135  // Get the argument exponent and clear the sign bit.
2136  __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2137  __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2138  __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2139
2140  // Retrieve FCSR and check for fpu errors.
2141  __ cfc1(t5, FCSR);
2142  __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
2143  __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2144
2145  // Check for NaN, Infinity, and -Infinity.
2146  // They are invariant through a Math.Floor call, so just
2147  // return the original argument.
2148  __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2149        >> HeapNumber::kMantissaBitsInTopWord));
2150  __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2151  // We had an overflow or underflow in the conversion. Check if we
2152  // have a big exponent.
2153  // If greater or equal, the argument is already round and in v0.
2154  __ Branch(&restore_fcsr_and_return, ge, t3,
2155      Operand(HeapNumber::kMantissaBits));
2156  __ Branch(&wont_fit_smi);
2157
2158  __ bind(&no_fpu_error);
2159  // Move the result back to v0.
2160  __ mfc1(v0, f0);
2161  // Check if the result fits into a smi.
2162  __ Addu(a1, v0, Operand(0x40000000));
2163  __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2164  // Tag the result.
2165  STATIC_ASSERT(kSmiTag == 0);
2166  __ sll(v0, v0, kSmiTagSize);
2167
2168  // Check for -0.
2169  __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2170  // t1 already holds the HeapNumber exponent.
2171  __ And(t0, t1, Operand(HeapNumber::kSignMask));
2172  // If our HeapNumber is negative it was -0, so load its address and return.
2173  // Else v0 is loaded with 0, so we can also just return.
2174  __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2175  __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2176
2177  __ bind(&restore_fcsr_and_return);
2178  // Restore FCSR and return.
2179  __ ctc1(a3, FCSR);
2180
2181  __ DropAndRet(argc + 1);
2182
2183  __ bind(&wont_fit_smi);
2184  // Restore FCSR and fall to slow case.
2185  __ ctc1(a3, FCSR);
2186
2187  __ bind(&slow);
2188  // We do not have to patch the receiver because the function makes no use of
2189  // it.
2190  GenerateJumpFunctionIgnoreReceiver(function);
2191
2192  HandlerFrontendFooter(&miss);
2193
2194  // Return the generated code.
2195  return GetCode(type, name);
2196}
2197
2198
2199Handle<Code> CallStubCompiler::CompileMathAbsCall(
2200    Handle<Object> object,
2201    Handle<JSObject> holder,
2202    Handle<Cell> cell,
2203    Handle<JSFunction> function,
2204    Handle<String> name,
2205    Code::StubType type) {
2206  const int argc = arguments().immediate();
2207  // If the object is not a JSObject or we got an unexpected number of
2208  // arguments, bail out to the regular call.
2209  if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
2210
2211  Label miss;
2212
2213  HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2214  if (!cell.is_null()) {
2215    ASSERT(cell->value() == *function);
2216    GenerateLoadFunctionFromCell(cell, function, &miss);
2217  }
2218
2219  // Load the (only) argument into v0.
2220  __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2221
2222  // Check if the argument is a smi.
2223  Label not_smi;
2224  STATIC_ASSERT(kSmiTag == 0);
2225  __ JumpIfNotSmi(v0, &not_smi);
2226
2227  // Do bitwise not or do nothing depending on the sign of the
2228  // argument.
2229  __ sra(t0, v0, kBitsPerInt - 1);
2230  __ Xor(a1, v0, t0);
2231
2232  // Add 1 or do nothing depending on the sign of the argument.
2233  __ Subu(v0, a1, t0);
2234
2235  // If the result is still negative, go to the slow case.
2236  // This only happens for the most negative smi.
2237  Label slow;
2238  __ Branch(&slow, lt, v0, Operand(zero_reg));
2239
2240  // Smi case done.
2241  __ DropAndRet(argc + 1);
2242
2243  // Check if the argument is a heap number and load its exponent and
2244  // sign.
2245  __ bind(&not_smi);
2246  __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
2247  __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2248
2249  // Check the sign of the argument. If the argument is positive,
2250  // just return it.
2251  Label negative_sign;
2252  __ And(t0, a1, Operand(HeapNumber::kSignMask));
2253  __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2254  __ DropAndRet(argc + 1);
2255
2256  // If the argument is negative, clear the sign, and return a new
2257  // number.
2258  __ bind(&negative_sign);
2259  __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2260  __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2261  __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2262  __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2263  __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2264  __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2265  __ DropAndRet(argc + 1);
2266
2267  __ bind(&slow);
2268  // We do not have to patch the receiver because the function makes no use of
2269  // it.
2270  GenerateJumpFunctionIgnoreReceiver(function);
2271
2272  HandlerFrontendFooter(&miss);
2273
2274  // Return the generated code.
2275  return GetCode(type, name);
2276}
2277
2278
2279Handle<Code> CallStubCompiler::CompileFastApiCall(
2280    const CallOptimization& optimization,
2281    Handle<Object> object,
2282    Handle<JSObject> holder,
2283    Handle<Cell> cell,
2284    Handle<JSFunction> function,
2285    Handle<String> name) {
2286
2287  Counters* counters = isolate()->counters();
2288
2289  ASSERT(optimization.is_simple_api_call());
2290  // Bail out if object is a global object as we don't want to
2291  // repatch it to global receiver.
2292  if (object->IsGlobalObject()) return Handle<Code>::null();
2293  if (!cell.is_null()) return Handle<Code>::null();
2294  if (!object->IsJSObject()) return Handle<Code>::null();
2295  int depth = optimization.GetPrototypeDepthOfExpectedType(
2296      Handle<JSObject>::cast(object), holder);
2297  if (depth == kInvalidProtoDepth) return Handle<Code>::null();
2298
2299  Label miss, miss_before_stack_reserved;
2300
2301  GenerateNameCheck(name, &miss_before_stack_reserved);
2302
2303  // Get the receiver from the stack.
2304  const int argc = arguments().immediate();
2305  __ lw(a1, MemOperand(sp, argc * kPointerSize));
2306
2307  // Check that the receiver isn't a smi.
2308  __ JumpIfSmi(a1, &miss_before_stack_reserved);
2309
2310  __ IncrementCounter(counters->call_const(), 1, a0, a3);
2311  __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2312
2313  ReserveSpaceForFastApiCall(masm(), a0);
2314
2315  // Check that the maps haven't changed and find a Holder as a side effect.
2316  CheckPrototypes(
2317      IC::CurrentTypeOf(object, isolate()),
2318      a1, holder, a0, a3, t0, name, depth, &miss);
2319
2320  GenerateFastApiDirectCall(masm(), optimization, argc, false);
2321
2322  __ bind(&miss);
2323  FreeSpaceForFastApiCall(masm());
2324
2325  HandlerFrontendFooter(&miss_before_stack_reserved);
2326
2327  // Return the generated code.
2328  return GetCode(function);
2329}
2330
2331
2332void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
2333  Label success;
2334  // Check that the object is a boolean.
2335  __ LoadRoot(at, Heap::kTrueValueRootIndex);
2336  __ Branch(&success, eq, object, Operand(at));
2337  __ LoadRoot(at, Heap::kFalseValueRootIndex);
2338  __ Branch(miss, ne, object, Operand(at));
2339  __ bind(&success);
2340}
2341
2342
2343void CallStubCompiler::PatchGlobalProxy(Handle<Object> object) {
2344  if (object->IsGlobalObject()) {
2345    const int argc = arguments().immediate();
2346    const int receiver_offset = argc * kPointerSize;
2347    __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2348    __ sw(a3, MemOperand(sp, receiver_offset));
2349  }
2350}
2351
2352
2353Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object,
2354                                                 Handle<JSObject> holder,
2355                                                 Handle<Name> name,
2356                                                 CheckType check,
2357                                                 Label* miss) {
2358  // ----------- S t a t e -------------
2359  //  -- a2    : name
2360  //  -- ra    : return address
2361  // -----------------------------------
2362  GenerateNameCheck(name, miss);
2363
2364  Register reg = a0;
2365
2366  // Get the receiver from the stack.
2367  const int argc = arguments().immediate();
2368  const int receiver_offset = argc * kPointerSize;
2369  __ lw(a0, MemOperand(sp, receiver_offset));
2370
2371  // Check that the receiver isn't a smi.
2372  if (check != NUMBER_CHECK) {
2373    __ JumpIfSmi(a0, miss);
2374  }
2375
2376  // Make sure that it's okay not to patch the on stack receiver
2377  // unless we're doing a receiver map check.
2378  ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2379  switch (check) {
2380    case RECEIVER_MAP_CHECK:
2381      __ IncrementCounter(isolate()->counters()->call_const(), 1, a1, a3);
2382
2383      // Check that the maps haven't changed.
2384      reg = CheckPrototypes(
2385          IC::CurrentTypeOf(object, isolate()),
2386          reg, holder, a1, a3, t0, name, miss);
2387      break;
2388
2389    case STRING_CHECK: {
2390      // Check that the object is a string.
2391      __ GetObjectType(reg, a3, a3);
2392      __ Branch(miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2393      // Check that the maps starting from the prototype haven't changed.
2394      GenerateDirectLoadGlobalFunctionPrototype(
2395          masm(), Context::STRING_FUNCTION_INDEX, a1, miss);
2396      break;
2397    }
2398    case SYMBOL_CHECK: {
2399      // Check that the object is a symbol.
2400      __ GetObjectType(reg, a1, a3);
2401      __ Branch(miss, ne, a3, Operand(SYMBOL_TYPE));
2402      // Check that the maps starting from the prototype haven't changed.
2403      GenerateDirectLoadGlobalFunctionPrototype(
2404          masm(), Context::SYMBOL_FUNCTION_INDEX, a1, miss);
2405      break;
2406    }
2407    case NUMBER_CHECK: {
2408      Label fast;
2409      // Check that the object is a smi or a heap number.
2410      __ JumpIfSmi(reg, &fast);
2411      __ GetObjectType(reg, a3, a3);
2412      __ Branch(miss, ne, a3, Operand(HEAP_NUMBER_TYPE));
2413      __ bind(&fast);
2414      // Check that the maps starting from the prototype haven't changed.
2415      GenerateDirectLoadGlobalFunctionPrototype(
2416          masm(), Context::NUMBER_FUNCTION_INDEX, a1, miss);
2417      break;
2418    }
2419    case BOOLEAN_CHECK: {
2420      GenerateBooleanCheck(reg, miss);
2421
2422      // Check that the maps starting from the prototype haven't changed.
2423      GenerateDirectLoadGlobalFunctionPrototype(
2424          masm(), Context::BOOLEAN_FUNCTION_INDEX, a1, miss);
2425      break;
2426    }
2427  }
2428
2429  if (check != RECEIVER_MAP_CHECK) {
2430    Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
2431    reg = CheckPrototypes(
2432        IC::CurrentTypeOf(prototype, isolate()),
2433        a1, holder, a1, a3, t0, name, miss);
2434  }
2435
2436  return reg;
2437}
2438
2439
2440void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
2441                                            Register function,
2442                                            Label* miss) {
2443  ASSERT(function.is(a1));
2444  // Check that the function really is a function.
2445  GenerateFunctionCheck(function, a3, miss);
2446  PatchGlobalProxy(object);
2447  // Invoke the function.
2448  __ InvokeFunction(a1, arguments(), JUMP_FUNCTION,
2449                    NullCallWrapper(), call_kind());
2450}
2451
2452
2453Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2454                                                      Handle<JSObject> holder,
2455                                                      Handle<Name> name) {
2456  Label miss;
2457
2458  GenerateNameCheck(name, &miss);
2459
2460  // Get the number of arguments.
2461  const int argc = arguments().immediate();
2462  LookupResult lookup(isolate());
2463  LookupPostInterceptor(holder, name, &lookup);
2464
2465  // Get the receiver from the stack.
2466  __ lw(a1, MemOperand(sp, argc * kPointerSize));
2467
2468  CallInterceptorCompiler compiler(this, arguments(), a2, extra_state());
2469  compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2470                   &miss);
2471
2472  // Move returned value, the function to call, to a1.
2473  __ mov(a1, v0);
2474  // Restore receiver.
2475  __ lw(a0, MemOperand(sp, argc * kPointerSize));
2476
2477  GenerateJumpFunction(object, a1, &miss);
2478
2479  HandlerFrontendFooter(&miss);
2480
2481  // Return the generated code.
2482  return GetCode(Code::FAST, name);
2483}
2484
2485
2486Handle<Code> CallStubCompiler::CompileCallGlobal(
2487    Handle<JSObject> object,
2488    Handle<GlobalObject> holder,
2489    Handle<PropertyCell> cell,
2490    Handle<JSFunction> function,
2491    Handle<Name> name) {
2492  if (HasCustomCallGenerator(function)) {
2493    Handle<Code> code = CompileCustomCall(
2494        object, holder, cell, function, Handle<String>::cast(name),
2495        Code::NORMAL);
2496    // A null handle means bail out to the regular compiler code below.
2497    if (!code.is_null()) return code;
2498  }
2499
2500  Label miss;
2501  HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2502  // Potentially loads a closure that matches the shared function info of the
2503  // function, rather than function.
2504  GenerateLoadFunctionFromCell(cell, function, &miss);
2505  Counters* counters = isolate()->counters();
2506  __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
2507  GenerateJumpFunction(object, a1, function);
2508  HandlerFrontendFooter(&miss);
2509
2510  // Return the generated code.
2511  return GetCode(Code::NORMAL, name);
2512}
2513
2514
2515Handle<Code> StoreStubCompiler::CompileStoreCallback(
2516    Handle<JSObject> object,
2517    Handle<JSObject> holder,
2518    Handle<Name> name,
2519    Handle<ExecutableAccessorInfo> callback) {
2520  HandlerFrontend(IC::CurrentTypeOf(object, isolate()),
2521                  receiver(), holder, name);
2522
2523  // Stub never generated for non-global objects that require access
2524  // checks.
2525  ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
2526
2527  __ push(receiver());  // Receiver.
2528  __ li(at, Operand(callback));  // Callback info.
2529  __ push(at);
2530  __ li(at, Operand(name));
2531  __ Push(at, value());
2532
2533  // Do tail-call to the runtime system.
2534  ExternalReference store_callback_property =
2535      ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
2536  __ TailCallExternalReference(store_callback_property, 4, 1);
2537
2538  // Return the generated code.
2539  return GetCode(kind(), Code::FAST, name);
2540}
2541
2542
2543Handle<Code> StoreStubCompiler::CompileStoreCallback(
2544    Handle<JSObject> object,
2545    Handle<JSObject> holder,
2546    Handle<Name> name,
2547    const CallOptimization& call_optimization) {
2548  HandlerFrontend(IC::CurrentTypeOf(object, isolate()),
2549                  receiver(), holder, name);
2550
2551  Register values[] = { value() };
2552  GenerateFastApiCall(
2553      masm(), call_optimization, receiver(), scratch3(), 1, values);
2554
2555  // Return the generated code.
2556  return GetCode(kind(), Code::FAST, name);
2557}
2558
2559
2560#undef __
2561#define __ ACCESS_MASM(masm)
2562
2563
2564void StoreStubCompiler::GenerateStoreViaSetter(
2565    MacroAssembler* masm,
2566    Handle<JSFunction> setter) {
2567  // ----------- S t a t e -------------
2568  //  -- a0    : value
2569  //  -- a1    : receiver
2570  //  -- a2    : name
2571  //  -- ra    : return address
2572  // -----------------------------------
2573  {
2574    FrameScope scope(masm, StackFrame::INTERNAL);
2575
2576    // Save value register, so we can restore it later.
2577    __ push(a0);
2578
2579    if (!setter.is_null()) {
2580      // Call the JavaScript setter with receiver and value on the stack.
2581      __ push(a1);
2582      __ push(a0);
2583      ParameterCount actual(1);
2584      ParameterCount expected(setter);
2585      __ InvokeFunction(setter, expected, actual,
2586                        CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
2587    } else {
2588      // If we generate a global code snippet for deoptimization only, remember
2589      // the place to continue after deoptimization.
2590      masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2591    }
2592
2593    // We have to return the passed value, not the return value of the setter.
2594    __ pop(v0);
2595
2596    // Restore context register.
2597    __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2598  }
2599  __ Ret();
2600}
2601
2602
2603#undef __
2604#define __ ACCESS_MASM(masm())
2605
2606
2607Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2608    Handle<JSObject> object,
2609    Handle<Name> name) {
2610  Label miss;
2611
2612  // Check that the map of the object hasn't changed.
2613  __ CheckMap(receiver(), scratch1(), Handle<Map>(object->map()), &miss,
2614              DO_SMI_CHECK);
2615
2616  // Perform global security token check if needed.
2617  if (object->IsJSGlobalProxy()) {
2618    __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
2619  }
2620
2621  // Stub is never generated for non-global objects that require access
2622  // checks.
2623  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2624
2625  __ Push(receiver(), this->name(), value());
2626
2627  // Do tail-call to the runtime system.
2628  ExternalReference store_ic_property =
2629      ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
2630  __ TailCallExternalReference(store_ic_property, 3, 1);
2631
2632  // Handle store cache miss.
2633  __ bind(&miss);
2634  TailCallBuiltin(masm(), MissBuiltin(kind()));
2635
2636  // Return the generated code.
2637  return GetCode(kind(), Code::FAST, name);
2638}
2639
2640
2641Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<Type> type,
2642                                                      Handle<JSObject> last,
2643                                                      Handle<Name> name) {
2644  NonexistentHandlerFrontend(type, last, name);
2645
2646  // Return undefined if maps of the full prototype chain is still the same.
2647  __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2648  __ Ret();
2649
2650  // Return the generated code.
2651  return GetCode(kind(), Code::FAST, name);
2652}
2653
2654
2655Register* LoadStubCompiler::registers() {
2656  // receiver, name, scratch1, scratch2, scratch3, scratch4.
2657  static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2658  return registers;
2659}
2660
2661
2662Register* KeyedLoadStubCompiler::registers() {
2663  // receiver, name, scratch1, scratch2, scratch3, scratch4.
2664  static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2665  return registers;
2666}
2667
2668
2669Register* StoreStubCompiler::registers() {
2670  // receiver, name, value, scratch1, scratch2, scratch3.
2671  static Register registers[] = { a1, a2, a0, a3, t0, t1 };
2672  return registers;
2673}
2674
2675
2676Register* KeyedStoreStubCompiler::registers() {
2677  // receiver, name, value, scratch1, scratch2, scratch3.
2678  static Register registers[] = { a2, a1, a0, a3, t0, t1 };
2679  return registers;
2680}
2681
2682
2683void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
2684                                              Register name_reg,
2685                                              Label* miss) {
2686  __ Branch(miss, ne, name_reg, Operand(name));
2687}
2688
2689
2690void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2691                                               Register name_reg,
2692                                               Label* miss) {
2693  __ Branch(miss, ne, name_reg, Operand(name));
2694}
2695
2696
2697#undef __
2698#define __ ACCESS_MASM(masm)
2699
2700
2701void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2702                                             Register receiver,
2703                                             Handle<JSFunction> getter) {
2704  // ----------- S t a t e -------------
2705  //  -- a0    : receiver
2706  //  -- a2    : name
2707  //  -- ra    : return address
2708  // -----------------------------------
2709  {
2710    FrameScope scope(masm, StackFrame::INTERNAL);
2711
2712    if (!getter.is_null()) {
2713      // Call the JavaScript getter with the receiver on the stack.
2714      __ push(receiver);
2715      ParameterCount actual(0);
2716      ParameterCount expected(getter);
2717      __ InvokeFunction(getter, expected, actual,
2718                        CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
2719    } else {
2720      // If we generate a global code snippet for deoptimization only, remember
2721      // the place to continue after deoptimization.
2722      masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2723    }
2724
2725    // Restore context register.
2726    __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2727  }
2728  __ Ret();
2729}
2730
2731
2732#undef __
2733#define __ ACCESS_MASM(masm())
2734
2735
2736Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2737    Handle<Type> type,
2738    Handle<GlobalObject> global,
2739    Handle<PropertyCell> cell,
2740    Handle<Name> name,
2741    bool is_dont_delete) {
2742  Label miss;
2743
2744  HandlerFrontendHeader(type, receiver(), global, name, &miss);
2745
2746  // Get the value from the cell.
2747  __ li(a3, Operand(cell));
2748  __ lw(t0, FieldMemOperand(a3, Cell::kValueOffset));
2749
2750  // Check for deleted property if property can actually be deleted.
2751  if (!is_dont_delete) {
2752    __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2753    __ Branch(&miss, eq, t0, Operand(at));
2754  }
2755
2756  HandlerFrontendFooter(name, &miss);
2757
2758  Counters* counters = isolate()->counters();
2759  __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2760  __ Ret(USE_DELAY_SLOT);
2761  __ mov(v0, t0);
2762
2763  // Return the generated code.
2764  return GetCode(kind(), Code::NORMAL, name);
2765}
2766
2767
2768Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
2769    TypeHandleList* types,
2770    CodeHandleList* handlers,
2771    Handle<Name> name,
2772    Code::StubType type,
2773    IcCheckType check) {
2774  Label miss;
2775
2776  if (check == PROPERTY) {
2777    GenerateNameCheck(name, this->name(), &miss);
2778  }
2779
2780  Label number_case;
2781  Register match = scratch1();
2782  Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
2783  __ JumpIfSmi(receiver(), smi_target, match);  // Reg match is 0 if Smi.
2784
2785  Register map_reg = scratch2();
2786
2787  int receiver_count = types->length();
2788  int number_of_handled_maps = 0;
2789  __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
2790  for (int current = 0; current < receiver_count; ++current) {
2791    Handle<Type> type = types->at(current);
2792    Handle<Map> map = IC::TypeToMap(*type, isolate());
2793    if (!map->is_deprecated()) {
2794      number_of_handled_maps++;
2795      // Check map and tail call if there's a match.
2796      // Separate compare from branch, to provide path for above JumpIfSmi().
2797      __ Subu(match, map_reg, Operand(map));
2798      if (type->Is(Type::Number())) {
2799        ASSERT(!number_case.is_unused());
2800        __ bind(&number_case);
2801      }
2802      __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
2803          eq, match, Operand(zero_reg));
2804    }
2805  }
2806  ASSERT(number_of_handled_maps != 0);
2807
2808  __ bind(&miss);
2809  TailCallBuiltin(masm(), MissBuiltin(kind()));
2810
2811  // Return the generated code.
2812  InlineCacheState state =
2813      number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
2814  return GetICCode(kind(), type, name, state);
2815}
2816
2817
2818Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2819    MapHandleList* receiver_maps,
2820    CodeHandleList* handler_stubs,
2821    MapHandleList* transitioned_maps) {
2822  Label miss;
2823  __ JumpIfSmi(receiver(), &miss);
2824
2825  int receiver_count = receiver_maps->length();
2826  __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
2827  for (int i = 0; i < receiver_count; ++i) {
2828    if (transitioned_maps->at(i).is_null()) {
2829      __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
2830          scratch1(), Operand(receiver_maps->at(i)));
2831    } else {
2832      Label next_map;
2833      __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
2834      __ li(transition_map(), Operand(transitioned_maps->at(i)));
2835      __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
2836      __ bind(&next_map);
2837    }
2838  }
2839
2840  __ bind(&miss);
2841  TailCallBuiltin(masm(), MissBuiltin(kind()));
2842
2843  // Return the generated code.
2844  return GetICCode(
2845      kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
2846}
2847
2848
2849#undef __
2850#define __ ACCESS_MASM(masm)
2851
2852
2853void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
2854    MacroAssembler* masm) {
2855  // ---------- S t a t e --------------
2856  //  -- ra     : return address
2857  //  -- a0     : key
2858  //  -- a1     : receiver
2859  // -----------------------------------
2860  Label slow, miss;
2861
2862  Register key = a0;
2863  Register receiver = a1;
2864
2865  __ JumpIfNotSmi(key, &miss);
2866  __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
2867  __ sra(a2, a0, kSmiTagSize);
2868  __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
2869  __ Ret();
2870
2871  // Slow case, key and receiver still in a0 and a1.
2872  __ bind(&slow);
2873  __ IncrementCounter(
2874      masm->isolate()->counters()->keyed_load_external_array_slow(),
2875      1, a2, a3);
2876  // Entry registers are intact.
2877  // ---------- S t a t e --------------
2878  //  -- ra     : return address
2879  //  -- a0     : key
2880  //  -- a1     : receiver
2881  // -----------------------------------
2882  TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
2883
2884  // Miss case, call the runtime.
2885  __ bind(&miss);
2886
2887  // ---------- S t a t e --------------
2888  //  -- ra     : return address
2889  //  -- a0     : key
2890  //  -- a1     : receiver
2891  // -----------------------------------
2892  TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss);
2893}
2894
2895
2896#undef __
2897
2898} }  // namespace v8::internal
2899
2900#endif  // V8_TARGET_ARCH_MIPS
2901