stub-cache-x64.cc revision 8b112d2025046f85ef7f6be087c6129c872ebad2
1e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// Copyright 2011 the V8 project authors. All rights reserved.
2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without
3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met:
5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions of source code must retain the above copyright
7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       notice, this list of conditions and the following disclaimer.
8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions in binary form must reproduce the above
9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       copyright notice, this list of conditions and the following
10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       disclaimer in the documentation and/or other materials provided
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       with the distribution.
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Neither the name of Google Inc. nor the names of its
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       contributors may be used to endorse or promote products derived
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       from this software without specific prior written permission.
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h"
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#if defined(V8_TARGET_ARCH_X64)
31f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "ic-inl.h"
338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch#include "codegen.h"
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "stub-cache.h"
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm)
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4244f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic void ProbeTable(Isolate* isolate,
4344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                       MacroAssembler* masm,
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       Code::Flags flags,
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       StubCache::Table table,
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       Register name,
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       Register offset) {
483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  ASSERT_EQ(8, kPointerSize);
493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  ASSERT_EQ(16, sizeof(StubCache::Entry));
503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // The offset register holds the entry offset times four (due to masking
513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // and shifting optimizations).
5244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ LoadAddress(kScratchRegister, key_offset);
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key in the entry matches the name.
573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Multiply entry offset by 16 to get the entry address. Since the
583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // offset register already holds the entry offset times four, multiply
593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // by a further four.
603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ cmpl(name, Operand(kScratchRegister, offset, times_4, 0));
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss);
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the code entry from the cache.
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Use key_offset + kPointerSize, rather than loading value_offset.
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(kScratchRegister,
653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          Operand(kScratchRegister, offset, times_4, kPointerSize));
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the flags match what we're looking for.
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset));
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ and_(offset, Immediate(~Code::kFlagsNotUsedInLookup));
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpl(offset, Immediate(flags));
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss);
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Jump to the first instruction in the code stub.
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ addq(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(kScratchRegister);
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
803bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// Helper function used to check that the dictionary doesn't contain
813bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// the property. This function may return false negatives, so miss_label
823bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// must always call a backup property check that is complete.
833bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// This function is safe to call if the receiver has fast properties.
843bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// Name must be a symbol and receiver must be a heap object.
853bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdochstatic void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
863bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                             Label* miss_label,
873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                             Register receiver,
883bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                             String* name,
893bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                             Register r0,
903bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                             Register r1) {
913bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  ASSERT(name->IsSymbol());
9244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
9344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->negative_lookups(), 1);
9444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->negative_lookups_miss(), 1);
953bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
963bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  Label done;
973bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  __ movq(r0, FieldOperand(receiver, HeapObject::kMapOffset));
983bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
993bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const int kInterceptorOrAccessCheckNeededMask =
1003bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
1013bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1023bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // Bail out if the receiver has a named interceptor or requires access checks.
1033bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  __ testb(FieldOperand(r0, Map::kBitFieldOffset),
1043bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch           Immediate(kInterceptorOrAccessCheckNeededMask));
1053bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  __ j(not_zero, miss_label);
1063bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1073bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // Check that receiver is a JSObject.
1083bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE);
1093bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  __ j(below, miss_label);
1103bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1113bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // Load properties array.
1123bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  Register properties = r0;
1133bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  __ movq(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
1143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1153bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // Check that the properties array is a dictionary.
1163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
1173bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                 Heap::kHashTableMapRootIndex);
1183bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  __ j(not_equal, miss_label);
1193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1203bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // Compute the capacity mask.
1213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const int kCapacityOffset =
1223bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      StringDictionary::kHeaderSize +
1233bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      StringDictionary::kCapacityIndex * kPointerSize;
1243bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1253bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // Generate an unrolled loop that performs a few probes before
1263bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // giving up.
1273bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  static const int kProbes = 4;
1283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const int kElementsStartOffset =
1293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      StringDictionary::kHeaderSize +
1303bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      StringDictionary::kElementsStartIndex * kPointerSize;
1313bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
1333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
1343bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // undefined value), it guarantees the hash table doesn't contain the
1353bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // property. It's true even if some slots represent deleted properties
1363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // (their names are the null value).
1373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  for (int i = 0; i < kProbes; i++) {
1383bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    // r0 points to properties hash.
1393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
1403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    Register index = r1;
1413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    // Capacity is smi 2^n.
1423bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset));
1433bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    __ decl(index);
1443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    __ and_(index,
1453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch            Immediate(name->Hash() + StringDictionary::GetProbeOffset(i)));
1463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    // Scale the index by multiplying by the entry size.
1483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
1493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
1503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    Register entity_name = r1;
1523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    // Having undefined at this place means the name is not contained.
1533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    ASSERT_EQ(kSmiTagSize, 1);
1543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    __ movq(entity_name, Operand(properties, index, times_pointer_size,
1553bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                 kElementsStartOffset - kHeapObjectTag));
15644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ Cmp(entity_name, masm->isolate()->factory()->undefined_value());
1573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    // __ jmp(miss_label);
1583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    if (i != kProbes - 1) {
1593bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ j(equal, &done);
1603bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1613bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      // Stop if found the property.
1623bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ Cmp(entity_name, Handle<String>(name));
1633bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ j(equal, miss_label);
1643bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1653bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      // Check if the entry name is not a symbol.
1663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
1673bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
1683bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch               Immediate(kIsSymbolMask));
1693bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ j(zero, miss_label);
1703bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    } else {
1713bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      // Give up probing if still not found the undefined value.
1723bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ j(not_equal, miss_label);
1733bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    }
1743bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  }
1753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1763bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  __ bind(&done);
17744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ DecrementCounter(counters->negative_lookups_miss(), 1);
1783bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch}
1793bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1803bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCache::GenerateProbe(MacroAssembler* masm,
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Code::Flags flags,
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Register receiver,
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Register name,
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Register scratch,
1863e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu                              Register extra,
1873e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu                              Register extra2) {
18844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Isolate* isolate = masm->isolate();
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
1903e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu  USE(extra);   // The register extra is not used on the X64 platform.
1913e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu  USE(extra2);  // The register extra2 is not used on the X64 platform.
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure that code is valid. The shifting code relies on the
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // entry size being 16.
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(sizeof(Entry) == 16);
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure the flags do not name a specific type.
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure that there are no register conflicts.
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!scratch.is(receiver));
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!scratch.is(name));
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2033e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu  // Check scratch register is valid, extra and extra2 are unused.
2043e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu  ASSERT(!scratch.is(no_reg));
2053e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu  ASSERT(extra2.is(no_reg));
2063e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(receiver, &miss);
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the map of the receiver and compute the hash.
211d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movl(scratch, FieldOperand(name, String::kHashFieldOffset));
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Use only the low 32 bits of the map pointer.
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ xor_(scratch, Immediate(flags));
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the primary table.
21844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ProbeTable(isolate, masm, flags, kPrimary, name, scratch);
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Primary miss: Compute hash for secondary probe.
221d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movl(scratch, FieldOperand(name, String::kHashFieldOffset));
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ xor_(scratch, Immediate(flags));
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ subl(scratch, name);
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ addl(scratch, Immediate(flags));
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ and_(scratch, Immediate((kSecondaryTableSize - 1) << kHeapObjectTagSize));
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the secondary table.
23044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ProbeTable(isolate, masm, flags, kSecondary, name, scratch);
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Fall-through and let caller handle the miss by
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // entering the runtime system.
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
2399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                       int index,
2409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                       Register prototype) {
2419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Load the global or builtins object from the current context.
2429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(prototype,
2439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block             Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Load the global context from the global or builtins object.
2459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(prototype,
2469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block             FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
2479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Load the function from the global context.
2489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
2499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Load the initial map.  The global functions all have initial maps.
2509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(prototype,
2519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block             FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
2529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Load the prototype from the initial map.
2539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
2549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
2589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    MacroAssembler* masm, int index, Register prototype, Label* miss) {
25944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Isolate* isolate = masm->isolate();
2609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check we're still in the same context.
26144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Move(prototype, isolate->global());
2629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)),
2639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block          prototype);
2649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, miss);
2659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the global function with the given index.
26644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  JSFunction* function =
26744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      JSFunction::cast(isolate->global_context()->get(index));
2689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Load its initial map. The global functions all have initial maps.
2699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Move(prototype, Handle<Map>(function->initial_map()));
2709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Load the prototype from the initial map.
2719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Register receiver,
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Register scratch,
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Label* miss_label) {
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(receiver, miss_label);
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is a JS array.
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, miss_label);
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load length directly from the JS array.
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, FieldOperand(receiver, JSArray::kLengthOffset));
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Generate code to check if an object is a string.  If the object is
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// a string, the map's instance type is left in the scratch register.
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void GenerateStringCheck(MacroAssembler* masm,
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Register receiver,
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Register scratch,
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Label* smi,
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Label* non_string_object) {
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(receiver, smi);
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is a string.
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzxbq(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(kNotStringTag != 0);
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ testl(scratch, Immediate(kNotStringTag));
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, non_string_object);
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            Register receiver,
313402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                            Register scratch1,
314402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                            Register scratch2,
3151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                            Label* miss,
3161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                            bool support_wrappers) {
317402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label check_wrapper;
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the object is a string leaving the instance type in the
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // scratch register.
3211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateStringCheck(masm, receiver, scratch1, miss,
3221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                      support_wrappers ? &check_wrapper : miss);
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load length directly from the string.
3256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ movq(rax, FieldOperand(receiver, String::kLengthOffset));
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (support_wrappers) {
3291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Check if the object is a JSValue wrapper.
3301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ bind(&check_wrapper);
3311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ cmpl(scratch1, Immediate(JS_VALUE_TYPE));
3321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ j(not_equal, miss);
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Check if the wrapped value is a string and load the length
3351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // directly if it is.
3361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
3371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
3381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movq(rax, FieldOperand(scratch2, String::kLengthOffset));
3391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ ret(0);
3401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
3459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 Register receiver,
3469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 Register result,
3479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 Register scratch,
3489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 Label* miss_label) {
3499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ TryGetFunctionPrototype(receiver, result, miss_label);
3509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (!result.is(rax)) __ movq(rax, result);
3519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret(0);
3529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
3539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
3549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
3559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// Load a fast property out of a holder object (src). In-object properties
3569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// are loaded directly otherwise the property is loaded from the properties
3579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// fixed array.
3589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
3599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                            Register dst, Register src,
3609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                            JSObject* holder, int index) {
3619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Adjust for the number of properties stored in the holder.
3629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  index -= holder->map()->inobject_properties();
3639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (index < 0) {
3649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Get the property straight out of the holder.
3659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    int offset = holder->map()->instance_size() + (index * kPointerSize);
3669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(dst, FieldOperand(src, offset));
3679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  } else {
3689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Calculate the offset into the properties array.
3699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    int offset = index * kPointerSize + FixedArray::kHeaderSize;
3709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
3719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(dst, FieldOperand(dst, offset));
3729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
3739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
3749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
3759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
3769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockstatic void PushInterceptorArguments(MacroAssembler* masm,
3779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     Register receiver,
3789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     Register holder,
3799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     Register name,
3809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     JSObject* holder_obj) {
3819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(name);
3829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
38344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor));
3849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Move(kScratchRegister, Handle<Object>(interceptor));
3859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(kScratchRegister);
3869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(receiver);
3879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(holder);
3889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
3899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
3909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
3919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   Register receiver,
394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   Register holder,
395402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                                   Register name,
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   JSObject* holder_obj) {
397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference ref =
40044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
40144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        masm->isolate());
4028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ Set(rax, 5);
40344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ LoadAddress(rbx, ref);
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CEntryStub stub(1);
406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CallStub(&stub);
407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4108a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang// Number of pointers to be reserved on stack for fast API call.
4118a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wangstatic const int kFastApiCallArguments = 3;
412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
4148a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang// Reserves space for the extra arguments to API function in the
4156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// caller's frame.
4166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block//
4176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// These arguments are set by CheckPrototypes and GenerateFastApiCall.
4186ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
4196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ----------- S t a t e -------------
4206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- rsp[0] : return address
4216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- rsp[8] : last argument in the internal frame of the caller
4226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // -----------------------------------
4236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ movq(scratch, Operand(rsp, 0));
4248a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
4256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ movq(Operand(rsp, 0), scratch);
4266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ Move(scratch, Smi::FromInt(0));
4278a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  for (int i = 1; i <= kFastApiCallArguments; i++) {
4288a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang     __ movq(Operand(rsp, i * kPointerSize), scratch);
4298a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  }
4306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
4316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
4326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
4336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// Undoes the effects of ReserveSpaceForFastApiCall.
4346ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
4356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ----------- S t a t e -------------
4368a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //  -- rsp[0]  : return address.
4378a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //  -- rsp[8]  : last fast api call extra argument.
4386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ...
4398a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //  -- rsp[kFastApiCallArguments * 8] : first fast api call extra argument.
4408a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //  -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal
4418a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //                                          frame.
4426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // -----------------------------------
4436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ movq(scratch, Operand(rsp, 0));
4448a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch);
4458a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments));
4466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
4476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
4486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
4498a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang// Generates call to API function.
4501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockstatic MaybeObject* GenerateFastApiCall(MacroAssembler* masm,
4511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                        const CallOptimization& optimization,
4521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                        int argc) {
4536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ----------- S t a t e -------------
4546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- rsp[0]              : return address
4556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- rsp[8]              : object passing the type check
4566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //                           (last fast api call extra argument,
4576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //                            set by CheckPrototypes)
4588a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //  -- rsp[16]             : api function
4596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //                           (first fast api call extra argument)
4608a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //  -- rsp[24]             : api call data
4618a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //  -- rsp[32]             : last argument
4626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ...
4638a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //  -- rsp[(argc + 3) * 8] : first argument
4648a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //  -- rsp[(argc + 4) * 8] : receiver
4656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // -----------------------------------
4666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Get the function and setup the context.
4676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  JSFunction* function = optimization.constant_function();
4686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ Move(rdi, Handle<JSFunction>(function));
4696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
4706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
4718a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // Pass the additional arguments.
4728a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ movq(Operand(rsp, 2 * kPointerSize), rdi);
4736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Object* call_data = optimization.api_call_info()->data();
4748a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
47544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (masm->isolate()->heap()->InNewSpace(call_data)) {
4768a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    __ Move(rcx, api_call_info_handle);
4776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset));
4788a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    __ movq(Operand(rsp, 3 * kPointerSize), rbx);
4796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  } else {
4808a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    __ Move(Operand(rsp, 3 * kPointerSize), Handle<Object>(call_data));
4816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
4826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
4838a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // Prepare arguments.
4848a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ lea(rbx, Operand(rsp, 3 * kPointerSize));
4856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
4868a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  Object* callback = optimization.api_call_info()->callback();
4878a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  Address api_function_address = v8::ToCData<Address>(callback);
4888a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  ApiFunction fun(api_function_address);
4898a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
4908a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#ifdef _WIN64
4918a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // Win64 uses first register--rcx--for returned value.
4928a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  Register arguments_arg = rdx;
4938a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#else
4948a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  Register arguments_arg = rdi;
4958a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#endif
4968a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
4978a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // Allocate the v8::Arguments structure in the arguments' space since
4988a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // it's not controlled by GC.
4998a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const int kApiStackSpace = 4;
5008a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
5018a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ PrepareCallApiFunction(kApiStackSpace);
5028a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
5038a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ movq(StackSpaceOperand(0), rbx);  // v8::Arguments::implicit_args_.
5048a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ addq(rbx, Immediate(argc * kPointerSize));
5058a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ movq(StackSpaceOperand(1), rbx);  // v8::Arguments::values_.
5068a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ Set(StackSpaceOperand(2), argc);  // v8::Arguments::length_.
5078a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // v8::Arguments::is_construct_call_.
5088a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ Set(StackSpaceOperand(3), 0);
5098a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
5108a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // v8::InvocationCallback's argument.
5118a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ lea(arguments_arg, StackSpaceOperand(0));
5128a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // Emitting a stub call may try to allocate (if the code is not
5138a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // already generated).  Do not allow the assembler to perform a
5148a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // garbage collection but instead return the allocation failure
5158a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // object.
5161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  return masm->TryCallApiFunctionAndReturn(&fun,
5171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                           argc + kFastApiCallArguments + 1);
5186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
5196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
5206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass CallInterceptorCompiler BASE_EMBEDDED {
522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
5236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  CallInterceptorCompiler(StubCompiler* stub_compiler,
5246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                          const ParameterCount& arguments,
5256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                          Register name)
5266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      : stub_compiler_(stub_compiler),
5276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        arguments_(arguments),
5286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        name_(name) {}
5296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
5301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  MaybeObject* Compile(MacroAssembler* masm,
5311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                       JSObject* object,
5321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                       JSObject* holder,
5331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                       String* name,
5341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                       LookupResult* lookup,
5351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                       Register receiver,
5361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                       Register scratch1,
5371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                       Register scratch2,
5381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                       Register scratch3,
5391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                       Label* miss) {
5406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    ASSERT(holder->HasNamedInterceptor());
5416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
5426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
5436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Check that the receiver isn't a smi.
5446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ JumpIfSmi(receiver, miss);
5456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
5466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    CallOptimization optimization(lookup);
5476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
5486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (optimization.is_constant_call()) {
5498a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      return CompileCacheable(masm,
5508a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                              object,
5518a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                              receiver,
5528a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                              scratch1,
5538a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                              scratch2,
5548a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                              scratch3,
5558a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                              holder,
5568a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                              lookup,
5578a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                              name,
5588a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                              optimization,
5591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                              miss);
5606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    } else {
5616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      CompileRegular(masm,
5626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                     object,
5636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                     receiver,
5646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                     scratch1,
5656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                     scratch2,
5663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                     scratch3,
5676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                     name,
5686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                     holder,
5696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                     miss);
57044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      return masm->isolate()->heap()->undefined_value();  // Success.
5716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
5726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block private:
5751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  MaybeObject* CompileCacheable(MacroAssembler* masm,
5761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                JSObject* object,
5771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                Register receiver,
5781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                Register scratch1,
5791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                Register scratch2,
5801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                Register scratch3,
5811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                JSObject* interceptor_holder,
5821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                LookupResult* lookup,
5831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                String* name,
5841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                const CallOptimization& optimization,
5851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                Label* miss_label) {
5866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    ASSERT(optimization.is_constant_call());
5876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    ASSERT(!lookup->holder()->IsGlobalObject());
5886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
5896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    int depth1 = kInvalidProtoDepth;
5906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    int depth2 = kInvalidProtoDepth;
5916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    bool can_do_fast_api_call = false;
5926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (optimization.is_simple_api_call() &&
5936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        !lookup->holder()->IsGlobalObject()) {
594f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke      depth1 =
595f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke          optimization.GetPrototypeDepthOfExpectedType(object,
596f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                                                       interceptor_holder);
5976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      if (depth1 == kInvalidProtoDepth) {
598f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke        depth2 =
599f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke            optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
600f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                                                         lookup->holder());
601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
6026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
6036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                             (depth2 != kInvalidProtoDepth);
604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
60644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Counters* counters = masm->isolate()->counters();
60744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ IncrementCounter(counters->call_const_interceptor(), 1);
608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (can_do_fast_api_call) {
61044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
6116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      ReserveSpaceForFastApiCall(masm, scratch1);
6126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
613402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
614f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Check that the maps from receiver to interceptor's holder
615f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // haven't changed and thus we can invoke interceptor.
6166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    Label miss_cleanup;
6176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
6186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    Register holder =
6197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch        stub_compiler_->CheckPrototypes(object, receiver,
6207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                        interceptor_holder, scratch1,
6213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                        scratch2, scratch3, name, depth1, miss);
622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
623f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Invoke an interceptor and if it provides a value,
624f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // branch to |regular_invoke|.
6256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    Label regular_invoke;
626f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
627f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                        &regular_invoke);
628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
629f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Interceptor returned nothing for this property.  Try to use cached
630f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // constant function.
631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
632f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Check that the maps from interceptor's holder to constant function's
633f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // holder haven't changed and thus we can use cached constant function.
6347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    if (interceptor_holder != lookup->holder()) {
6357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
6367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                      lookup->holder(), scratch1,
6373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                      scratch2, scratch3, name, depth2, miss);
6387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    } else {
6397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // CheckPrototypes has a side effect of fetching a 'holder'
6407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // for API (object which is instanceof for the signature).  It's
6417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // safe to omit it here, as if present, it should be fetched
6427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // by the previous CheckPrototypes.
6437f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      ASSERT(depth2 == kInvalidProtoDepth);
6447f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    }
645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
646f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Invoke function.
6476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (can_do_fast_api_call) {
6481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      MaybeObject* result = GenerateFastApiCall(masm,
6491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                optimization,
6501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                arguments_.immediate());
6511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      if (result->IsFailure()) return result;
6526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    } else {
6536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ InvokeFunction(optimization.constant_function(), arguments_,
6546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                        JUMP_FUNCTION);
6556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
657f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Deferred code for fast API call case---clean preallocated space.
6586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (can_do_fast_api_call) {
6596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ bind(&miss_cleanup);
6606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      FreeSpaceForFastApiCall(masm, scratch1);
6616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ jmp(miss_label);
6626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
664f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Invoke a regular function.
6656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ bind(&regular_invoke);
6666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (can_do_fast_api_call) {
6676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      FreeSpaceForFastApiCall(masm, scratch1);
6686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
6698a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
67044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return masm->isolate()->heap()->undefined_value();  // Success.
671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void CompileRegular(MacroAssembler* masm,
6746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                      JSObject* object,
675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      Register receiver,
6766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                      Register scratch1,
6776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                      Register scratch2,
6783bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                      Register scratch3,
6796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                      String* name,
680f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                      JSObject* interceptor_holder,
681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      Label* miss_label) {
6826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    Register holder =
683f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke        stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
6843bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                        scratch1, scratch2, scratch3, name,
6856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                        miss_label);
6866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ EnterInternalFrame();
688402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Save the name_ register across the call.
689402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ push(name_);
690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    PushInterceptorArguments(masm,
692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                             receiver,
693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                             holder,
694402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                             name_,
695f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                             interceptor_holder);
696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
697402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ CallExternalReference(
69844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
69944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                          masm->isolate()),
700402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        5);
701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Restore the name_ register.
703402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ pop(name_);
704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LeaveInternalFrame();
705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  void LoadWithInterceptor(MacroAssembler* masm,
7086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                           Register receiver,
7096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                           Register holder,
7106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                           JSObject* holder_obj,
7116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                           Label* interceptor_succeeded) {
7126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ EnterInternalFrame();
7136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ push(holder);  // Save the holder.
7146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ push(name_);  // Save the name.
7156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
7166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    CompileCallLoadPropertyWithInterceptor(masm,
7176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                           receiver,
7186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                           holder,
7196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                           name_,
7206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                           holder_obj);
7216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
7226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ pop(name_);  // Restore the name.
7236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ pop(receiver);  // Restore the holder.
7246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ LeaveInternalFrame();
7256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
7266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
7276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ j(not_equal, interceptor_succeeded);
7286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
7296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
7306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  StubCompiler* stub_compiler_;
731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const ParameterCount& arguments_;
732402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Register name_;
733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
7379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
7389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Code* code = NULL;
7399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (kind == Code::LOAD_IC) {
74044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss);
7419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  } else {
74244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss);
7439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
7449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
7459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Handle<Code> ic(code);
7469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Jump(ic, RelocInfo::CODE_TARGET);
7479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
7489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
7499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
7509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// Both name_reg and receiver_reg are preserved on jumps to miss_label,
7519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// but may be destroyed if store is successful.
7529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateStoreField(MacroAssembler* masm,
7539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                      JSObject* object,
7549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                      int index,
7559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                      Map* transition,
7569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                      Register receiver_reg,
7579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                      Register name_reg,
7589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                      Register scratch,
7599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                      Label* miss_label) {
7609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the object isn't a smi.
7619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(receiver_reg, miss_label);
7629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
7639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the map of the object hasn't changed.
7649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
7659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block         Handle<Map>(object->map()));
7669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, miss_label);
7679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
7689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Perform global security token check if needed.
7699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (object->IsJSGlobalProxy()) {
7709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
7719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
7729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
7739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Stub never generated for non-global objects that require access
7749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // checks.
7759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
7769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
7779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Perform map transition for the receiver if necessary.
7789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
7799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // The properties must be extended before we can store the value.
7809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // We jump to a runtime call that extends the properties array.
7819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ pop(scratch);  // Return address.
7829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ push(receiver_reg);
7839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ Push(Handle<Map>(transition));
7849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ push(rax);
7859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ push(scratch);
7869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ TailCallExternalReference(
78744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
78844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                          masm->isolate()),
78944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        3,
79044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        1);
7919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    return;
7929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
7939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
7949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (transition != NULL) {
7959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Update the map of the object; no write barrier updating is
7969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // needed because the map is never in new space.
7979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset),
7989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block            Handle<Map>(transition));
7999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
8009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
8019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Adjust for the number of properties stored in the object. Even in the
8029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // face of a transition we can use the old map here because the size of the
8039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // object and the number of in-object properties is not going to change.
8049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  index -= object->map()->inobject_properties();
8059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
8069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (index < 0) {
8079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Set the property straight into the object.
8089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    int offset = object->map()->instance_size() + (index * kPointerSize);
8099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(FieldOperand(receiver_reg, offset), rax);
8109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
8119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Update the write barrier for the array address.
8129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Pass the value being stored in the now unused name_reg.
8139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(name_reg, rax);
8149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ RecordWrite(receiver_reg, offset, name_reg, scratch);
8159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  } else {
8169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Write to the properties array.
8179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    int offset = index * kPointerSize + FixedArray::kHeaderSize;
8189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Get the properties array (optimistically).
8199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
8209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(FieldOperand(scratch, offset), rax);
8219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
8229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Update the write barrier for the array address.
8239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Pass the value being stored in the now unused name_reg.
8249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(name_reg, rax);
8259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ RecordWrite(scratch, offset, name_reg, receiver_reg);
8269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
8279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
8289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the value (register rax).
8299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret(0);
8309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
8319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
8329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
8339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// Generate code to check that a global property cell is empty. Create
8349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// the property cell at compilation time if no cell exists for the
8356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// property.
8365913587db4c6bab03d97bfe44b06289fd6d7270dJohn ReckMUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
8375913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck    MacroAssembler* masm,
8385913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck    GlobalObject* global,
8395913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck    String* name,
8405913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck    Register scratch,
8415913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck    Label* miss) {
8425913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck  Object* probe;
8435913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck  { MaybeObject* maybe_probe = global->EnsurePropertyCell(name);
8445913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck    if (!maybe_probe->ToObject(&probe)) return maybe_probe;
8455913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck  }
8466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
8476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ASSERT(cell->value()->IsTheHole());
8486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ Move(scratch, Handle<Object>(cell));
8496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
85044f0eee88ff00398ff7f715fab053374d808c90dSteve Block         masm->isolate()->factory()->the_hole_value());
8516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_equal, miss);
8526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  return cell;
8536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
8546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
8556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM((masm()))
858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8599dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
8609fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockRegister StubCompiler::CheckPrototypes(JSObject* object,
8619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       Register object_reg,
8629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       JSObject* holder,
8639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       Register holder_reg,
8649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       Register scratch1,
8659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       Register scratch2,
8669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       String* name,
8679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       int save_at_depth,
8689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       Label* miss) {
8699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Make sure there's no overlap between holder and object registers.
8709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
8719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
8729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block         && !scratch2.is(scratch1));
8739dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
8749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Keep track of the current object in register reg.  On the first
8759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // iteration, reg is an alias for object_reg, on later iterations,
8769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // it is an alias for holder_reg.
8779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register reg = object_reg;
8789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  int depth = 0;
8799dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
8809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (save_at_depth == depth) {
8819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(Operand(rsp, kPointerSize), object_reg);
8829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
88359151504615d929945dc59db37bf1166937748c6Steve Block
8849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check the maps in the prototype chain.
8859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Traverse the prototype chain from the object and do map checks.
8869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  JSObject* current = object;
8879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  while (current != holder) {
8889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    depth++;
88959151504615d929945dc59db37bf1166937748c6Steve Block
8909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Only global objects and objects that do not require access
8919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // checks are allowed in stubs.
8929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
89359151504615d929945dc59db37bf1166937748c6Steve Block
8949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSObject* prototype = JSObject::cast(current->GetPrototype());
8959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (!current->HasFastProperties() &&
8969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        !current->IsJSGlobalObject() &&
8979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        !current->IsJSGlobalProxy()) {
8989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      if (!name->IsSymbol()) {
89944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        MaybeObject* lookup_result = heap()->LookupSymbol(name);
9009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        if (lookup_result->IsFailure()) {
9019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block          set_failure(Failure::cast(lookup_result));
9029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block          return reg;
9039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        } else {
9049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block          name = String::cast(lookup_result->ToObjectUnchecked());
9059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        }
9069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      }
9079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      ASSERT(current->property_dictionary()->FindEntry(name) ==
9089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block             StringDictionary::kNotFound);
90959151504615d929945dc59db37bf1166937748c6Steve Block
9109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      GenerateDictionaryNegativeLookup(masm(),
9119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       miss,
9129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       reg,
9139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       name,
9149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       scratch1,
9159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                       scratch2);
9169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
9179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      reg = holder_reg;  // from now the object is in holder_reg
9189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
91944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    } else if (heap()->InNewSpace(prototype)) {
9209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Get the map of the current object.
9219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
9229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Cmp(scratch1, Handle<Map>(current->map()));
9239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Branch on the result of the map check.
9249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ j(not_equal, miss);
9259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Check access rights to the global object.  This has to happen
9269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // after the map check so that we know that the object is
9279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // actually a global object.
9289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      if (current->IsJSGlobalProxy()) {
9299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ CheckAccessGlobalProxy(reg, scratch1, miss);
93059151504615d929945dc59db37bf1166937748c6Steve Block
9319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        // Restore scratch register to be the map of the object.
9329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        // We load the prototype from the map in the scratch register.
9339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
9349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      }
9359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // The prototype is in new space; we cannot store a reference
9369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // to it in the code. Load it from the map.
9379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      reg = holder_reg;  // from now the object is in holder_reg
9389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
93959151504615d929945dc59db37bf1166937748c6Steve Block
9409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    } else {
9419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Check the map of the current object.
9429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
9439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block          Handle<Map>(current->map()));
9449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Branch on the result of the map check.
9459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ j(not_equal, miss);
9469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Check access rights to the global object.  This has to happen
9479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // after the map check so that we know that the object is
9489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // actually a global object.
9499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      if (current->IsJSGlobalProxy()) {
9509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ CheckAccessGlobalProxy(reg, scratch1, miss);
9519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      }
9529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // The prototype is in old space; load it directly.
9539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      reg = holder_reg;  // from now the object is in holder_reg
9549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Move(reg, Handle<JSObject>(prototype));
9559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    }
95659151504615d929945dc59db37bf1166937748c6Steve Block
9579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (save_at_depth == depth) {
9589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ movq(Operand(rsp, kPointerSize), reg);
9599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    }
96059151504615d929945dc59db37bf1166937748c6Steve Block
9619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Go to the next object in the prototype chain.
9629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    current = prototype;
96359151504615d929945dc59db37bf1166937748c6Steve Block  }
96459151504615d929945dc59db37bf1166937748c6Steve Block
9659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check the holder map.
9669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map()));
9679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, miss);
96859151504615d929945dc59db37bf1166937748c6Steve Block
9699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Log the check depth.
97044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
9717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
9729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Perform security check for access to the global object and return
9739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // the holder register.
9749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(current == holder);
9759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
9769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (current->IsJSGlobalProxy()) {
9779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ CheckAccessGlobalProxy(reg, scratch1, miss);
978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
9809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If we've skipped any global objects, it's not enough to verify
9819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // that their maps haven't changed.  We also need to check that the
9829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // property cell for the property is still empty.
9839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  current = object;
9849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  while (current != holder) {
9859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (current->IsGlobalObject()) {
9869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      MaybeObject* cell = GenerateCheckPropertyCell(masm(),
9879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    GlobalObject::cast(current),
9889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    name,
9899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    scratch1,
9909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    miss);
9919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      if (cell->IsFailure()) {
9929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        set_failure(Failure::cast(cell));
9939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        return reg;
994e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      }
9958a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    }
9969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    current = JSObject::cast(current->GetPrototype());
9975913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck  }
998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
9999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the register containing the holder.
10009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return reg;
1001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
10049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadField(JSObject* object,
10059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     JSObject* holder,
10069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     Register receiver,
10079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     Register scratch1,
10089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     Register scratch2,
10099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     Register scratch3,
10109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     int index,
10119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     String* name,
10129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                     Label* miss) {
1013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
10149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(receiver, miss);
1015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
10169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check the prototype chain.
10179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register reg =
10189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      CheckPrototypes(object, receiver, holder,
10199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                      scratch1, scratch2, scratch3, name, miss);
1020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
10219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the value from the properties.
10229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
10239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret(0);
1024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
10271e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockMaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
10281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                JSObject* holder,
10291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                Register receiver,
10301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                Register name_reg,
10311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                Register scratch1,
10321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                Register scratch2,
10331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                Register scratch3,
10341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                AccessorInfo* callback,
10351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                String* name,
10361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                Label* miss) {
10379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the receiver isn't a smi.
10389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(receiver, miss);
10396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
10409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the maps haven't changed.
10419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register reg =
10429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      CheckPrototypes(object, receiver, holder, scratch1,
10439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                      scratch2, scratch3, name, miss);
10446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
10459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Handle<AccessorInfo> callback_handle(callback);
10466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
10479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Insert additional parameters into the stack frame above return address.
10489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(!scratch2.is(reg));
10499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ pop(scratch2);  // Get return address to place it below.
10509dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
10519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(receiver);  // receiver
10529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(reg);  // holder
105344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (heap()->InNewSpace(callback_handle->data())) {
10549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ Move(scratch1, callback_handle);
10559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset));  // data
10569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  } else {
10579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ Push(Handle<Object>(callback_handle->data()));
10589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
10599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(name_reg);  // name
10609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Save a pointer to where we pushed the arguments pointer.
10619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // This will be passed as the const AccessorInfo& to the C++ callback.
10626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
10639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block#ifdef _WIN64
10649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Win64 uses first register--rcx--for returned value.
10659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register accessor_info_arg = r8;
10669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register name_arg = rdx;
10679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block#else
10689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register accessor_info_arg = rsi;
10699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register name_arg = rdi;
10709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block#endif
10716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
10729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(!name_arg.is(scratch2));
10739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(name_arg, rsp);
10749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(scratch2);  // Restore return address.
10756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
10769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Do call through the api.
10779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Address getter_address = v8::ToCData<Address>(callback->getter());
10789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ApiFunction fun(getter_address);
1079756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
10809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // 3 elements array for v8::Agruments::values_ and handler for name.
10819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int kStackSpace = 4;
10826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
10839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Allocate v8::AccessorInfo in non-GCed stack space.
10849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int kArgStackSpace = 1;
10856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
10869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ PrepareCallApiFunction(kArgStackSpace);
10879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ lea(rax, Operand(name_arg, 3 * kPointerSize));
10886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
10899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // v8::AccessorInfo::args_.
10909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(StackSpaceOperand(0), rax);
10916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
10929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // The context register (rsi) has been saved in PrepareCallApiFunction and
10939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // could be used to pass arguments.
10949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ lea(accessor_info_arg, StackSpaceOperand(0));
10956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
10969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Emitting a stub call may try to allocate (if the code is not
10979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // already generated).  Do not allow the assembler to perform a
10989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // garbage collection but instead return the allocation failure
10999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // object.
11001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
11019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
11026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
11036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
11049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadConstant(JSObject* object,
11059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                        JSObject* holder,
11069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                        Register receiver,
11079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                        Register scratch1,
11089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                        Register scratch2,
11099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                        Register scratch3,
11109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                        Object* value,
11119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                        String* name,
11129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                        Label* miss) {
11139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the receiver isn't a smi.
11149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(receiver, miss);
11156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
11169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the maps haven't changed.
11179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register reg =
11189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      CheckPrototypes(object, receiver, holder,
11199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                      scratch1, scratch2, scratch3, name, miss);
11209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
11219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the constant value.
11229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Move(rax, Handle<Object>(value));
11239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret(0);
11249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
11256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
11266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
11279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadInterceptor(JSObject* object,
11289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           JSObject* interceptor_holder,
11299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           LookupResult* lookup,
11309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           Register receiver,
11319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           Register name_reg,
11329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           Register scratch1,
11339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           Register scratch2,
11349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           Register scratch3,
11359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           String* name,
11369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           Label* miss) {
11379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(interceptor_holder->HasNamedInterceptor());
11389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
11396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
11409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the receiver isn't a smi.
11419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(receiver, miss);
11426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
11439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // So far the most popular follow ups for interceptor loads are FIELD
11449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // and CALLBACKS, so inline only them, other cases may be added
11459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // later.
11469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  bool compile_followup_inline = false;
11479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (lookup->IsProperty() && lookup->IsCacheable()) {
11489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (lookup->type() == FIELD) {
11499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      compile_followup_inline = true;
11509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    } else if (lookup->type() == CALLBACKS &&
11519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        lookup->GetCallbackObject()->IsAccessorInfo() &&
11529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
11539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      compile_followup_inline = true;
11549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    }
11559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
11569dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
11579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (compile_followup_inline) {
11589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Compile the interceptor call, followed by inline code to load the
11599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // property from further up the prototype chain if the call fails.
11609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Check that the maps haven't changed.
11619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
11629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                          scratch1, scratch2, scratch3,
11639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                          name, miss);
11649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
11656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
11669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Save necessary data before invoking an interceptor.
11679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Requires a frame to make GC aware of pushed pointers.
11689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ EnterInternalFrame();
11695913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck
11709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
11719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // CALLBACKS case needs a receiver to be passed into C++ callback.
11729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ push(receiver);
11739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    }
11749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ push(holder_reg);
11759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ push(name_reg);
11766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
11779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Invoke an interceptor.  Note: map checks from receiver to
11789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // interceptor's holder has been compiled before (see a caller
11799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // of this method.)
11809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    CompileCallLoadPropertyWithInterceptor(masm(),
11819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           receiver,
11829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           holder_reg,
11839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           name_reg,
11849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                           interceptor_holder);
11856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
11869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Check if interceptor provided a value for property.  If it's
11879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // the case, return immediately.
11889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    Label interceptor_failed;
11899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
11909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ j(equal, &interceptor_failed);
11919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ LeaveInternalFrame();
11929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ ret(0);
11936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
11949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ bind(&interceptor_failed);
11959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ pop(name_reg);
11969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ pop(holder_reg);
11979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
11989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ pop(receiver);
11999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    }
12006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ LeaveInternalFrame();
12026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Check that the maps from interceptor's holder to lookup's holder
12049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // haven't changed.  And load lookup's holder into |holder| register.
12059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (interceptor_holder != lookup->holder()) {
12069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      holder_reg = CheckPrototypes(interceptor_holder,
12079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                   holder_reg,
12089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                   lookup->holder(),
12099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                   scratch1,
12109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                   scratch2,
12119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                   scratch3,
12129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                   name,
12139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                   miss);
12149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    }
12156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (lookup->type() == FIELD) {
12179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // We found FIELD property in prototype chain of interceptor's holder.
12189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Retrieve a field from field's holder.
12199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      GenerateFastPropertyLoad(masm(), rax, holder_reg,
12209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                               lookup->holder(), lookup->GetFieldIndex());
12219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ ret(0);
12229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    } else {
12239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // We found CALLBACKS property in prototype chain of interceptor's
12249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // holder.
12259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      ASSERT(lookup->type() == CALLBACKS);
12269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
12279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
12289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      ASSERT(callback != NULL);
12299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      ASSERT(callback->getter() != NULL);
1230756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
12319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Tail call to runtime.
12329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Important invariant in CALLBACKS case: the code above must be
12339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // structured to never clobber |receiver| register.
12349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ pop(scratch2);  // return address
12359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ push(receiver);
12369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ push(holder_reg);
12379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Move(holder_reg, Handle<AccessorInfo>(callback));
12389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
12399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ push(holder_reg);
12409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ push(name_reg);
12419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ push(scratch2);  // restore return address
1242756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
12439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      ExternalReference ref =
124444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
124544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                            isolate());
12469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ TailCallExternalReference(ref, 5, 1);
12476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
12489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  } else {  // !compile_followup_inline
12499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Call the runtime system to load the interceptor.
12509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Check that the maps haven't changed.
12519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
12529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                          scratch1, scratch2, scratch3,
12539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                          name, miss);
12549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ pop(scratch2);  // save old return address
12559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    PushInterceptorArguments(masm(), receiver, holder_reg,
12569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                             name_reg, interceptor_holder);
12579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ push(scratch2);  // restore old return address
12586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    ExternalReference ref = ExternalReference(
126044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
12619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ TailCallExternalReference(ref, 5, 1);
12625913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck  }
12636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
12646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
12679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (kind_ == Code::KEYED_CALL_IC) {
12689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ Cmp(rcx, Handle<String>(name));
12699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ j(not_equal, miss);
12709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
12719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
12726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
12759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   JSObject* holder,
12769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   String* name,
12779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   Label* miss) {
12789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(holder->IsGlobalObject());
12796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the number of arguments.
12819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int argc = arguments().immediate();
12829dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
12836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Get the receiver from the stack.
12846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
12856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If the object is the holder then we know that it's a global
12879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // object which can only happen for contextual calls. In this case,
12889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // the receiver cannot be a smi.
12899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (object != holder) {
12909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ JumpIfSmi(rdx, miss);
12915913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck  }
12926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the maps haven't changed.
12949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, miss);
12956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
12966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
12989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
12999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    JSFunction* function,
13009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    Label* miss) {
13019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the value from the cell.
13029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Move(rdi, Handle<JSGlobalPropertyCell>(cell));
13039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
130480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the cell contains the same function.
130644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (heap()->InNewSpace(function)) {
13079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // We can't embed a pointer to a function in new space so we have
13089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // to verify that the shared function info is unchanged. This has
13099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // the nice side effect that multiple closures based on the same
13109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // function can all use this call IC. Before we load through the
13119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // function, we have to verify that it still is a function.
13129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ JumpIfSmi(rdi, miss);
13139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
13149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ j(not_equal, miss);
131580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Check the shared function info. Make sure it hasn't changed.
13179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
13189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
13199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ j(not_equal, miss);
132080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
13219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ Cmp(rdi, Handle<JSFunction>(function));
13229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ j(not_equal, miss);
132380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
13249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
132580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
132680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13279fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::GenerateMissBranch() {
132844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_obj = isolate()->stub_cache()->ComputeCallMiss(
132944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      arguments().immediate(), kind_);
13305913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck  Object* obj;
13319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (!maybe_obj->ToObject(&obj)) return maybe_obj;
13329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
13339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return obj;
13347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
13357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
13367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
13379fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
13389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                JSObject* holder,
13399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                int index,
13409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                String* name) {
134180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ----------- S t a t e -------------
13429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rcx                 : function name
13439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[0]              : return address
13449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[8]              : argument argc
13459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[16]             : argument argc - 1
13469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ...
13479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[argc * 8]       : argument 1
13489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[(argc + 1) * 8] : argument 0 = receiver
134980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // -----------------------------------
135080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label miss;
13519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
135280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateNameCheck(name, &miss);
135380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the receiver from the stack.
13559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int argc = arguments().immediate();
13569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
135780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the receiver isn't a smi.
13599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(rdx, &miss);
136080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Do the right check and compute the holder register.
13629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register reg = CheckPrototypes(object, rdx, holder, rbx, rax, rdi,
13639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                 name, &miss);
136480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateFastPropertyLoad(masm(), rdi, reg, holder, index);
136680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the function really is a function.
13689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(rdi, &miss);
13699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx);
13709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, &miss);
13719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
13729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Patch the receiver on the stack with the global proxy if
13739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // necessary.
13749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (object->IsGlobalObject()) {
13759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
13769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
13779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
13789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
13799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Invoke the function.
13809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION);
13817f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
13829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Handle call cache miss.
138380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&miss);
138444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_result = GenerateMissBranch();
138544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (maybe_result->IsFailure()) return maybe_result;
138680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
138780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return the generated code.
13889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(FIELD, name);
138980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
13906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
13916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
13929fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
13939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    JSObject* holder,
13949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    JSGlobalPropertyCell* cell,
13959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    JSFunction* function,
13969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    String* name) {
139759151504615d929945dc59db37bf1166937748c6Steve Block  // ----------- S t a t e -------------
13989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx                 : name
139959151504615d929945dc59db37bf1166937748c6Steve Block  //  -- rsp[0]              : return address
140059151504615d929945dc59db37bf1166937748c6Steve Block  //  -- rsp[(argc - n) * 8] : arg[n] (zero-based)
140159151504615d929945dc59db37bf1166937748c6Steve Block  //  -- ...
140259151504615d929945dc59db37bf1166937748c6Steve Block  //  -- rsp[(argc + 1) * 8] : receiver
140359151504615d929945dc59db37bf1166937748c6Steve Block  // -----------------------------------
140459151504615d929945dc59db37bf1166937748c6Steve Block
14059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If object is not an array, bail out to regular call.
140644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
140759151504615d929945dc59db37bf1166937748c6Steve Block
140859151504615d929945dc59db37bf1166937748c6Steve Block  Label miss;
14099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
141059151504615d929945dc59db37bf1166937748c6Steve Block  GenerateNameCheck(name, &miss);
141159151504615d929945dc59db37bf1166937748c6Steve Block
14129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the receiver from the stack.
14139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int argc = arguments().immediate();
14149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
141559151504615d929945dc59db37bf1166937748c6Steve Block
14169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the receiver isn't a smi.
14179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(rdx, &miss);
141859151504615d929945dc59db37bf1166937748c6Steve Block
14199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  CheckPrototypes(JSObject::cast(object),
14209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                  rdx,
14219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                  holder,
14229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                  rbx,
14239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                  rax,
14249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                  rdi,
14259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                  name,
14269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                  &miss);
14279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (argc == 0) {
14299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Noop, return the length.
14309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset));
14319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ ret((argc + 1) * kPointerSize);
143259151504615d929945dc59db37bf1166937748c6Steve Block  } else {
14339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    Label call_builtin;
143459151504615d929945dc59db37bf1166937748c6Steve Block
14359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Get the elements array of the object.
14369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
143759151504615d929945dc59db37bf1166937748c6Steve Block
14389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // Check that the elements are in fast mode and writable.
14399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
144044f0eee88ff00398ff7f715fab053374d808c90dSteve Block           factory()->fixed_array_map());
14419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ j(not_equal, &call_builtin);
144259151504615d929945dc59db37bf1166937748c6Steve Block
14439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (argc == 1) {  // Otherwise fall through to call builtin.
14449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      Label exit, with_write_barrier, attempt_to_grow_elements;
144559151504615d929945dc59db37bf1166937748c6Steve Block
14469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Get the array's length into rax and calculate new length.
14479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
14489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
14499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ addl(rax, Immediate(argc));
145059151504615d929945dc59db37bf1166937748c6Steve Block
14519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Get the element's length into rcx.
14529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ SmiToInteger32(rcx, FieldOperand(rbx, FixedArray::kLengthOffset));
145359151504615d929945dc59db37bf1166937748c6Steve Block
14549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Check if we could survive without allocation.
14559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ cmpl(rax, rcx);
14569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ j(greater, &attempt_to_grow_elements);
14579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Save new length.
14599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
14609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Push the element.
14629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ movq(rcx, Operand(rsp, argc * kPointerSize));
14639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ lea(rdx, FieldOperand(rbx,
14649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                               rax, times_pointer_size,
14659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                               FixedArray::kHeaderSize - argc * kPointerSize));
14669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ movq(Operand(rdx, 0), rcx);
14679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Check if value is a smi.
14699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Integer32ToSmi(rax, rax);  // Return new length as smi.
14709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ JumpIfNotSmi(rcx, &with_write_barrier);
14729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ bind(&exit);
14749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ ret((argc + 1) * kPointerSize);
14759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ bind(&with_write_barrier);
14779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ InNewSpace(rbx, rcx, equal, &exit);
14799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ RecordWriteHelper(rbx, rdx, rcx);
14819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ ret((argc + 1) * kPointerSize);
14839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ bind(&attempt_to_grow_elements);
14859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      if (!FLAG_inline_new) {
14869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ jmp(&call_builtin);
14879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      }
14889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      ExternalReference new_space_allocation_top =
149044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          ExternalReference::new_space_allocation_top_address(isolate());
14919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      ExternalReference new_space_allocation_limit =
149244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          ExternalReference::new_space_allocation_limit_address(isolate());
14939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      const int kAllocationDelta = 4;
14959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Load top.
149644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ Load(rcx, new_space_allocation_top);
14979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
14989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Check if it's the end of elements.
14999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ lea(rdx, FieldOperand(rbx,
15009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                               rax, times_pointer_size,
15019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                               FixedArray::kHeaderSize - argc * kPointerSize));
15029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ cmpq(rdx, rcx);
15039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ j(not_equal, &call_builtin);
15049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ addq(rcx, Immediate(kAllocationDelta * kPointerSize));
150544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      Operand limit_operand =
150644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          masm()->ExternalOperand(new_space_allocation_limit);
150744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ cmpq(rcx, limit_operand);
15089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ j(above, &call_builtin);
15099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
15109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // We fit and could grow elements.
151144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ Store(new_space_allocation_top, rcx);
15129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ movq(rcx, Operand(rsp, argc * kPointerSize));
15139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
15149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Push the argument...
15159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ movq(Operand(rdx, 0), rcx);
15169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // ... and fill the rest with holes.
15179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
15189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      for (int i = 1; i < kAllocationDelta; i++) {
15199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ movq(Operand(rdx, i * kPointerSize), kScratchRegister);
15209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      }
15219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
15229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Restore receiver to rdx as finish sequence assumes it's here.
15239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
15249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
15259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Increment element's and array's sizes.
15269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ SmiAddConstant(FieldOperand(rbx, FixedArray::kLengthOffset),
15279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                        Smi::FromInt(kAllocationDelta));
15289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
15299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Make new length a smi before returning it.
15309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Integer32ToSmi(rax, rax);
15319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax);
15329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
15339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Elements are in new space, so write barrier is not required.
15349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ ret((argc + 1) * kPointerSize);
15359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    }
15369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
15379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ bind(&call_builtin);
153844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
153944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                   isolate()),
15409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                 argc + 1,
15419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                 1);
15429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
154359151504615d929945dc59db37bf1166937748c6Steve Block
154459151504615d929945dc59db37bf1166937748c6Steve Block  __ bind(&miss);
154544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_result = GenerateMissBranch();
154644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (maybe_result->IsFailure()) return maybe_result;
154759151504615d929945dc59db37bf1166937748c6Steve Block
154859151504615d929945dc59db37bf1166937748c6Steve Block  // Return the generated code.
15499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(function);
15500d5e116f6aee03185f237311a943491bb079a768Kristian Monsen}
15510d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
15520d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
15539fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
15549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   JSObject* holder,
15559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   JSGlobalPropertyCell* cell,
15569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   JSFunction* function,
15579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   String* name) {
1558f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // ----------- S t a t e -------------
15599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx                 : name
1560f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  //  -- rsp[0]              : return address
1561f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  //  -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1562f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  //  -- ...
1563f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  //  -- rsp[(argc + 1) * 8] : receiver
1564f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // -----------------------------------
1565f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
15669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If object is not an array, bail out to regular call.
156744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
1568f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
15699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss, return_undefined, call_builtin;
1570f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
1571f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  GenerateNameCheck(name, &miss);
1572f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
15739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the receiver from the stack.
15749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int argc = arguments().immediate();
15759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1576f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
15779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the receiver isn't a smi.
15789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(rdx, &miss);
1579f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
15809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  CheckPrototypes(JSObject::cast(object), rdx,
15819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                  holder, rbx,
15829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                  rax, rdi, name, &miss);
1583f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
15849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the elements array of the object.
15859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
1586f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
15879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the elements are in fast mode and writable.
15889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
15899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                 Heap::kFixedArrayMapRootIndex);
15909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, &call_builtin);
1591f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
15929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the array's length into rcx and calculate new length.
15939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
15949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ subl(rcx, Immediate(1));
15959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(negative, &return_undefined);
1596f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
15979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the last element.
15989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ LoadRoot(r9, Heap::kTheHoleValueRootIndex);
15999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rax, FieldOperand(rbx,
16009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                            rcx, times_pointer_size,
16019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                            FixedArray::kHeaderSize));
16029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check if element is already the hole.
16039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ cmpq(rax, r9);
16049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If so, call slow-case to also check prototypes for value.
16059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(equal, &call_builtin);
1606f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
16079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Set the array's length.
16089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
1609f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
16109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Fill with the hole and return original value.
16119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(FieldOperand(rbx,
16129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                       rcx, times_pointer_size,
16139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                       FixedArray::kHeaderSize),
16149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block          r9);
16159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret((argc + 1) * kPointerSize);
1616f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
16179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&return_undefined);
16189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
16199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret((argc + 1) * kPointerSize);
1620f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
16219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&call_builtin);
162244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ TailCallExternalReference(
162344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference(Builtins::c_ArrayPop, isolate()),
162444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      argc + 1,
162544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      1);
1626f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
1627f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  __ bind(&miss);
162844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_result = GenerateMissBranch();
162944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (maybe_result->IsFailure()) return maybe_result;
1630f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
1631f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // Return the generated code.
16329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(function);
1633f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
1634f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
1635f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
16369fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
16379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    Object* object,
16389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSObject* holder,
16399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSGlobalPropertyCell* cell,
16409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSFunction* function,
16419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    String* name) {
1642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
16439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx                 : function name
16449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0]              : return address
16459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[(argc - n) * 8] : arg[n] (zero-based)
16469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- ...
16479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[(argc + 1) * 8] : receiver
1648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If object is not a string, bail out to regular call.
165144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (!object->IsString() || cell != NULL) return heap()->undefined_value();
16529dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
1653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int argc = arguments().immediate();
1654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
1656b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  Label name_miss;
16579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label index_out_of_range;
1658b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  Label* index_out_of_range_label = &index_out_of_range;
1659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1660b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
1661b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    index_out_of_range_label = &miss;
1662b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  }
1663b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1664b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  GenerateNameCheck(name, &name_miss);
1665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the maps starting from the prototype haven't changed.
16679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateDirectLoadGlobalFunctionPrototype(masm(),
16689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                            Context::STRING_FUNCTION_INDEX,
16699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                            rax,
16709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                            &miss);
16719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(object != holder);
16729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
16739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                  rbx, rdx, rdi, name, &miss);
1674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register receiver = rbx;
16769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register index = rdi;
16779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register scratch = rdx;
16789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register result = rax;
16799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
16809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (argc > 0) {
16819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
16829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  } else {
16839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
16849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
1685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  StringCharCodeAtGenerator char_code_at_generator(receiver,
16879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   index,
16889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   scratch,
16899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   result,
16909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   &miss,  // When not a string.
16919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   &miss,  // When not a number.
1692b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                                   index_out_of_range_label,
16939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   STRING_INDEX_IS_NUMBER);
16949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  char_code_at_generator.GenerateFast(masm());
16959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret((argc + 1) * kPointerSize);
1696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  StubRuntimeCallHelper call_helper;
16989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  char_code_at_generator.GenerateSlow(masm(), call_helper);
1699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1700b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  if (index_out_of_range.is_linked()) {
1701b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    __ bind(&index_out_of_range);
1702b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    __ LoadRoot(rax, Heap::kNanValueRootIndex);
1703b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    __ ret((argc + 1) * kPointerSize);
1704b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  }
1705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
1707b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  // Restore function name in rcx.
1708b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  __ Move(rcx, Handle<String>(name));
1709b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  __ bind(&name_miss);
171044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_result = GenerateMissBranch();
171144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (maybe_result->IsFailure()) return maybe_result;
1712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
17149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(function);
1715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
17189fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileStringCharAtCall(
17199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    Object* object,
17209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSObject* holder,
17219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSGlobalPropertyCell* cell,
17229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSFunction* function,
17239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    String* name) {
1724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
17259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx                 : function name
17269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0]              : return address
17279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[(argc - n) * 8] : arg[n] (zero-based)
17289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- ...
17299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[(argc + 1) * 8] : receiver
173059151504615d929945dc59db37bf1166937748c6Steve Block  // -----------------------------------
173159151504615d929945dc59db37bf1166937748c6Steve Block
17329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If object is not a string, bail out to regular call.
173344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (!object->IsString() || cell != NULL) return heap()->undefined_value();
17349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
17359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int argc = arguments().immediate();
173659151504615d929945dc59db37bf1166937748c6Steve Block
1737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
1738b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  Label name_miss;
17399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label index_out_of_range;
1740b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  Label* index_out_of_range_label = &index_out_of_range;
1741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1742b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
1743b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    index_out_of_range_label = &miss;
1744b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  }
1745b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1746b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  GenerateNameCheck(name, &name_miss);
17479dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
17489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the maps starting from the prototype haven't changed.
17499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateDirectLoadGlobalFunctionPrototype(masm(),
17509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                            Context::STRING_FUNCTION_INDEX,
17519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                            rax,
17529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                            &miss);
17539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(object != holder);
17549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
17559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                  rbx, rdx, rdi, name, &miss);
1756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
17579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register receiver = rax;
17589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register index = rdi;
17599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register scratch1 = rbx;
17609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register scratch2 = rdx;
17619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register result = rax;
17629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
17639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (argc > 0) {
17649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
17659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  } else {
17669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
17699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  StringCharAtGenerator char_at_generator(receiver,
17709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                          index,
17719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                          scratch1,
17729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                          scratch2,
17739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                          result,
17749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                          &miss,  // When not a string.
17759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                          &miss,  // When not a number.
1776b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                          index_out_of_range_label,
17779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                          STRING_INDEX_IS_NUMBER);
17789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  char_at_generator.GenerateFast(masm());
17799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret((argc + 1) * kPointerSize);
17809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
17819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  StubRuntimeCallHelper call_helper;
17829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  char_at_generator.GenerateSlow(masm(), call_helper);
1783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1784b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  if (index_out_of_range.is_linked()) {
1785b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    __ bind(&index_out_of_range);
1786b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
1787b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    __ ret((argc + 1) * kPointerSize);
1788b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  }
1789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
1791b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  // Restore function name in rcx.
1792b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  __ Move(rcx, Handle<String>(name));
1793b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  __ bind(&name_miss);
179444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_result = GenerateMissBranch();
179544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (maybe_result->IsFailure()) return maybe_result;
1796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
17989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(function);
1799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18029fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
18039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    Object* object,
18049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSObject* holder,
18059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSGlobalPropertyCell* cell,
18069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSFunction* function,
18079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    String* name) {
1808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
18099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx                 : function name
18109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0]              : return address
18119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[(argc - n) * 8] : arg[n] (zero-based)
18129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- ...
18139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[(argc + 1) * 8] : receiver
1814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int argc = arguments().immediate();
1817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If the object is not a JSObject or we got an unexpected number of
18199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // arguments, bail out to the regular call.
182044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
1821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
18239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateNameCheck(name, &miss);
1824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (cell == NULL) {
18269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(rdx, Operand(rsp, 2 * kPointerSize));
1827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ JumpIfSmi(rdx, &miss);
1829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    CheckPrototypes(JSObject::cast(object), rdx, holder, rbx, rax, rdi, name,
18319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                    &miss);
18329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  } else {
18339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    ASSERT(cell->value() == function);
18349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
18359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    GenerateLoadFunctionFromCell(cell, function, &miss);
18369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
1837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Load the char code argument.
18399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Register code = rbx;
18409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(code, Operand(rsp, 1 * kPointerSize));
18416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check the code is a smi.
18439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label slow;
18449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfNotSmi(code, &slow);
18456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Convert the smi code to uint16.
18479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ SmiAndConstant(code, code, Smi::FromInt(0xffff));
18486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  StringCharFromCodeGenerator char_from_code_generator(code, rax);
18509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  char_from_code_generator.GenerateFast(masm());
18519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret(2 * kPointerSize);
18526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  StubRuntimeCallHelper call_helper;
18549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  char_from_code_generator.GenerateSlow(masm(), call_helper);
18559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
18569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Tail call the full function. We do not have to patch the receiver
18579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // because the function makes no use of it.
18589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&slow);
18599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
18606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&miss);
18629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rcx: function name.
186344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_result = GenerateMissBranch();
186444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (maybe_result->IsFailure()) return maybe_result;
18656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Return the generated code.
18679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
18686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
18696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18719fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
18729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    JSObject* holder,
18739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    JSGlobalPropertyCell* cell,
18749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    JSFunction* function,
18759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                    String* name) {
18769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // TODO(872): implement this.
187744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return heap()->undefined_value();
1878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18819fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
18829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                  JSObject* holder,
18839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                  JSGlobalPropertyCell* cell,
18849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                  JSFunction* function,
18859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                  String* name) {
1886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
18879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx                 : function name
18889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0]              : return address
18899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[(argc - n) * 8] : arg[n] (zero-based)
18909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- ...
18919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[(argc + 1) * 8] : receiver
1892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
18939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
18949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int argc = arguments().immediate();
18959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
18969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If the object is not a JSObject or we got an unexpected number of
18979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // arguments, bail out to the regular call.
189844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
18999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
1900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
19019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateNameCheck(name, &miss);
1902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (cell == NULL) {
19049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(rdx, Operand(rsp, 2 * kPointerSize));
1905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ JumpIfSmi(rdx, &miss);
1907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    CheckPrototypes(JSObject::cast(object), rdx, holder, rbx, rax, rdi, name,
19099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                    &miss);
19109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  } else {
19119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    ASSERT(cell->value() == function);
19129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
19139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    GenerateLoadFunctionFromCell(cell, function, &miss);
19149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
1915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Load the (only) argument into rax.
19179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rax, Operand(rsp, 1 * kPointerSize));
1918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check if the argument is a smi.
19209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label not_smi;
19219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  STATIC_ASSERT(kSmiTag == 0);
19229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfNotSmi(rax, &not_smi);
19239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ SmiToInteger32(rax, rax);
1924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
19269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // otherwise.
19279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movl(rbx, rax);
19289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ sarl(rbx, Immediate(kBitsPerInt - 1));
1929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Do bitwise not or do nothing depending on ebx.
19319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ xorl(rax, rbx);
1932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Add 1 or do nothing depending on ebx.
19349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ subl(rax, rbx);
19359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
19369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If the result is still negative, go to the slow case.
19379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // This only happens for the most negative smi.
19389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label slow;
19399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(negative, &slow);
19409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
19419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Smi case done.
19429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Integer32ToSmi(rax, rax);
19439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret(2 * kPointerSize);
19449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
19459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check if the argument is a heap number and load its value.
19469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&not_smi);
194744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ CheckMap(rax, factory()->heap_number_map(), &slow, true);
19489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
1949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check the sign of the argument. If the argument is positive,
19519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // just return it.
19529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label negative_sign;
19539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int sign_mask_shift =
19549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      (HeapNumber::kExponentOffset - HeapNumber::kValueOffset) * kBitsPerByte;
19559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift,
19569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block          RelocInfo::NONE);
19579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ testq(rbx, rdi);
19589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_zero, &negative_sign);
19599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret(2 * kPointerSize);
1960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If the argument is negative, clear the sign, and return a new
19629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // number. We still have the sign mask in rdi.
19639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&negative_sign);
19649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ xor_(rbx, rdi);
19659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ AllocateHeapNumber(rax, rdx, &slow);
19669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rbx);
19679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret(2 * kPointerSize);
1968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Tail call the full function. We do not have to patch the receiver
19709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // because the function makes no use of it.
19719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&slow);
19729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
19759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rcx: function name.
197644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_result = GenerateMissBranch();
197744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (maybe_result->IsFailure()) return maybe_result;
1978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
19809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
1981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
198444f0eee88ff00398ff7f715fab053374d808c90dSteve BlockMaybeObject* CallStubCompiler::CompileFastApiCall(
198544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    const CallOptimization& optimization,
198644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Object* object,
198744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    JSObject* holder,
198844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    JSGlobalPropertyCell* cell,
198944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    JSFunction* function,
199044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    String* name) {
199144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(optimization.is_simple_api_call());
199244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Bail out if object is a global object as we don't want to
199344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // repatch it to global receiver.
199444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (object->IsGlobalObject()) return heap()->undefined_value();
199544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (cell != NULL) return heap()->undefined_value();
199644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int depth = optimization.GetPrototypeDepthOfExpectedType(
199744f0eee88ff00398ff7f715fab053374d808c90dSteve Block            JSObject::cast(object), holder);
199844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (depth == kInvalidProtoDepth) return heap()->undefined_value();
199944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
200044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Label miss, miss_before_stack_reserved;
200144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
200244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  GenerateNameCheck(name, &miss_before_stack_reserved);
200344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
200444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Get the receiver from the stack.
200544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int argc = arguments().immediate();
200644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
200744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
200844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Check that the receiver isn't a smi.
200944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ JumpIfSmi(rdx, &miss_before_stack_reserved);
201044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
201144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
201244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->call_const(), 1);
201344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->call_const_fast_api(), 1);
201444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
201544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Allocate space for v8::Arguments implicit values. Must be initialized
201644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // before calling any runtime function.
201744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
201844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
201944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Check that the maps haven't changed and find a Holder as a side effect.
202044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CheckPrototypes(JSObject::cast(object), rdx, holder,
202144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                  rbx, rax, rdi, name, depth, &miss);
202244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
202344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Move the return address on top of the stack.
202444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rax, Operand(rsp, 3 * kPointerSize));
202544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(Operand(rsp, 0 * kPointerSize), rax);
202644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
202744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
202844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (result->IsFailure()) return result;
202944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
203044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ bind(&miss);
203144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
203244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
203344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ bind(&miss_before_stack_reserved);
203444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_result = GenerateMissBranch();
203544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (maybe_result->IsFailure()) return maybe_result;
203644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
203744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Return the generated code.
203844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return GetCode(function);
203944f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
204044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
204144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
20429fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
20439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   JSObject* holder,
20449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   JSFunction* function,
20459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   String* name,
20469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   CheckType check) {
2047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
20489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rcx                 : function name
20499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[0]              : return address
20509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[8]              : argument argc
20519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[16]             : argument argc - 1
20529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ...
20539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[argc * 8]       : argument 1
20549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[(argc + 1) * 8] : argument 0 = receiver
2055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
205744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (HasCustomCallGenerator(function)) {
20589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    MaybeObject* maybe_result = CompileCustomCall(
205944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        object, holder, NULL, function, name);
20609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    Object* result;
20619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (!maybe_result->ToObject(&result)) return maybe_result;
20629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // undefined means bail out to regular compiler.
20639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (!result->IsUndefined()) return result;
20640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  }
2065e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
206644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Label miss;
2067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
206844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  GenerateNameCheck(name, &miss);
2069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
20709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the receiver from the stack.
20719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int argc = arguments().immediate();
20729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
20749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the receiver isn't a smi.
20759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (check != NUMBER_CHECK) {
207644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ JumpIfSmi(rdx, &miss);
20779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
2078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
20799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Make sure that it's okay not to patch the on stack receiver
20809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // unless we're doing a receiver map check.
20819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
208344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
208444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SharedFunctionInfo* function_info = function->shared();
20859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  switch (check) {
20869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    case RECEIVER_MAP_CHECK:
208744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ IncrementCounter(counters->call_const(), 1);
2088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
20899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Check that the maps haven't changed.
20909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      CheckPrototypes(JSObject::cast(object), rdx, holder,
209144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                      rbx, rax, rdi, name, &miss);
2092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
20939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // Patch the receiver on the stack with the global proxy if
20949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      // necessary.
20959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      if (object->IsGlobalObject()) {
20969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
20979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
20989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      }
20999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      break;
2100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
21019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    case STRING_CHECK:
2102e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      if (!function->IsBuiltin() && !function_info->strict_mode()) {
2103e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        // Calling non-strict non-builtins with a value as the receiver
2104e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        // requires boxing.
21059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ jmp(&miss);
21069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      } else {
21079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        // Check that the object is a two-byte string or a symbol.
21089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
21099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ j(above_equal, &miss);
21109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        // Check that the maps starting from the prototype haven't changed.
21119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        GenerateDirectLoadGlobalFunctionPrototype(
21129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block            masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
21139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
21149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                        rbx, rdx, rdi, name, &miss);
21159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      }
21169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      break;
2117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
21189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    case NUMBER_CHECK: {
2119e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      if (!function->IsBuiltin() && !function_info->strict_mode()) {
2120e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        // Calling non-strict non-builtins with a value as the receiver
2121e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        // requires boxing.
21229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ jmp(&miss);
21239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      } else {
21249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        Label fast;
21259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        // Check that the object is a smi or a heap number.
21269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ JumpIfSmi(rdx, &fast);
21279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
21289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ j(not_equal, &miss);
21299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ bind(&fast);
21309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        // Check that the maps starting from the prototype haven't changed.
21319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        GenerateDirectLoadGlobalFunctionPrototype(
21329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block            masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
21339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
21349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                        rbx, rdx, rdi, name, &miss);
21359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      }
21369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      break;
21379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    }
2138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
21399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    case BOOLEAN_CHECK: {
2140e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      if (!function->IsBuiltin() && !function_info->strict_mode()) {
2141e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        // Calling non-strict non-builtins with a value as the receiver
2142e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        // requires boxing.
21439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ jmp(&miss);
21449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      } else {
21459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        Label fast;
21469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        // Check that the object is a boolean.
21479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
21489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ j(equal, &fast);
21499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
21509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ j(not_equal, &miss);
21519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        __ bind(&fast);
21529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        // Check that the maps starting from the prototype haven't changed.
21539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        GenerateDirectLoadGlobalFunctionPrototype(
21549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block            masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
21559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
21569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                        rbx, rdx, rdi, name, &miss);
21579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      }
21589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      break;
21599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    }
2160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
21619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    default:
21629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      UNREACHABLE();
21639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
2164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
216544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
2166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
21679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Handle call cache miss.
2168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
216944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_result = GenerateMissBranch();
217044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (maybe_result->IsFailure()) return maybe_result;
2171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
21739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(function);
2174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
21779fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
21789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                      JSObject* holder,
21799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                      String* name) {
2180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
21819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rcx                 : function name
21829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[0]              : return address
21839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[8]              : argument argc
21849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[16]             : argument argc - 1
21859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ...
21869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[argc * 8]       : argument 1
21879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[(argc + 1) * 8] : argument 0 = receiver
2188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
21919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateNameCheck(name, &miss);
2192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
21939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the number of arguments.
21949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int argc = arguments().immediate();
2195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LookupResult lookup;
2197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LookupPostInterceptor(holder, name, &lookup);
21989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
21999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the receiver from the stack.
22009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
22019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
22029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  CallInterceptorCompiler compiler(this, arguments(), rcx);
22031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  MaybeObject* result = compiler.Compile(masm(),
22041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         object,
22051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         holder,
22061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         name,
22071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         &lookup,
22081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         rdx,
22091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         rbx,
22101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         rdi,
22111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         rax,
22121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         &miss);
22131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (result->IsFailure()) return result;
22149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
22159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Restore receiver.
22169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
22179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
22189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the function really is a function.
22199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(rax, &miss);
22209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
22219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, &miss);
22229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
22239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Patch the receiver on the stack with the global proxy if
22249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // necessary.
22259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (object->IsGlobalObject()) {
22269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
22279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
22289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
22299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
22309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Invoke the function.
22319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rdi, rax);
22329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION);
22339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
22349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Handle load cache miss.
2235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
223644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_result = GenerateMissBranch();
223744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (maybe_result->IsFailure()) return maybe_result;
2238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(INTERCEPTOR, name);
2241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
22449fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
22459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 GlobalObject* holder,
22469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 JSGlobalPropertyCell* cell,
22479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 JSFunction* function,
22489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 String* name) {
2249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
22509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rcx                 : function name
22519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[0]              : return address
22529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[8]              : argument argc
22539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[16]             : argument argc - 1
22549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ...
22559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[argc * 8]       : argument 1
22569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // rsp[(argc + 1) * 8] : argument 0 = receiver
2257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
22589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
225944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (HasCustomCallGenerator(function)) {
22609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    MaybeObject* maybe_result = CompileCustomCall(
226144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        object, holder, cell, function, name);
22629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    Object* result;
22639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (!maybe_result->ToObject(&result)) return maybe_result;
22649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    // undefined means bail out to regular compiler.
22659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (!result->IsUndefined()) return result;
22669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
22679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
2268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
22709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateNameCheck(name, &miss);
2271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
22729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the number of arguments.
22739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  const int argc = arguments().immediate();
2274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
22759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateGlobalReceiverCheck(object, holder, name, &miss);
22769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
22779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadFunctionFromCell(cell, function, &miss);
22789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
22799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Patch the receiver on the stack with the global proxy.
22809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (object->IsGlobalObject()) {
22819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
22829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
22839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
22849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
2285b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  // Setup the context (function already in rdi).
22869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
22879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
22889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Jump to the cached code (tail call).
228944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
229044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->call_global_inline(), 1);
22919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ASSERT(function->is_compiled());
22929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ParameterCount expected(function->shared()->formal_parameter_count());
2293b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  if (V8::UseCrankshaft()) {
2294b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    // TODO(kasperl): For now, we always call indirectly through the
2295b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    // code field in the function to allow recompilation to take effect
2296b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    // without changing any of the call sites.
2297b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
2298b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION);
2299b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  } else {
2300b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    Handle<Code> code(function->code());
2301b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    __ InvokeCode(code, expected, arguments(),
2302b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                  RelocInfo::CODE_TARGET, JUMP_FUNCTION);
2303b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  }
23049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Handle call cache miss.
2305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
230644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->call_global_inline_miss(), 1);
230744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MaybeObject* maybe_result = GenerateMissBranch();
230844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (maybe_result->IsFailure()) return maybe_result;
2309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
23119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(NORMAL, name);
2312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
23159fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
23169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                  int index,
23179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                  Map* transition,
23189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                  String* name) {
2319b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ----------- S t a t e -------------
23209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : value
23219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx    : name
2322b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //  -- rdx    : receiver
23239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0] : return address
2324b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // -----------------------------------
2325b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label miss;
2326b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
23279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Generate store field code.  Preserves receiver and name on jump to miss.
23289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateStoreField(masm(),
23299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                     object,
23309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                     index,
23319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                     transition,
23329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                     rdx, rcx, rbx,
23339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                     &miss);
2334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
23359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Handle store cache miss.
2336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&miss);
233744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
23389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Jump(ic, RelocInfo::CODE_TARGET);
2339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Return the generated code.
23419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2344b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
23455913587db4c6bab03d97bfe44b06289fd6d7270dJohn ReckMaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
23465913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck                                                     AccessorInfo* callback,
23475913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck                                                     String* name) {
2348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rax    : value
2350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rcx    : name
23514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- rdx    : receiver
2352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rsp[0] : return address
2353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
23574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ JumpIfSmi(rdx, &miss);
2358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the map of the object hasn't changed.
23604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Handle<Map>(object->map()));
2362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss);
2363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform global security token check if needed.
2365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (object->IsJSGlobalProxy()) {
23664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ CheckAccessGlobalProxy(rdx, rbx, &miss);
2367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Stub never generated for non-global objects that require access
2370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // checks.
2371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rbx);  // remove the return address
23749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(rdx);  // receiver
23759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Push(Handle<AccessorInfo>(callback));  // callback info
23769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(rcx);  // name
23779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(rax);  // value
23789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ push(rbx);  // restore return address
23799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
23809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Do tail-call to the runtime system.
23819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  ExternalReference store_callback_property =
238244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
23839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ TailCallExternalReference(store_callback_property, 4, 1);
2384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle store cache miss.
2386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
238744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(ic, RelocInfo::CODE_TARGET);
2389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
23919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(CALLBACKS, name);
2392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
23955913587db4c6bab03d97bfe44b06289fd6d7270dJohn ReckMaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
23965913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck                                                        String* name) {
2397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rax    : value
2399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rcx    : name
24004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- rdx    : receiver
2401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rsp[0] : return address
2402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
24064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ JumpIfSmi(rdx, &miss);
2407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the map of the object hasn't changed.
24094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Handle<Map>(receiver->map()));
2411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss);
2412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform global security token check if needed.
2414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (receiver->IsJSGlobalProxy()) {
24154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ CheckAccessGlobalProxy(rdx, rbx, &miss);
2416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Stub never generated for non-global objects that require access
2419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // checks.
2420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rbx);  // remove the return address
24234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ push(rdx);  // receiver
2424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rcx);  // name
2425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rax);  // value
2426e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Push(Smi::FromInt(strict_mode_));
2427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rbx);  // restore return address
2428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to the runtime system.
2430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference store_ic_property =
243144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
2432e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ TailCallExternalReference(store_ic_property, 4, 1);
2433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle store cache miss.
2435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
243644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(ic, RelocInfo::CODE_TARGET);
2438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(INTERCEPTOR, name);
2441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
24445913587db4c6bab03d97bfe44b06289fd6d7270dJohn ReckMaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
24455913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck                                                   JSGlobalPropertyCell* cell,
24465913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck                                                   String* name) {
2447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rax    : value
2449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rcx    : name
24504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- rdx    : receiver
2451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rsp[0] : return address
2452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the map of the global has not changed.
24564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Handle<Map>(object->map()));
2458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss);
2459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
24601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Check that the value in the cell is not the hole. If it is, this
24611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // cell could have been deleted and reintroducing the global needs
24621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // to update the property details in the property dictionary of the
24631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // global object. We bail out to the runtime system to do that.
24641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ Move(rbx, Handle<JSGlobalPropertyCell>(cell));
24651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CompareRoot(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
24661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                 Heap::kTheHoleValueRootIndex);
24671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ j(equal, &miss);
24681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Store the value in the cell.
24701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), rax);
2471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the value (register rax).
247344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
247444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->named_store_global_inline(), 1);
2475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
2476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle store cache miss.
2478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
247944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
248044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(ic, RelocInfo::CODE_TARGET);
2482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(NORMAL, name);
2485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
24885913587db4c6bab03d97bfe44b06289fd6d7270dJohn ReckMaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
24895913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck                                                       int index,
24905913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck                                                       Map* transition,
24915913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck                                                       String* name) {
2492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rax     : value
2494f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  //  -- rcx     : key
2495f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  //  -- rdx     : receiver
2496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rsp[0]  : return address
2497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
250044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
250144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->keyed_store_field(), 1);
2502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the name has not changed.
2504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Cmp(rcx, Handle<String>(name));
2505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss);
2506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2507402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Generate store field code.  Preserves receiver and name on jump to miss.
2508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateStoreField(masm(),
2509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     object,
2510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     index,
2511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     transition,
2512402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                     rdx, rcx, rbx,
2513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     &miss);
2514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle store cache miss.
2516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
251744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ DecrementCounter(counters->keyed_store_field(), 1);
251844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
2519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(ic, RelocInfo::CODE_TARGET);
2520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2526b0fe1620dcb4135ac3ab2d66ff93072373911299Ben MurdochMaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
2527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    JSObject* receiver) {
2528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ----------- S t a t e -------------
2529b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //  -- rax    : value
2530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //  -- rcx    : key
2531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //  -- rdx    : receiver
2532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //  -- rsp[0] : return address
2533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // -----------------------------------
2534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label miss;
2535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Check that the receiver isn't a smi.
2537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ JumpIfSmi(rdx, &miss);
2538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Check that the map matches.
2540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch         Handle<Map>(receiver->map()));
2542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_equal, &miss);
2543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Check that the key is a smi.
2545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ JumpIfNotSmi(rcx, &miss);
2546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get the elements array and make sure it is a fast element array, not 'cow'.
2548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
2549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
255044f0eee88ff00398ff7f715fab053374d808c90dSteve Block         factory()->fixed_array_map());
2551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_equal, &miss);
2552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Check that the key is within bounds.
2554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (receiver->IsJSArray()) {
2555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
2556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ j(above_equal, &miss);
2557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
2558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
2559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ j(above_equal, &miss);
2560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Do the store and update the write barrier. Make sure to preserve
2563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // the value in register eax.
2564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(rdx, rax);
2565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiToInteger32(rcx, rcx);
2566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
2567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          rax);
2568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ RecordWrite(rdi, 0, rdx, rcx);
2569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Done.
2571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(0);
2572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Handle store cache miss.
2574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&miss);
257544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
2576e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ jmp(ic, RelocInfo::CODE_TARGET);
2577e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
2578e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Return the generated code.
2579e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return GetCode(NORMAL, NULL);
2580e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
2581e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
2582e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
25839fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
25849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                      JSObject* object,
25859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                      JSObject* last) {
25869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
25879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : receiver
25889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx    : name
25899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0] : return address
25909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
25919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
25927f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
25939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Chech that receiver is not a smi.
25949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(rax, &miss);
25957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
25969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check the maps of the full prototype chain. Also check that
25979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // global property cells up to (but not including) the last object
25989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // in the prototype chain are empty.
25999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  CheckPrototypes(object, rax, last, rbx, rdx, rdi, name, &miss);
26009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If the last object in the prototype chain is a global object,
26029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // check that the global property cell is empty.
26039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (last->IsGlobalObject()) {
26049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    MaybeObject* cell = GenerateCheckPropertyCell(masm(),
26059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                  GlobalObject::cast(last),
26069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                  name,
26079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                  rdx,
26089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                  &miss);
26099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    if (cell->IsFailure()) {
26109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      miss.Unuse();
26119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      return cell;
26127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    }
26137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  }
26147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
26159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return undefined if maps of the full prototype chain are still the
26169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // same and no global property with this name contains a value.
26179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
26189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret(0);
26199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
26219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
26229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
262444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return GetCode(NONEXISTENT, heap()->empty_string());
26259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
26269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26289fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object,
26299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                JSObject* holder,
26309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                int index,
26319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                String* name) {
26329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
26339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : receiver
26349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx    : name
26359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0] : return address
26369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
26379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
26389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadField(object, holder, rax, rbx, rdx, rdi, index, name, &miss);
26409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
26419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
26429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
26449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(FIELD, name);
26459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
26469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26489fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
26499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   JSObject* object,
26509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   JSObject* holder,
26519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   AccessorInfo* callback) {
26529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
26539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : receiver
26549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx    : name
26559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0] : return address
26569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
26579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
26589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  MaybeObject* result = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx,
26601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                             rdi, callback, name, &miss);
26611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (result->IsFailure()) {
26629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    miss.Unuse();
26631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    return result;
26649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
26659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
26679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
26689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
26709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(CALLBACKS, name);
26719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
26729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26749fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
26759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   JSObject* holder,
26769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   Object* value,
26779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                   String* name) {
26789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
26799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : receiver
26809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx    : name
26819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0] : return address
26829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
26839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
26849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss);
26869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
26879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
26889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
26909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(CONSTANT_FUNCTION, name);
26919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
26929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
26949fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
26959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                      JSObject* holder,
26969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                      String* name) {
26979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
26989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : receiver
26999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx    : name
27009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0] : return address
27019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
27029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
27039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
27049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  LookupResult lookup;
27059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  LookupPostInterceptor(holder, name, &lookup);
27069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
27079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // TODO(368): Compile in the whole chain: all the interceptors in
27089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // prototypes and ultimate answer.
27099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadInterceptor(receiver,
27109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          holder,
27119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          &lookup,
27129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          rax,
27139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          rcx,
27149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          rdx,
27159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          rbx,
27169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          rdi,
27179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          name,
27189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          &miss);
27199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
27209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
27219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
27229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
27239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
27249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(INTERCEPTOR, name);
27259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
27269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
27279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
27289fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
27299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 GlobalObject* holder,
27309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 JSGlobalPropertyCell* cell,
27319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 String* name,
27329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                 bool is_dont_delete) {
27339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
27349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : receiver
27359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rcx    : name
27369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0] : return address
27379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
27389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
27399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
27409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // If the object is the holder then we know that it's a global
27419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // object which can only happen for contextual loads. In this case,
27429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // the receiver cannot be a smi.
27439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (object != holder) {
27449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ JumpIfSmi(rax, &miss);
27459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
27469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
27479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the maps haven't changed.
27489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  CheckPrototypes(object, rax, holder, rbx, rdx, rdi, name, &miss);
27499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
27509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the value from the cell.
27519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Move(rbx, Handle<JSGlobalPropertyCell>(cell));
27529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset));
27539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
27549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check for deleted property if property can actually be deleted.
27559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  if (!is_dont_delete) {
27569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
27579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ j(equal, &miss);
27589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  } else if (FLAG_debug_code) {
27599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
27609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    __ Check(not_equal, "DontDelete cells can't contain the hole");
27619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
27629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
276344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
276444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->named_load_global_stub(), 1);
27659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rax, rbx);
27669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ ret(0);
27679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
27689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
276944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->named_load_global_stub_miss(), 1);
27709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
27717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
27729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
27739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(NORMAL, name);
27749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
27757f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
27767f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
27779fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
27789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                     JSObject* receiver,
27799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                     JSObject* holder,
27809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                     int index) {
27819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
27829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax     : key
27839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rdx     : receiver
27849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0]  : return address
27859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
27869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
27877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
278844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
278944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->keyed_load_field(), 1);
27907f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
27919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the name has not changed.
27929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Cmp(rax, Handle<String>(name));
27939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, &miss);
27947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
27959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss);
27967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
27979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
279844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ DecrementCounter(counters->keyed_load_field(), 1);
27999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
28007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
28019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
28029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(FIELD, name);
28039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
28047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
28057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
28069fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
28079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    String* name,
28089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSObject* receiver,
28099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    JSObject* holder,
28109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    AccessorInfo* callback) {
28119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
28129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax     : key
28139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rdx     : receiver
28149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0]  : return address
28159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
28169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
28177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
281844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
281944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->keyed_load_callback(), 1);
2820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the name has not changed.
28229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Cmp(rax, Handle<String>(name));
28239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, &miss);
2824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  MaybeObject* result = GenerateLoadCallback(receiver, holder, rdx, rax, rbx,
28261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                             rcx, rdi, callback, name, &miss);
28271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (result->IsFailure()) {
28289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block    miss.Unuse();
28291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    return result;
28309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  }
2831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
2833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
283444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ DecrementCounter(counters->keyed_load_callback(), 1);
28359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2836bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch
28379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
28389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(CALLBACKS, name);
28399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
28408a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
2841bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch
28429fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
28439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                        JSObject* receiver,
28449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                        JSObject* holder,
28459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                        Object* value) {
28469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
28479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : key
28489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rdx    : receiver
28499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0]  : return address
28509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
28519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
2852bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch
285344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
285444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->keyed_load_constant_function(), 1);
2855bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch
28569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the name has not changed.
28579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Cmp(rax, Handle<String>(name));
28589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, &miss);
28598a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
28609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadConstant(receiver, holder, rdx, rbx, rcx, rdi,
28619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                       value, name, &miss);
28629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
286344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ DecrementCounter(counters->keyed_load_constant_function(), 1);
28649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
28658a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
28669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
28679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(CONSTANT_FUNCTION, name);
28689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
28698a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
28708a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
28719fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
28729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                           JSObject* holder,
28739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                                           String* name) {
28749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
28759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : key
28769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rdx    : receiver
28779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0]  : return address
28789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
28799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
28808a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
288144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
288244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->keyed_load_interceptor(), 1);
28838a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
28849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the name has not changed.
28859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Cmp(rax, Handle<String>(name));
28869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, &miss);
28879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
28889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  LookupResult lookup;
28899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  LookupPostInterceptor(holder, name, &lookup);
28909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadInterceptor(receiver,
28919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          holder,
28929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          &lookup,
28939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          rdx,
28949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          rax,
28959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          rcx,
28969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          rbx,
28979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          rdi,
28989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          name,
28999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                          &miss);
29009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
290144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ DecrementCounter(counters->keyed_load_interceptor(), 1);
29029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
29039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
29049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
29059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(INTERCEPTOR, name);
2906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
29099fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
29109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
29119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : key
29129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rdx    : receiver
29139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0]  : return address
29149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
29159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
29163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
291744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
291844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->keyed_load_array_length(), 1);
29193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
29209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the name has not changed.
29219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Cmp(rax, Handle<String>(name));
29229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, &miss);
29233bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
29249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadArrayLength(masm(), rdx, rcx, &miss);
29259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
292644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ DecrementCounter(counters->keyed_load_array_length(), 1);
29279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
29283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
29299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
29309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(CALLBACKS, name);
29319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
29323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
29333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
29349fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
29359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
29369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : key
29379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rdx    : receiver
29389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0] : return address
29399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
29409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
29413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
294244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
294344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->keyed_load_string_length(), 1);
29443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
29459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the name has not changed.
29469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Cmp(rax, Handle<String>(name));
29479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, &miss);
29483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
29491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true);
29509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
295144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ DecrementCounter(counters->keyed_load_string_length(), 1);
29529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
29533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
29549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
29559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(CALLBACKS, name);
29569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
29573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
29583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
29599fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
29609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
29619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : key
29629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rdx    : receiver
29639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rsp[0]  : return address
29649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
29659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
29663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
296744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
296844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->keyed_load_function_prototype(), 1);
2969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
29709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the name has not changed.
29719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Cmp(rax, Handle<String>(name));
29729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, &miss);
2973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
29749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss);
29759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
297644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ DecrementCounter(counters->keyed_load_function_prototype(), 1);
29779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
29789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
29799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
29809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(CALLBACKS, name);
2981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
29849fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
29859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // ----------- S t a t e -------------
29869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rax    : key
29879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  //  -- rdx    : receiver
298844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  //  -- rsp[0] : return address
29899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // -----------------------------------
29909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  Label miss;
2991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
29929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the receiver isn't a smi.
29939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfSmi(rdx, &miss);
2994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
29959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the map matches.
29969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
29979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block         Handle<Map>(receiver->map()));
29989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(not_equal, &miss);
2999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the key is a smi.
30019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ JumpIfNotSmi(rax, &miss);
3002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Get the elements array.
30049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
30059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ AssertFastElements(rcx);
3006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Check that the key is within bounds.
30089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
30099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(above_equal, &miss);
3010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Load the result and make sure it's not the hole.
30129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  SmiIndex index = masm()->SmiToIndex(rbx, rax, kPointerSizeLog2);
30139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rbx, FieldOperand(rcx,
30149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                            index.reg,
30159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                            index.scale,
30169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                            FixedArray::kHeaderSize));
30179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
30189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ j(equal, &miss);
30199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ movq(rax, rbx);
3020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
30219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
30229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ bind(&miss);
30239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
30249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
30259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  // Return the generated code.
30269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  return GetCode(NORMAL, NULL);
3027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Specialized stub for constructing objects from functions which only have only
3031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// simple assignments of the form this.x = ...; in their body.
30328a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) WangMaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
3033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
3034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rax : argc
3035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rdi : constructor
3036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rsp[0] : return address
3037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- rsp[4] : last argument
3038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
3039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label generic_stub_call;
3040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Use r8 for holding undefined which is used in several places below.
304244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Move(r8, factory()->undefined_value());
3043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT
3045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check to see whether there are any break points in the function code. If
3046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // there are jump to the generic constructor stub which calls the actual
3047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // code for the function thereby hitting the break points.
3048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
3049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kDebugInfoOffset));
3050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(rbx, r8);
3051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &generic_stub_call);
3052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
3053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the initial map and verify that it is in fact a map.
3055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
3056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Will both indicate a NULL and a Smi.
3057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(kSmiTag == 0);
3058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(rbx, &generic_stub_call);
3059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(rbx, MAP_TYPE, rcx);
3060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &generic_stub_call);
3061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
3063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cannot construct functions this way.
3064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rdi: constructor
3065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rbx: initial map
3066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpInstanceType(rbx, JS_FUNCTION_TYPE);
3067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Assert(not_equal, "Function constructed by construct stub.");
3068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
3069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Now allocate the JSObject in new space.
3071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rdi: constructor
3072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rbx: initial map
3073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset));
3074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ shl(rcx, Immediate(kPointerSizeLog2));
3075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ AllocateInNewSpace(rcx,
3076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        rdx,
3077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        rcx,
3078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        no_reg,
3079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        &generic_stub_call,
3080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        NO_ALLOCATION_FLAGS);
3081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Allocated the JSObject, now initialize the fields and add the heap tag.
3083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rbx: initial map
3084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rdx: JSObject (untagged)
3085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(Operand(rdx, JSObject::kMapOffset), rbx);
308644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Move(rbx, factory()->empty_fixed_array());
3087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(Operand(rdx, JSObject::kPropertiesOffset), rbx);
3088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(Operand(rdx, JSObject::kElementsOffset), rbx);
3089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: argc
3091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rdx: JSObject (untagged)
3092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the address of the first in-object property into r9.
3093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(r9, Operand(rdx, JSObject::kHeaderSize));
3094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate the location of the first argument. The stack contains only the
3095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // return address on top of the argc arguments.
3096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(rcx, Operand(rsp, rax, times_pointer_size, 0));
3097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: argc
3099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rcx: first argument
3100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rdx: JSObject (untagged)
3101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r8: undefined
3102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r9: first in-object property of the JSObject
3103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fill the initialized properties with a constant value or a passed argument
3104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // depending on the this.x = ...; assignment in the function.
31058a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  SharedFunctionInfo* shared = function->shared();
3106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (shared->IsThisPropertyAssignmentArgument(i)) {
3108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Check if the argument assigned to the property is actually passed.
3109e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      // If argument is not passed the property is set to undefined,
3110e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      // otherwise find it on the stack.
3111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3112e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      __ movq(rbx, r8);
3113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ cmpq(rax, Immediate(arg_number));
3114e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      __ cmovq(above, rbx, Operand(rcx, arg_number * -kPointerSize));
3115e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      // Store value in the property.
3116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(Operand(r9, i * kPointerSize), rbx);
3117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
3118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Set the property to the constant value.
3119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ Move(Operand(r9, i * kPointerSize), constant);
3121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fill the unused in-object property fields with undefined.
31258a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  ASSERT(function->has_initial_map());
3126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = shared->this_property_assignments_count();
31278a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang       i < function->initial_map()->inobject_properties();
3128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block       i++) {
3129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(Operand(r9, i * kPointerSize), r8);
3130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: argc
3133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rdx: JSObject (untagged)
3134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Move argc to rbx and the JSObject to return to rax and tag it.
3135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rbx, rax);
3136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, rdx);
3137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ or_(rax, Immediate(kHeapObjectTag));
3138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: JSObject
3140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rbx: argc
3141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Remove caller arguments and receiver from the stack and return.
3142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rcx);
3143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(rsp, Operand(rsp, rbx, times_pointer_size, 1 * kPointerSize));
3144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rcx);
314544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
314644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->constructed_objects(), 1);
314744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->constructed_objects_stub(), 1);
3148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
3149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Jump to the generic stub in case the specialized code cannot handle the
3151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // construction.
3152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&generic_stub_call);
315344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Code* code =
315444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      isolate()->builtins()->builtin(Builtins::kJSConstructStubGeneric);
3155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> generic_construct_stub(code);
3156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
3159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode();
3160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
31631e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockMaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
316444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
31651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // ----------- S t a t e -------------
31661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rax    : key
31671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rdx    : receiver
31681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rsp[0] : return address
31691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // -----------------------------------
31701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Label slow;
31711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
31721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Check that the object isn't a smi.
31731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ JumpIfSmi(rdx, &slow);
31741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
31751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Check that the key is a smi.
31761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ JumpIfNotSmi(rax, &slow);
31771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
317844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Check that the map matches.
317944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false);
31801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
31811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
31821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Check that the index is in range.
31831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ SmiToInteger32(rcx, rax);
31841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
31851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Unsigned comparison catches both negative and too-large values.
31861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ j(above_equal, &slow);
31871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
31881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rax: index (as a smi)
31891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rdx: receiver (JSObject)
31901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rcx: untagged index
31911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rbx: elements array
31921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
31931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rbx: base pointer of external storage
31941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  switch (array_type) {
31951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalByteArray:
31961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movsxbq(rcx, Operand(rbx, rcx, times_1, 0));
31971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
319844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case kExternalPixelArray:
31991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalUnsignedByteArray:
32001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movzxbq(rcx, Operand(rbx, rcx, times_1, 0));
32011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
32021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalShortArray:
32031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movsxwq(rcx, Operand(rbx, rcx, times_2, 0));
32041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
32051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalUnsignedShortArray:
32061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movzxwq(rcx, Operand(rbx, rcx, times_2, 0));
32071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
32081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalIntArray:
32091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movsxlq(rcx, Operand(rbx, rcx, times_4, 0));
32101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
32111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalUnsignedIntArray:
32121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movl(rcx, Operand(rbx, rcx, times_4, 0));
32131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
32141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalFloatArray:
32151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0));
32161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
32171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    default:
32181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      UNREACHABLE();
32191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
32201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
32211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rax: index
32231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rdx: receiver
32241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // For integer array types:
32251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rcx: value
32261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // For floating-point array type:
32271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // xmm0: value as double.
32281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(kSmiValueSize == 32);
32301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (array_type == kExternalUnsignedIntArray) {
32311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // For the UnsignedInt array type, we need to see whether
32321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // the value can be represented in a Smi. If not, we need to convert
32331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // it to a HeapNumber.
32341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    NearLabel box_int;
32351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ JumpIfUIntNotValidSmiValue(rcx, &box_int);
32371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ Integer32ToSmi(rax, rcx);
32391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ ret(0);
32401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ bind(&box_int);
32421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Allocate a HeapNumber for the int and perform int-to-double
32441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // conversion.
32451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // The value is zero-extended since we loaded the value from memory
32461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // with movl.
32471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ cvtqsi2sd(xmm0, rcx);
32481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ AllocateHeapNumber(rcx, rbx, &slow);
32501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Set the value.
32511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
32521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movq(rax, rcx);
32531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ ret(0);
32541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else if (array_type == kExternalFloatArray) {
32551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // For the floating-point array type, we need to always allocate a
32561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // HeapNumber.
32571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ AllocateHeapNumber(rcx, rbx, &slow);
32581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Set the value.
32591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
32601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movq(rax, rcx);
32611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ ret(0);
32621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else {
32631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ Integer32ToSmi(rax, rcx);
32641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ ret(0);
32651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
32661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Slow case: Jump to runtime.
32681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&slow);
326944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = isolate()->counters();
327044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
32711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // ----------- S t a t e -------------
32731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rax    : key
32741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rdx    : receiver
32751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rsp[0]  : return address
32761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // -----------------------------------
32771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ pop(rbx);
32791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rdx);  // receiver
32801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rax);  // name
32811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rbx);  // return address
32821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Perform tail call to the entry.
32841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
32851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Return the generated code.
32871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  return GetCode(flags);
32881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
32891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
32911e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockMaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
329244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
32931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // ----------- S t a t e -------------
32941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rax     : value
32951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rcx     : key
32961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rdx     : receiver
32971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rsp[0]  : return address
32981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // -----------------------------------
32991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Label slow;
33001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
33011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Check that the object isn't a smi.
33021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ JumpIfSmi(rdx, &slow);
33031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
330444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Check that the map matches.
330544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false);
33061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
330744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
330844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Check that the key is a smi.
330944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ JumpIfNotSmi(rcx, &slow);
33101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
33111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Check that the index is in range.
33121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ SmiToInteger32(rdi, rcx);  // Untag the index.
33131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset));
33141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Unsigned comparison catches both negative and too-large values.
33151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ j(above_equal, &slow);
33161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
33171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Handle both smis and HeapNumbers in the fast path. Go to the
33181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // runtime for all other kinds of values.
33191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rax: value
33201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rcx: key (a smi)
33211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rdx: receiver (a JSObject)
33221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rbx: elements array
33231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rdi: untagged key
33241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  NearLabel check_heap_number;
332544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (array_type == kExternalPixelArray) {
332644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Float to pixel conversion is only implemented in the runtime for now.
332744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ JumpIfNotSmi(rax, &slow);
332844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
332944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ JumpIfNotSmi(rax, &check_heap_number);
333044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
33311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // No more branches to slow case on this path.  Key and receiver not needed.
33321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ SmiToInteger32(rdx, rax);
33331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
33341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // rbx: base pointer of external storage
33351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  switch (array_type) {
333644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    case kExternalPixelArray:
333744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      {  // Clamp the value to [0..255].
333844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        NearLabel done;
333944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        __ testl(rdx, Immediate(0xFFFFFF00));
334044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        __ j(zero, &done);
334144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        __ setcc(negative, rdx);  // 1 if negative, 0 if positive.
334244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        __ decb(rdx);  // 0 if negative, 255 if positive.
334344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        __ bind(&done);
334444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
334544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ movb(Operand(rbx, rdi, times_1, 0), rdx);
334644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
33471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalByteArray:
33481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalUnsignedByteArray:
33491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movb(Operand(rbx, rdi, times_1, 0), rdx);
33501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
33511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalShortArray:
33521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalUnsignedShortArray:
33531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movw(Operand(rbx, rdi, times_2, 0), rdx);
33541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
33551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalIntArray:
33561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalUnsignedIntArray:
33571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movl(Operand(rbx, rdi, times_4, 0), rdx);
33581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
33591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case kExternalFloatArray:
33601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // Need to perform int-to-float conversion.
33611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ cvtlsi2ss(xmm0, rdx);
33621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
33631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
33641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    default:
33651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      UNREACHABLE();
33661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
33671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
33681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ ret(0);
33691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
337044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // TODO(danno): handle heap number -> pixel array conversion
337144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (array_type != kExternalPixelArray) {
337244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ bind(&check_heap_number);
337344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // rax: value
337444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // rcx: key (a smi)
337544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // rdx: receiver (a JSObject)
337644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // rbx: elements array
337744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // rdi: untagged key
337844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
337944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ j(not_equal, &slow);
338044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // No more branches to slow case on this path.
338144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
338244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // The WebGL specification leaves the behavior of storing NaN and
338344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // +/-Infinity into integer arrays basically undefined. For more
338444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // reproducible behavior, convert these to zero.
338544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
338644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
33871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // rdi: untagged index
33881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // rbx: base pointer of external storage
338944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // top of FPU stack: value
339044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (array_type == kExternalFloatArray) {
339144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ cvtsd2ss(xmm0, xmm0);
339244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
339344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ ret(0);
339444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    } else {
339544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // Perform float-to-int conversion with truncation (round-to-zero)
339644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // behavior.
339744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
339844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // Convert to int32 and store the low byte/word.
339944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // If the value is NaN or +/-infinity, the result is 0x80000000,
340044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // which is automatically zero when taken mod 2^n, n < 32.
340144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // rdx: value (converted to an untagged integer)
340244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // rdi: untagged index
340344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // rbx: base pointer of external storage
340444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      switch (array_type) {
340544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case kExternalByteArray:
340644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case kExternalUnsignedByteArray:
340744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          __ cvttsd2si(rdx, xmm0);
340844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          __ movb(Operand(rbx, rdi, times_1, 0), rdx);
340944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
341044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case kExternalShortArray:
341144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case kExternalUnsignedShortArray:
341244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          __ cvttsd2si(rdx, xmm0);
341344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          __ movw(Operand(rbx, rdi, times_2, 0), rdx);
341444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
341544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case kExternalIntArray:
341644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case kExternalUnsignedIntArray: {
341744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          // Convert to int64, so that NaN and infinities become
341844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          // 0x8000000000000000, which is zero mod 2^32.
341944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          __ cvttsd2siq(rdx, xmm0);
342044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          __ movl(Operand(rbx, rdi, times_4, 0), rdx);
342144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
342244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
342344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        default:
342444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          UNREACHABLE();
342544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
34261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      }
342744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ ret(0);
34281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
34291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
34301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
34311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Slow case: call runtime.
34321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&slow);
34331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
34341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // ----------- S t a t e -------------
34351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rax     : value
34361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rcx     : key
34371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rdx     : receiver
34381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  -- rsp[0]  : return address
34391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // -----------------------------------
34401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
34411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ pop(rbx);
34421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rdx);  // receiver
34431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rcx);  // key
34441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rax);  // value
3445e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Push(Smi::FromInt(NONE));   // PropertyAttributes
3446e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Push(Smi::FromInt(
3447e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      Code::ExtractExtraICStateFromFlags(flags) & kStrictMode));
34481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rbx);  // return address
34491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
34501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Do tail-call to runtime routine.
3451e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
34521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
34531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  return GetCode(flags);
34541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
34551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
3456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
3457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
3459f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
3460f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#endif  // V8_TARGET_ARCH_X64
3461