stub-cache-ia32.cc revision 59151504615d929945dc59db37bf1166937748c6
1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2006-2009 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_IA32)
31f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "ic-inl.h"
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "codegen-inl.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
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void ProbeTable(MacroAssembler* masm,
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       Code::Flags flags,
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       StubCache::Table table,
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       Register name,
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       Register offset,
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       Register extra) {
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference key_offset(SCTableReference::keyReference(table));
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference value_offset(SCTableReference::valueReference(table));
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (extra.is_valid()) {
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Get the code entry from the cache.
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(extra, Operand::StaticArray(offset, times_2, value_offset));
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check that the key in the entry matches the name.
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(not_equal, &miss, not_taken);
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check that the flags match what we're looking for.
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ and_(offset, ~Code::kFlagsNotUsedInLookup);
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(offset, flags);
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(not_equal, &miss);
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Jump to the first instruction in the code stub.
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(Operand(extra), Immediate(Code::kHeaderSize - kHeapObjectTag));
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ jmp(Operand(extra));
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&miss);
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Save the offset on the stack.
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ push(offset);
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check that the key in the entry matches the name.
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(not_equal, &miss, not_taken);
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Get the code entry from the cache.
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check that the flags match what we're looking for.
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ and_(offset, ~Code::kFlagsNotUsedInLookup);
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(offset, flags);
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(not_equal, &miss);
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Restore offset and re-load code entry from cache.
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ pop(offset);
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Jump to the first instruction in the code stub.
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag));
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ jmp(Operand(offset));
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Pop at miss.
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&miss);
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ pop(offset);
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1048defd9ff6930b4e24729971a61cf7469daf119beSteve Block// Helper function used to check that the dictionary doesn't contain
1058defd9ff6930b4e24729971a61cf7469daf119beSteve Block// the property. This function may return false negatives, so miss_label
1068defd9ff6930b4e24729971a61cf7469daf119beSteve Block// must always call a backup property check that is complete.
1078defd9ff6930b4e24729971a61cf7469daf119beSteve Block// This function is safe to call if the receiver has fast properties.
1088defd9ff6930b4e24729971a61cf7469daf119beSteve Block// Name must be a symbol and receiver must be a heap object.
1098defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
1108defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                             Label* miss_label,
1118defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                             Register receiver,
1128defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                             String* name,
1138defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                             Register r0,
1143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                             Register r1) {
1158defd9ff6930b4e24729971a61cf7469daf119beSteve Block  ASSERT(name->IsSymbol());
1168defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ IncrementCounter(&Counters::negative_lookups, 1);
1178defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ IncrementCounter(&Counters::negative_lookups_miss, 1);
1188defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1198defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Label done;
1208defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset));
1218defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1228defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kInterceptorOrAccessCheckNeededMask =
1238defd9ff6930b4e24729971a61cf7469daf119beSteve Block      (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
1243bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1258defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Bail out if the receiver has a named interceptor or requires access checks.
1263bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  __ test_b(FieldOperand(r0, Map::kBitFieldOffset),
1273bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch            kInterceptorOrAccessCheckNeededMask);
1288defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(not_zero, miss_label, not_taken);
1298defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1303bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // Check that receiver is a JSObject.
1318defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE);
1328defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(below, miss_label, not_taken);
1338defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1348defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Load properties array.
1358defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Register properties = r0;
1368defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
1378defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1388defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Check that the properties array is a dictionary.
1398defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
1408defd9ff6930b4e24729971a61cf7469daf119beSteve Block         Immediate(Factory::hash_table_map()));
1418defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(not_equal, miss_label);
1428defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1438defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Compute the capacity mask.
1448defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kCapacityOffset =
1458defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kHeaderSize +
1468defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kCapacityIndex * kPointerSize;
1478defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1488defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Generate an unrolled loop that performs a few probes before
1498defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // giving up.
1508defd9ff6930b4e24729971a61cf7469daf119beSteve Block  static const int kProbes = 4;
1518defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kElementsStartOffset =
1528defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kHeaderSize +
1538defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kElementsStartIndex * kPointerSize;
1548defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1558defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // If names of slots in range from 1 to kProbes - 1 for the hash value are
1568defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // not equal to the name and kProbes-th slot is not used (its name is the
1578defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // undefined value), it guarantees the hash table doesn't contain the
1588defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // property. It's true even if some slots represent deleted properties
1598defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // (their names are the null value).
1608defd9ff6930b4e24729971a61cf7469daf119beSteve Block  for (int i = 0; i < kProbes; i++) {
1618defd9ff6930b4e24729971a61cf7469daf119beSteve Block    // r0 points to properties hash.
1628defd9ff6930b4e24729971a61cf7469daf119beSteve Block    // Compute the masked index: (hash + i + i * i) & mask.
1633bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    Register index = r1;
1648defd9ff6930b4e24729971a61cf7469daf119beSteve Block    // Capacity is smi 2^n.
1658defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(index, FieldOperand(properties, kCapacityOffset));
1668defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ dec(index);
1678defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ and_(Operand(index),
1688defd9ff6930b4e24729971a61cf7469daf119beSteve Block            Immediate(Smi::FromInt(name->Hash() +
1698defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   StringDictionary::GetProbeOffset(i))));
1708defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1718defd9ff6930b4e24729971a61cf7469daf119beSteve Block    // Scale the index by multiplying by the entry size.
1728defd9ff6930b4e24729971a61cf7469daf119beSteve Block    ASSERT(StringDictionary::kEntrySize == 3);
1738defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
1748defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    Register entity_name = r1;
1768defd9ff6930b4e24729971a61cf7469daf119beSteve Block    // Having undefined at this place means the name is not contained.
1778defd9ff6930b4e24729971a61cf7469daf119beSteve Block    ASSERT_EQ(kSmiTagSize, 1);
1788defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
1798defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                kElementsStartOffset - kHeapObjectTag));
1808defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ cmp(entity_name, Factory::undefined_value());
1818defd9ff6930b4e24729971a61cf7469daf119beSteve Block    if (i != kProbes - 1) {
1828defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ j(equal, &done, taken);
1838defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1848defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // Stop if found the property.
1858defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ cmp(entity_name, Handle<String>(name));
1868defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ j(equal, miss_label, not_taken);
1878defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1883bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      // Check if the entry name is not a symbol.
1893bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
1903bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
1913bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                kIsSymbolMask);
1923bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ j(zero, miss_label, not_taken);
1938defd9ff6930b4e24729971a61cf7469daf119beSteve Block    } else {
1948defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // Give up probing if still not found the undefined value.
1958defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ j(not_equal, miss_label, not_taken);
1968defd9ff6930b4e24729971a61cf7469daf119beSteve Block    }
1978defd9ff6930b4e24729971a61cf7469daf119beSteve Block  }
1988defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1998defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ bind(&done);
2008defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ DecrementCounter(&Counters::negative_lookups_miss, 1);
2018defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
2028defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2038defd9ff6930b4e24729971a61cf7469daf119beSteve Block
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCache::GenerateProbe(MacroAssembler* masm,
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Code::Flags flags,
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Register receiver,
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Register name,
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Register scratch,
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Register extra) {
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure that code is valid. The shifting code relies on the
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // entry size being 8.
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(sizeof(Entry) == 8);
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure the flags does not name a specific type.
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure that there are no register conflicts.
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!scratch.is(receiver));
221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!scratch.is(name));
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!extra.is(receiver));
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!extra.is(name));
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!extra.is(scratch));
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(receiver, Immediate(kSmiTagMask));
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &miss, not_taken);
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the map of the receiver and compute the hash.
231d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ xor_(scratch, flags);
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the primary table.
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ProbeTable(masm, flags, kPrimary, name, scratch, extra);
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Primary miss: Compute hash for secondary probe.
240d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ xor_(scratch, flags);
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ sub(scratch, Operand(name));
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ add(Operand(scratch), Immediate(flags));
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the secondary table.
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ProbeTable(masm, flags, kSecondary, name, scratch, extra);
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Fall-through and let caller handle the miss by
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // entering the runtime system.
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                       int index,
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                       Register prototype) {
26080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadGlobalFunction(index, prototype);
26180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadGlobalFunctionInitialMap(prototype, prototype);
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the prototype from the initial map.
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2677f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
2687f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    MacroAssembler* masm, int index, Register prototype) {
2697f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Get the global function with the given index.
2707f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
2717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Load its initial map. The global functions all have initial maps.
2727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ Set(prototype, Immediate(Handle<Map>(function->initial_map())));
2737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Load the prototype from the initial map.
2747f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
2757f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
2767f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
2777f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Register receiver,
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Register scratch,
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Label* miss_label) {
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(receiver, Immediate(kSmiTagMask));
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, miss_label, not_taken);
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is a JS array.
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, miss_label, not_taken);
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load length directly from the JS array.
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Generate code to check if an object is a string.  If the object is
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// a string, the map's instance type is left in the scratch register.
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void GenerateStringCheck(MacroAssembler* masm,
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Register receiver,
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Register scratch,
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Label* smi,
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Label* non_string_object) {
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(receiver, Immediate(kSmiTagMask));
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, smi, not_taken);
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is a string.
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(kNotStringTag != 0);
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(scratch, Immediate(kNotStringTag));
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, non_string_object, not_taken);
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            Register receiver,
318402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                            Register scratch1,
319402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                            Register scratch2,
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            Label* miss) {
321402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label check_wrapper;
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the object is a string leaving the instance type in the
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // scratch register.
325402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
327d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Load length from the string and convert to a smi.
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the object is a JSValue wrapper.
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_wrapper);
333402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(scratch1, JS_VALUE_TYPE);
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, miss, not_taken);
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the wrapped value is a string and load the length
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // directly if it is.
338402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
339402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
340402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
341402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ ret(0);
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                 Register receiver,
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                 Register scratch1,
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                 Register scratch2,
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                 Label* miss_label) {
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(eax, Operand(scratch1));
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Load a fast property out of a holder object (src). In-object properties
357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// are loaded directly otherwise the property is loaded from the properties
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// fixed array.
359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            Register dst, Register src,
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            JSObject* holder, int index) {
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Adjust for the number of properties stored in the holder.
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  index -= holder->map()->inobject_properties();
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (index < 0) {
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Get the property straight out of the holder.
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int offset = holder->map()->instance_size() + (index * kPointerSize);
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(dst, FieldOperand(src, offset));
368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Calculate the offset into the properties array.
370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int offset = index * kPointerSize + FixedArray::kHeaderSize;
371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(dst, FieldOperand(dst, offset));
373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
377402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescustatic void PushInterceptorArguments(MacroAssembler* masm,
378402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                     Register receiver,
379402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                     Register holder,
380402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                     Register name,
381402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                     JSObject* holder_obj) {
382402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(name);
383402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
384402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ASSERT(!Heap::InNewSpace(interceptor));
3856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register scratch = name;
3866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(scratch, Immediate(Handle<Object>(interceptor)));
3876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(scratch);
388402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(receiver);
3896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(holder);
3906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset));
391402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
392402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
393402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   Register receiver,
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   Register holder,
397e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                   Register name,
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   JSObject* holder_obj) {
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
400402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CallExternalReference(
401402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly)),
402402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        5);
403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
406402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu// Reserves space for the extra arguments to FastHandleApiCall in the
407402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu// caller's frame.
408402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu//
409402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu// These arguments are set by CheckPrototypes and GenerateFastApiCall.
410402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescustatic void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
411402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ----------- S t a t e -------------
412402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[0] : return address
413402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[4] : last argument in the internal frame of the caller
414402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // -----------------------------------
415402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(scratch);
416402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(Immediate(Smi::FromInt(0)));
417402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(Immediate(Smi::FromInt(0)));
418402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(Immediate(Smi::FromInt(0)));
419402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(Immediate(Smi::FromInt(0)));
420402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(scratch);
421402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
422402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
423402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
424402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu// Undoes the effects of ReserveSpaceForFastApiCall.
425402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescustatic void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
426402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ----------- S t a t e -------------
427402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[0]  : return address
428402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[4]  : last fast api call extra argument
429402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- ...
430402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[16] : first fast api call extra argument
431402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[20] : last argument in the internal frame
432402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // -----------------------------------
433402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(scratch);
434402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ add(Operand(esp), Immediate(kPointerSize * 4));
435402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(scratch);
436402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
437402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
438402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
439402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu// Generates call to FastHandleApiCall builtin.
440402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescustatic void GenerateFastApiCall(MacroAssembler* masm,
441402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                const CallOptimization& optimization,
442402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                int argc) {
443402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ----------- S t a t e -------------
444402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[0]              : return address
445402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[4]              : object passing the type check
446402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //                           (last fast api call extra argument,
447402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //                            set by CheckPrototypes)
448402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[8]              : api call data
449402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[12]             : api callback
450402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[16]             : api function
451402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //                           (first fast api call extra argument)
452402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[20]             : last argument
453402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- ...
454402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[(argc + 5) * 4] : first argument
455402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[(argc + 6) * 4] : receiver
456402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // -----------------------------------
457402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
458402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Get the function and setup the context.
459402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  JSFunction* function = optimization.constant_function();
460402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi, Immediate(Handle<JSFunction>(function)));
461402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
462402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
463402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Pass the additional arguments FastHandleApiCall expects.
464402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(Operand(esp, 4 * kPointerSize), edi);
465402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  bool info_loaded = false;
466402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Object* callback = optimization.api_call_info()->callback();
467402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  if (Heap::InNewSpace(callback)) {
468402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    info_loaded = true;
469402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
470402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kCallbackOffset));
471402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(Operand(esp, 3 * kPointerSize), ebx);
472402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  } else {
473402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(Operand(esp, 3 * kPointerSize), Immediate(Handle<Object>(callback)));
474402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
475402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Object* call_data = optimization.api_call_info()->data();
476402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  if (Heap::InNewSpace(call_data)) {
477402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    if (!info_loaded) {
478402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
479402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    }
480402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
481402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(Operand(esp, 2 * kPointerSize), ebx);
482402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  } else {
483402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(Operand(esp, 2 * kPointerSize),
484402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu           Immediate(Handle<Object>(call_data)));
485402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
486402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
487402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Set the number of arguments.
488402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, Immediate(argc + 4));
489402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
490402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Jump to the fast api call builtin (tail call).
491402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Handle<Code> code = Handle<Code>(
492402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      Builtins::builtin(Builtins::FastHandleApiCall));
493402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ParameterCount expected(0);
494402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ InvokeCode(code, expected, expected,
495402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
496402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
497402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
498402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass CallInterceptorCompiler BASE_EMBEDDED {
500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
501402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  CallInterceptorCompiler(StubCompiler* stub_compiler,
502402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                          const ParameterCount& arguments,
503402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                          Register name)
504402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      : stub_compiler_(stub_compiler),
505402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        arguments_(arguments),
506402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        name_(name) {}
507402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
508402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  void Compile(MacroAssembler* masm,
509402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               JSObject* object,
510402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               JSObject* holder,
511402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               String* name,
512402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               LookupResult* lookup,
513402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               Register receiver,
514402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               Register scratch1,
515402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               Register scratch2,
5163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch               Register scratch3,
517402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               Label* miss) {
518402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    ASSERT(holder->HasNamedInterceptor());
519402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
520402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
521402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Check that the receiver isn't a smi.
522402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ test(receiver, Immediate(kSmiTagMask));
523402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ j(zero, miss, not_taken);
524402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
525402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    CallOptimization optimization(lookup);
526402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
5276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (optimization.is_constant_call()) {
528402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      CompileCacheable(masm,
529402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                       object,
530402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                       receiver,
531402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                       scratch1,
532402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                       scratch2,
5333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                       scratch3,
534402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                       holder,
535402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                       lookup,
536402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                       name,
537402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                       optimization,
538402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                       miss);
539402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    } else {
540402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      CompileRegular(masm,
541402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                     object,
542402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                     receiver,
543402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                     scratch1,
544402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                     scratch2,
5453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                     scratch3,
546402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                     name,
547402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                     holder,
548402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                     miss);
549402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    }
550402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
552402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu private:
553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void CompileCacheable(MacroAssembler* masm,
554402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                        JSObject* object,
555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        Register receiver,
556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        Register scratch1,
557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        Register scratch2,
5583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                        Register scratch3,
559f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                        JSObject* interceptor_holder,
560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        LookupResult* lookup,
561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        String* name,
562402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                        const CallOptimization& optimization,
563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        Label* miss_label) {
564402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    ASSERT(optimization.is_constant_call());
565402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    ASSERT(!lookup->holder()->IsGlobalObject());
566402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
567402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    int depth1 = kInvalidProtoDepth;
568402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    int depth2 = kInvalidProtoDepth;
569402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    bool can_do_fast_api_call = false;
570402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    if (optimization.is_simple_api_call() &&
571402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        !lookup->holder()->IsGlobalObject()) {
572f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke      depth1 =
573f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke          optimization.GetPrototypeDepthOfExpectedType(object,
574f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                                                       interceptor_holder);
575402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      if (depth1 == kInvalidProtoDepth) {
576f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke        depth2 =
577f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke            optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
578f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                                                         lookup->holder());
579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
580402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
581402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                             (depth2 != kInvalidProtoDepth);
582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
584402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ IncrementCounter(&Counters::call_const_interceptor, 1);
585402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
586402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    if (can_do_fast_api_call) {
587402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1);
588402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      ReserveSpaceForFastApiCall(masm, scratch1);
589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
591f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Check that the maps from receiver to interceptor's holder
592f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // haven't changed and thus we can invoke interceptor.
593402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    Label miss_cleanup;
594402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
595402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    Register holder =
5967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch        stub_compiler_->CheckPrototypes(object, receiver,
5977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                        interceptor_holder, scratch1,
5983bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                        scratch2, scratch3, name, depth1, miss);
599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
600f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Invoke an interceptor and if it provides a value,
601f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // branch to |regular_invoke|.
602402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    Label regular_invoke;
603f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
604f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                        &regular_invoke);
605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
606f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Interceptor returned nothing for this property.  Try to use cached
607f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // constant function.
608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
609f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Check that the maps from interceptor's holder to constant function's
610f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // holder haven't changed and thus we can use cached constant function.
6117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    if (interceptor_holder != lookup->holder()) {
6127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
6137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                      lookup->holder(), scratch1,
6143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                      scratch2, scratch3, name, depth2, miss);
6157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    } else {
6167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // CheckPrototypes has a side effect of fetching a 'holder'
6177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // for API (object which is instanceof for the signature).  It's
6187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // safe to omit it here, as if present, it should be fetched
6197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // by the previous CheckPrototypes.
6207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      ASSERT(depth2 == kInvalidProtoDepth);
6217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    }
622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
623f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Invoke function.
624402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    if (can_do_fast_api_call) {
625402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      GenerateFastApiCall(masm, optimization, arguments_.immediate());
626402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    } else {
627402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ InvokeFunction(optimization.constant_function(), arguments_,
628402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                        JUMP_FUNCTION);
629402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    }
630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
631f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Deferred code for fast API call case---clean preallocated space.
632402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    if (can_do_fast_api_call) {
633402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ bind(&miss_cleanup);
634402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      FreeSpaceForFastApiCall(masm, scratch1);
635402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ jmp(miss_label);
636402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    }
637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
638f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke    // Invoke a regular function.
639402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ bind(&regular_invoke);
640402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    if (can_do_fast_api_call) {
641402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      FreeSpaceForFastApiCall(masm, scratch1);
642402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    }
643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void CompileRegular(MacroAssembler* masm,
646402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                      JSObject* object,
647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      Register receiver,
648402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                      Register scratch1,
649402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                      Register scratch2,
6503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                      Register scratch3,
651402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                      String* name,
652f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                      JSObject* interceptor_holder,
653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      Label* miss_label) {
654402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    Register holder =
655f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke        stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
6563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                        scratch1, scratch2, scratch3, name,
657402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                        miss_label);
658402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ EnterInternalFrame();
660e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Save the name_ register across the call.
661e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ push(name_);
662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    PushInterceptorArguments(masm,
664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                             receiver,
665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                             holder,
666e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                             name_,
667f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                             interceptor_holder);
668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
669402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ CallExternalReference(
670402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          ExternalReference(
671402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu              IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
672402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          5);
673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
674e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Restore the name_ register.
675e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ pop(name_);
676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LeaveInternalFrame();
677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
679402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  void LoadWithInterceptor(MacroAssembler* masm,
680402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                           Register receiver,
681402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                           Register holder,
682402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                           JSObject* holder_obj,
683402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                           Label* interceptor_succeeded) {
684402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ EnterInternalFrame();
685402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ push(holder);  // Save the holder.
686402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ push(name_);  // Save the name.
687402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
688402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    CompileCallLoadPropertyWithInterceptor(masm,
689402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                           receiver,
690402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                           holder,
691402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                           name_,
692402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                           holder_obj);
693402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
694402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ pop(name_);  // Restore the name.
695402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ pop(receiver);  // Restore the holder.
696402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ LeaveInternalFrame();
697402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
698402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ cmp(eax, Factory::no_interceptor_result_sentinel());
699402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ j(not_equal, interceptor_succeeded);
700402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
701402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
702402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  StubCompiler* stub_compiler_;
703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const ParameterCount& arguments_;
704e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Register name_;
705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code* code = NULL;
711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (kind == Code::LOAD_IC) {
712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    code = Builtins::builtin(Builtins::LoadIC_Miss);
713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> ic(code);
718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(ic, RelocInfo::CODE_TARGET);
719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
722402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu// Both name_reg and receiver_reg are preserved on jumps to miss_label,
723402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu// but may be destroyed if store is successful.
724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateStoreField(MacroAssembler* masm,
725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      JSObject* object,
726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      int index,
727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Map* transition,
728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Register receiver_reg,
729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Register name_reg,
730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Register scratch,
731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Label* miss_label) {
732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(receiver_reg, Immediate(kSmiTagMask));
734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, miss_label, not_taken);
735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the map of the object hasn't changed.
737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Immediate(Handle<Map>(object->map())));
739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, miss_label, not_taken);
740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform global security token check if needed.
742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (object->IsJSGlobalProxy()) {
743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Stub never generated for non-global objects that require access
747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // checks.
748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform map transition for the receiver if necessary.
751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The properties must be extended before we can store the value.
753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // We jump to a runtime call that extends the properties array.
754402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ pop(scratch);  // Return address.
755402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ push(receiver_reg);
756402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ push(Immediate(Handle<Map>(transition)));
757402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ push(eax);
758402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ push(scratch);
7596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ TailCallExternalReference(
760402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return;
762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (transition != NULL) {
765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Update the map of the object; no write barrier updating is
766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // needed because the map is never in new space.
767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block           Immediate(Handle<Map>(transition)));
769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Adjust for the number of properties stored in the object. Even in the
772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // face of a transition we can use the old map here because the size of the
773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // object and the number of in-object properties is not going to change.
774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  index -= object->map()->inobject_properties();
775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (index < 0) {
777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Set the property straight into the object.
778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int offset = object->map()->instance_size() + (index * kPointerSize);
779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(FieldOperand(receiver_reg, offset), eax);
780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Update the write barrier for the array address.
782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Pass the value being stored in the now unused name_reg.
783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(name_reg, Operand(eax));
784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ RecordWrite(receiver_reg, offset, name_reg, scratch);
785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Write to the properties array.
787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int offset = index * kPointerSize + FixedArray::kHeaderSize;
788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Get the properties array (optimistically).
789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(FieldOperand(scratch, offset), eax);
791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Update the write barrier for the array address.
793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Pass the value being stored in the now unused name_reg.
794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(name_reg, Operand(eax));
795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ RecordWrite(scratch, offset, name_reg, receiver_reg);
796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the value (register eax).
799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// Generate code to check that a global property cell is empty. Create
8046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// the property cell at compilation time if no cell exists for the
8056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// property.
8066ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic Object* GenerateCheckPropertyCell(MacroAssembler* masm,
8076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         GlobalObject* global,
8086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         String* name,
8096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register scratch,
8106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Label* miss) {
8116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Object* probe = global->EnsurePropertyCell(name);
8126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  if (probe->IsFailure()) return probe;
8136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
8146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ASSERT(cell->value()->IsTheHole());
8156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(scratch, Immediate(Handle<Object>(cell)));
8166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
8176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block         Immediate(Factory::the_hole_value()));
8186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_equal, miss, not_taken);
8196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  return cell;
8206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
8216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
8226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
8238defd9ff6930b4e24729971a61cf7469daf119beSteve Block// Calls GenerateCheckPropertyCell for each global object in the prototype chain
8248defd9ff6930b4e24729971a61cf7469daf119beSteve Block// from object to (but not including) holder.
8258defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic Object* GenerateCheckPropertyCells(MacroAssembler* masm,
8268defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                          JSObject* object,
8278defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                          JSObject* holder,
8288defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                          String* name,
8298defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                          Register scratch,
8308defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                          Label* miss) {
8318defd9ff6930b4e24729971a61cf7469daf119beSteve Block  JSObject* current = object;
8328defd9ff6930b4e24729971a61cf7469daf119beSteve Block  while (current != holder) {
8338defd9ff6930b4e24729971a61cf7469daf119beSteve Block    if (current->IsGlobalObject()) {
8348defd9ff6930b4e24729971a61cf7469daf119beSteve Block      Object* cell = GenerateCheckPropertyCell(masm,
8358defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                               GlobalObject::cast(current),
8368defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                               name,
8378defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                               scratch,
8388defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                               miss);
8398defd9ff6930b4e24729971a61cf7469daf119beSteve Block      if (cell->IsFailure()) {
8408defd9ff6930b4e24729971a61cf7469daf119beSteve Block        return cell;
8418defd9ff6930b4e24729971a61cf7469daf119beSteve Block      }
8428defd9ff6930b4e24729971a61cf7469daf119beSteve Block    }
8438defd9ff6930b4e24729971a61cf7469daf119beSteve Block    ASSERT(current->IsJSObject());
8448defd9ff6930b4e24729971a61cf7469daf119beSteve Block    current = JSObject::cast(current->GetPrototype());
8458defd9ff6930b4e24729971a61cf7469daf119beSteve Block  }
8468defd9ff6930b4e24729971a61cf7469daf119beSteve Block  return NULL;
8478defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
8488defd9ff6930b4e24729971a61cf7469daf119beSteve Block
8498defd9ff6930b4e24729971a61cf7469daf119beSteve Block
850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm())
852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockRegister StubCompiler::CheckPrototypes(JSObject* object,
855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                       Register object_reg,
856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                       JSObject* holder,
857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                       Register holder_reg,
8583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                       Register scratch1,
8593bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                       Register scratch2,
860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                       String* name,
8618defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                       int save_at_depth,
8623bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                       Label* miss) {
8638defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Make sure there's no overlap between holder and object registers.
8643bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
8653bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
8663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch         && !scratch2.is(scratch1));
8678defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Keep track of the current object in register reg.
8688defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Register reg = object_reg;
8698defd9ff6930b4e24729971a61cf7469daf119beSteve Block  JSObject* current = object;
8708defd9ff6930b4e24729971a61cf7469daf119beSteve Block  int depth = 0;
8718defd9ff6930b4e24729971a61cf7469daf119beSteve Block
8728defd9ff6930b4e24729971a61cf7469daf119beSteve Block  if (save_at_depth == depth) {
8738defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(Operand(esp, kPointerSize), reg);
8748defd9ff6930b4e24729971a61cf7469daf119beSteve Block  }
875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8768defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Traverse the prototype chain and check the maps in the prototype chain for
8778defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // fast and global objects or do negative lookup for normal objects.
8788defd9ff6930b4e24729971a61cf7469daf119beSteve Block  while (current != holder) {
8798defd9ff6930b4e24729971a61cf7469daf119beSteve Block    depth++;
8808defd9ff6930b4e24729971a61cf7469daf119beSteve Block
8818defd9ff6930b4e24729971a61cf7469daf119beSteve Block    // Only global objects and objects that do not require access
8828defd9ff6930b4e24729971a61cf7469daf119beSteve Block    // checks are allowed in stubs.
8838defd9ff6930b4e24729971a61cf7469daf119beSteve Block    ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
8848defd9ff6930b4e24729971a61cf7469daf119beSteve Block
8858defd9ff6930b4e24729971a61cf7469daf119beSteve Block    ASSERT(current->GetPrototype()->IsJSObject());
8868defd9ff6930b4e24729971a61cf7469daf119beSteve Block    JSObject* prototype = JSObject::cast(current->GetPrototype());
8878defd9ff6930b4e24729971a61cf7469daf119beSteve Block    if (!current->HasFastProperties() &&
8888defd9ff6930b4e24729971a61cf7469daf119beSteve Block        !current->IsJSGlobalObject() &&
8898defd9ff6930b4e24729971a61cf7469daf119beSteve Block        !current->IsJSGlobalProxy()) {
8908defd9ff6930b4e24729971a61cf7469daf119beSteve Block      if (!name->IsSymbol()) {
8918defd9ff6930b4e24729971a61cf7469daf119beSteve Block        Object* lookup_result = Heap::LookupSymbol(name);
8928defd9ff6930b4e24729971a61cf7469daf119beSteve Block        if (lookup_result->IsFailure()) {
8938defd9ff6930b4e24729971a61cf7469daf119beSteve Block          set_failure(Failure::cast(lookup_result));
8948defd9ff6930b4e24729971a61cf7469daf119beSteve Block          return reg;
8958defd9ff6930b4e24729971a61cf7469daf119beSteve Block        } else {
8968defd9ff6930b4e24729971a61cf7469daf119beSteve Block          name = String::cast(lookup_result);
8978defd9ff6930b4e24729971a61cf7469daf119beSteve Block        }
8988defd9ff6930b4e24729971a61cf7469daf119beSteve Block      }
8998defd9ff6930b4e24729971a61cf7469daf119beSteve Block      ASSERT(current->property_dictionary()->FindEntry(name) ==
9008defd9ff6930b4e24729971a61cf7469daf119beSteve Block             StringDictionary::kNotFound);
9018defd9ff6930b4e24729971a61cf7469daf119beSteve Block
9028defd9ff6930b4e24729971a61cf7469daf119beSteve Block      GenerateDictionaryNegativeLookup(masm(),
9038defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                       miss,
9048defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                       reg,
9058defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                       name,
9063bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                       scratch1,
9073bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                       scratch2);
9083bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
9098defd9ff6930b4e24729971a61cf7469daf119beSteve Block      reg = holder_reg;  // from now the object is in holder_reg
9103bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
9118defd9ff6930b4e24729971a61cf7469daf119beSteve Block    } else if (Heap::InNewSpace(prototype)) {
9128defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // Get the map of the current object.
9133bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
9143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ cmp(Operand(scratch1), Immediate(Handle<Map>(current->map())));
9158defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // Branch on the result of the map check.
9168defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ j(not_equal, miss, not_taken);
9178defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // Check access rights to the global object.  This has to happen
9188defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // after the map check so that we know that the object is
9198defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // actually a global object.
9208defd9ff6930b4e24729971a61cf7469daf119beSteve Block      if (current->IsJSGlobalProxy()) {
9213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        __ CheckAccessGlobalProxy(reg, scratch1, miss);
9228defd9ff6930b4e24729971a61cf7469daf119beSteve Block
9238defd9ff6930b4e24729971a61cf7469daf119beSteve Block        // Restore scratch register to be the map of the object.
9248defd9ff6930b4e24729971a61cf7469daf119beSteve Block        // We load the prototype from the map in the scratch register.
9253bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
9268defd9ff6930b4e24729971a61cf7469daf119beSteve Block      }
9278defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // The prototype is in new space; we cannot store a reference
9288defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // to it in the code. Load it from the map.
9298defd9ff6930b4e24729971a61cf7469daf119beSteve Block      reg = holder_reg;  // from now the object is in holder_reg
9303bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
9318defd9ff6930b4e24729971a61cf7469daf119beSteve Block    } else {
9328defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // Check the map of the current object.
9338defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
9348defd9ff6930b4e24729971a61cf7469daf119beSteve Block             Immediate(Handle<Map>(current->map())));
9358defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // Branch on the result of the map check.
9368defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ j(not_equal, miss, not_taken);
9378defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // Check access rights to the global object.  This has to happen
9388defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // after the map check so that we know that the object is
9398defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // actually a global object.
9408defd9ff6930b4e24729971a61cf7469daf119beSteve Block      if (current->IsJSGlobalProxy()) {
9413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        __ CheckAccessGlobalProxy(reg, scratch1, miss);
942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
9438defd9ff6930b4e24729971a61cf7469daf119beSteve Block      // The prototype is in old space; load it directly.
9448defd9ff6930b4e24729971a61cf7469daf119beSteve Block      reg = holder_reg;  // from now the object is in holder_reg
9458defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ mov(reg, Handle<JSObject>(prototype));
946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
9478defd9ff6930b4e24729971a61cf7469daf119beSteve Block
9488defd9ff6930b4e24729971a61cf7469daf119beSteve Block    if (save_at_depth == depth) {
9498defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ mov(Operand(esp, kPointerSize), reg);
9508defd9ff6930b4e24729971a61cf7469daf119beSteve Block    }
9518defd9ff6930b4e24729971a61cf7469daf119beSteve Block
9528defd9ff6930b4e24729971a61cf7469daf119beSteve Block    // Go to the next object in the prototype chain.
9538defd9ff6930b4e24729971a61cf7469daf119beSteve Block    current = prototype;
954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
9558defd9ff6930b4e24729971a61cf7469daf119beSteve Block  ASSERT(current == holder);
9568defd9ff6930b4e24729971a61cf7469daf119beSteve Block
9578defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Log the check depth.
9588defd9ff6930b4e24729971a61cf7469daf119beSteve Block  LOG(IntEvent("check-maps-depth", depth + 1));
9598defd9ff6930b4e24729971a61cf7469daf119beSteve Block
9608defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Check the holder map.
9618defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
9628defd9ff6930b4e24729971a61cf7469daf119beSteve Block         Immediate(Handle<Map>(holder->map())));
9638defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(not_equal, miss, not_taken);
9648defd9ff6930b4e24729971a61cf7469daf119beSteve Block
9658defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Perform security check for access to the global object.
9668defd9ff6930b4e24729971a61cf7469daf119beSteve Block  ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
9678defd9ff6930b4e24729971a61cf7469daf119beSteve Block  if (holder->IsJSGlobalProxy()) {
9683bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    __ CheckAccessGlobalProxy(reg, scratch1, miss);
9698defd9ff6930b4e24729971a61cf7469daf119beSteve Block  };
9708defd9ff6930b4e24729971a61cf7469daf119beSteve Block
9718defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // If we've skipped any global objects, it's not enough to verify
9728defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // that their maps haven't changed.  We also need to check that the
9738defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // property cell for the property is still empty.
9748defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Object* result = GenerateCheckPropertyCells(masm(),
9758defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                              object,
9768defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                              holder,
9778defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                              name,
9783bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                              scratch1,
9798defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                              miss);
9808defd9ff6930b4e24729971a61cf7469daf119beSteve Block  if (result->IsFailure()) set_failure(Failure::cast(result));
981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
982402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Return the register containing the holder.
9838defd9ff6930b4e24729971a61cf7469daf119beSteve Block  return reg;
984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadField(JSObject* object,
988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     JSObject* holder,
989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     Register receiver,
990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     Register scratch1,
991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     Register scratch2,
9923bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                     Register scratch3,
993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     int index,
994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     String* name,
995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     Label* miss) {
996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(receiver, Immediate(kSmiTagMask));
998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, miss, not_taken);
999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check the prototype chain.
1001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register reg =
1002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CheckPrototypes(object, receiver, holder,
10033bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                      scratch1, scratch2, scratch3, name, miss);
1004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the value from the properties.
1006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
1007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
1008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1011e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkebool StubCompiler::GenerateLoadCallback(JSObject* object,
1012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        JSObject* holder,
1013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register receiver,
1014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register name_reg,
1015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register scratch1,
1016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register scratch2,
10173bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                        Register scratch3,
1018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        AccessorInfo* callback,
1019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        String* name,
1020e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                        Label* miss,
1021e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                        Failure** failure) {
1022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
1023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(receiver, Immediate(kSmiTagMask));
1024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, miss, not_taken);
1025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the maps haven't changed.
1027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register reg =
1028bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch      CheckPrototypes(object, receiver, holder, scratch1,
1029bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch                      scratch2, scratch3, name, miss);
1030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1031d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Handle<AccessorInfo> callback_handle(callback);
1032d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1033d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ EnterInternalFrame();
1034bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ PushHandleScope(scratch2);
1035bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  // Push the stack address where the list of arguments ends.
1036bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ mov(scratch2, esp);
1037bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ sub(Operand(scratch2), Immediate(2 * kPointerSize));
1038bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ push(scratch2);
1039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(receiver);  // receiver
1040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(reg);  // holder
10419dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Push data from AccessorInfo.
10429dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  if (Heap::InNewSpace(callback_handle->data())) {
1043bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch    __ mov(scratch2, Immediate(callback_handle));
1044bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch    __ push(FieldOperand(scratch2, AccessorInfo::kDataOffset));
10459dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  } else {
10469dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    __ push(Immediate(Handle<Object>(callback_handle->data())));
10479dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
1048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(name_reg);  // name
1049d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Save a pointer to where we pushed the arguments pointer.
10506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // This will be passed as the const AccessorInfo& to the C++ callback.
1051d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ mov(eax, esp);
10526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ add(Operand(eax), Immediate(4 * kPointerSize));
1053d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ mov(ebx, esp);
1054d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1055d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Do call through the api.
10566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace);
1057d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Address getter_address = v8::ToCData<Address>(callback->getter());
1058d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ApiFunction fun(getter_address);
1059d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ApiGetterEntryStub stub(callback_handle, &fun);
1060e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Emitting a stub call may try to allocate (if the code is not
1061e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // already generated).  Do not allow the assembler to perform a
1062e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // garbage collection but instead return the allocation failure
1063e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // object.
1064e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Object* result = masm()->TryCallStub(&stub);
1065e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (result->IsFailure()) {
1066e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    *failure = Failure::cast(result);
1067e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    return false;
1068e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
1069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1070d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // We need to avoid using eax since that now holds the result.
1071bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Register tmp = scratch2.is(eax) ? reg : scratch2;
1072e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Emitting PopHandleScope may try to allocate.  Do not allow the
1073e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // assembler to perform a garbage collection but instead return a
1074e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // failure object.
1075e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  result = masm()->TryPopHandleScope(eax, tmp);
1076e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (result->IsFailure()) {
1077e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    *failure = Failure::cast(result);
1078e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    return false;
1079e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
1080d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ LeaveInternalFrame();
1081d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1082d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ ret(0);
1083e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  return true;
1084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadConstant(JSObject* object,
1088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        JSObject* holder,
1089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register receiver,
1090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register scratch1,
1091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register scratch2,
10923bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                        Register scratch3,
1093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Object* value,
1094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        String* name,
1095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Label* miss) {
1096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
1097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(receiver, Immediate(kSmiTagMask));
1098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, miss, not_taken);
1099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the maps haven't changed.
1101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register reg =
1102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CheckPrototypes(object, receiver, holder,
11033bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                      scratch1, scratch2, scratch3, name, miss);
1104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the constant value.
1106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(eax, Handle<Object>(value));
1107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
1108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadInterceptor(JSObject* object,
11127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                           JSObject* interceptor_holder,
1113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           LookupResult* lookup,
1114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Register receiver,
1115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Register name_reg,
1116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Register scratch1,
1117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Register scratch2,
11183bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                           Register scratch3,
1119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           String* name,
1120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Label* miss) {
11217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ASSERT(interceptor_holder->HasNamedInterceptor());
11227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
11237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Check that the receiver isn't a smi.
11257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test(receiver, Immediate(kSmiTagMask));
11267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(zero, miss, not_taken);
11277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // So far the most popular follow ups for interceptor loads are FIELD
11297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // and CALLBACKS, so inline only them, other cases may be added
11307f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // later.
11317f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  bool compile_followup_inline = false;
11327f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  if (lookup->IsProperty() && lookup->IsCacheable()) {
11337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    if (lookup->type() == FIELD) {
11347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      compile_followup_inline = true;
11357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    } else if (lookup->type() == CALLBACKS &&
11367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch        lookup->GetCallbackObject()->IsAccessorInfo() &&
11377f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch        AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
11387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      compile_followup_inline = true;
11397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    }
11407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  }
11417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  if (compile_followup_inline) {
11437f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // Compile the interceptor call, followed by inline code to load the
11447f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // property from further up the prototype chain if the call fails.
11457f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // Check that the maps haven't changed.
11467f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
11473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                          scratch1, scratch2, scratch3,
11483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                          name, miss);
11497f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
11507f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // Save necessary data before invoking an interceptor.
11527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // Requires a frame to make GC aware of pushed pointers.
11537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ EnterInternalFrame();
11547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
11567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // CALLBACKS case needs a receiver to be passed into C++ callback.
11577f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ push(receiver);
11587f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    }
11597f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ push(holder_reg);
11607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ push(name_reg);
11617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // Invoke an interceptor.  Note: map checks from receiver to
11637f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // interceptor's holder has been compiled before (see a caller
11647f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // of this method.)
11657f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    CompileCallLoadPropertyWithInterceptor(masm(),
11667f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                           receiver,
11677f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                           holder_reg,
11687f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                           name_reg,
11697f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                           interceptor_holder);
11707f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // Check if interceptor provided a value for property.  If it's
11727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // the case, return immediately.
11737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    Label interceptor_failed;
11747f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ cmp(eax, Factory::no_interceptor_result_sentinel());
11757f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ j(equal, &interceptor_failed);
11767f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ LeaveInternalFrame();
11777f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ ret(0);
11787f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11797f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ bind(&interceptor_failed);
11807f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ pop(name_reg);
11817f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ pop(holder_reg);
11827f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
11837f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ pop(receiver);
11847f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    }
11857f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11867f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ LeaveInternalFrame();
11877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11887f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // Check that the maps from interceptor's holder to lookup's holder
11897f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // haven't changed.  And load lookup's holder into holder_reg.
11907f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    if (interceptor_holder != lookup->holder()) {
11917f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      holder_reg = CheckPrototypes(interceptor_holder,
11927f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   holder_reg,
11937f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   lookup->holder(),
11947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   scratch1,
11957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   scratch2,
11963bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                   scratch3,
11977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   name,
11987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   miss);
11997f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    }
12007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
12017f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    if (lookup->type() == FIELD) {
12027f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // We found FIELD property in prototype chain of interceptor's holder.
12037f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // Retrieve a field from field's holder.
12047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      GenerateFastPropertyLoad(masm(), eax, holder_reg,
12057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                               lookup->holder(), lookup->GetFieldIndex());
12067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ ret(0);
12077f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    } else {
12087f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // We found CALLBACKS property in prototype chain of interceptor's
12097f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // holder.
12107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      ASSERT(lookup->type() == CALLBACKS);
12117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
12127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
12137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      ASSERT(callback != NULL);
12147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      ASSERT(callback->getter() != NULL);
12157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
12167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // Tail call to runtime.
12177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // Important invariant in CALLBACKS case: the code above must be
12187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // structured to never clobber |receiver| register.
12197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ pop(scratch2);  // return address
12207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ push(receiver);
12217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ push(holder_reg);
12227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ mov(holder_reg, Immediate(Handle<AccessorInfo>(callback)));
12237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ push(holder_reg);
12247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
12257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ push(name_reg);
12267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ push(scratch2);  // restore return address
12277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
12287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      ExternalReference ref =
12297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch          ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
12307f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ TailCallExternalReference(ref, 5, 1);
12317f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    }
12327f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  } else {  // !compile_followup_inline
12337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // Call the runtime system to load the interceptor.
12347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    // Check that the maps haven't changed.
12357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    Register holder_reg =
12367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch        CheckPrototypes(object, receiver, interceptor_holder,
12373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                        scratch1, scratch2, scratch3, name, miss);
12387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ pop(scratch2);  // save old return address
12397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    PushInterceptorArguments(masm(), receiver, holder_reg,
12407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                             name_reg, interceptor_holder);
12417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ push(scratch2);  // restore old return address
12427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
12437f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    ExternalReference ref = ExternalReference(
12447f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch        IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
12457f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ TailCallExternalReference(ref, 5, 1);
12467f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  }
1247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
12507f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
12517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  if (kind_ == Code::KEYED_CALL_IC) {
12527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
12537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ j(not_equal, miss, not_taken);
12547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  }
12557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
12567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
12577f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
125859151504615d929945dc59db37bf1166937748c6Steve Blockvoid CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
125959151504615d929945dc59db37bf1166937748c6Steve Block                                                   JSObject* holder,
126059151504615d929945dc59db37bf1166937748c6Steve Block                                                   String* name,
126159151504615d929945dc59db37bf1166937748c6Steve Block                                                   Label* miss) {
126259151504615d929945dc59db37bf1166937748c6Steve Block  ASSERT(holder->IsGlobalObject());
126359151504615d929945dc59db37bf1166937748c6Steve Block
126459151504615d929945dc59db37bf1166937748c6Steve Block  // Get the number of arguments.
126559151504615d929945dc59db37bf1166937748c6Steve Block  const int argc = arguments().immediate();
126659151504615d929945dc59db37bf1166937748c6Steve Block
126759151504615d929945dc59db37bf1166937748c6Steve Block  // Get the receiver from the stack.
126859151504615d929945dc59db37bf1166937748c6Steve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
126959151504615d929945dc59db37bf1166937748c6Steve Block
127059151504615d929945dc59db37bf1166937748c6Steve Block  // If the object is the holder then we know that it's a global
127159151504615d929945dc59db37bf1166937748c6Steve Block  // object which can only happen for contextual calls. In this case,
127259151504615d929945dc59db37bf1166937748c6Steve Block  // the receiver cannot be a smi.
127359151504615d929945dc59db37bf1166937748c6Steve Block  if (object != holder) {
127459151504615d929945dc59db37bf1166937748c6Steve Block    __ test(edx, Immediate(kSmiTagMask));
127559151504615d929945dc59db37bf1166937748c6Steve Block    __ j(zero, miss, not_taken);
127659151504615d929945dc59db37bf1166937748c6Steve Block  }
127759151504615d929945dc59db37bf1166937748c6Steve Block
127859151504615d929945dc59db37bf1166937748c6Steve Block  // Check that the maps haven't changed.
127959151504615d929945dc59db37bf1166937748c6Steve Block  CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
128059151504615d929945dc59db37bf1166937748c6Steve Block}
128159151504615d929945dc59db37bf1166937748c6Steve Block
128259151504615d929945dc59db37bf1166937748c6Steve Block
128359151504615d929945dc59db37bf1166937748c6Steve Blockvoid CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
128459151504615d929945dc59db37bf1166937748c6Steve Block                                                    JSFunction* function,
128559151504615d929945dc59db37bf1166937748c6Steve Block                                                    Label* miss) {
128659151504615d929945dc59db37bf1166937748c6Steve Block  // Get the value from the cell.
128759151504615d929945dc59db37bf1166937748c6Steve Block  __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
128859151504615d929945dc59db37bf1166937748c6Steve Block  __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
128959151504615d929945dc59db37bf1166937748c6Steve Block
129059151504615d929945dc59db37bf1166937748c6Steve Block  // Check that the cell contains the same function.
129159151504615d929945dc59db37bf1166937748c6Steve Block  if (Heap::InNewSpace(function)) {
129259151504615d929945dc59db37bf1166937748c6Steve Block    // We can't embed a pointer to a function in new space so we have
129359151504615d929945dc59db37bf1166937748c6Steve Block    // to verify that the shared function info is unchanged. This has
129459151504615d929945dc59db37bf1166937748c6Steve Block    // the nice side effect that multiple closures based on the same
129559151504615d929945dc59db37bf1166937748c6Steve Block    // function can all use this call IC. Before we load through the
129659151504615d929945dc59db37bf1166937748c6Steve Block    // function, we have to verify that it still is a function.
129759151504615d929945dc59db37bf1166937748c6Steve Block    __ test(edi, Immediate(kSmiTagMask));
129859151504615d929945dc59db37bf1166937748c6Steve Block    __ j(zero, miss, not_taken);
129959151504615d929945dc59db37bf1166937748c6Steve Block    __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
130059151504615d929945dc59db37bf1166937748c6Steve Block    __ j(not_equal, miss, not_taken);
130159151504615d929945dc59db37bf1166937748c6Steve Block
130259151504615d929945dc59db37bf1166937748c6Steve Block    // Check the shared function info. Make sure it hasn't changed.
130359151504615d929945dc59db37bf1166937748c6Steve Block    __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
130459151504615d929945dc59db37bf1166937748c6Steve Block           Immediate(Handle<SharedFunctionInfo>(function->shared())));
130559151504615d929945dc59db37bf1166937748c6Steve Block    __ j(not_equal, miss, not_taken);
130659151504615d929945dc59db37bf1166937748c6Steve Block  } else {
130759151504615d929945dc59db37bf1166937748c6Steve Block    __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function)));
130859151504615d929945dc59db37bf1166937748c6Steve Block    __ j(not_equal, miss, not_taken);
130959151504615d929945dc59db37bf1166937748c6Steve Block  }
131059151504615d929945dc59db37bf1166937748c6Steve Block}
131159151504615d929945dc59db37bf1166937748c6Steve Block
131259151504615d929945dc59db37bf1166937748c6Steve Block
1313bb769b257e753aafcbd96767abb2abc645eaa20cBen MurdochObject* CallStubCompiler::GenerateMissBranch() {
1314bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
1315bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  if (obj->IsFailure()) return obj;
1316bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1317bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  return obj;
13187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
13197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
13207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
1321402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei PopescuObject* CallStubCompiler::CompileCallField(JSObject* object,
1322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           JSObject* holder,
1323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           int index,
1324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           String* name) {
1325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1326e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1327e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1328e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1329e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1330e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
1333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateNameCheck(name, &miss);
13357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
1336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver from the stack.
1337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int argc = arguments().immediate();
1338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
1341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
1342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &miss, not_taken);
1343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do the right check and compute the holder register.
13453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
13463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                                 name, &miss);
1347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
1349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the function really is a function.
1351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edi, Immediate(kSmiTagMask));
1352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &miss, not_taken);
1353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
1354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
1355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Patch the receiver on the stack with the global proxy if
1357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // necessary.
1358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (object->IsGlobalObject()) {
1359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function.
1364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
1365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle call cache miss.
1367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
1368bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Object* obj = GenerateMissBranch();
1369bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  if (obj->IsFailure()) return obj;
1370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
1372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(FIELD, name);
1373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13766ded16be15dd865a9b21ea304d5273c8be299c87Steve BlockObject* CallStubCompiler::CompileArrayPushCall(Object* object,
13776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                               JSObject* holder,
137859151504615d929945dc59db37bf1166937748c6Steve Block                                               JSGlobalPropertyCell* cell,
13796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                               JSFunction* function,
138059151504615d929945dc59db37bf1166937748c6Steve Block                                               String* name) {
13816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ----------- S t a t e -------------
13826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx                 : name
13836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- esp[0]              : return address
13846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
13856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ...
13866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- esp[(argc + 1) * 4] : receiver
13876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // -----------------------------------
13886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
13896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // If object is not an array, bail out to regular call.
139059151504615d929945dc59db37bf1166937748c6Steve Block  if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
13916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
13926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label miss;
13936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
13947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateNameCheck(name, &miss);
13957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
13966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Get the receiver from the stack.
13976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  const int argc = arguments().immediate();
13986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
13996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the receiver isn't a smi.
14016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(edx, Immediate(kSmiTagMask));
14026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(zero, &miss);
14036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  CheckPrototypes(JSObject::cast(object), edx,
14056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                  holder, ebx,
14063bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                  eax, edi, name, &miss);
14076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  if (argc == 0) {
14096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Noop, return the length.
14106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
14116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ ret((argc + 1) * kPointerSize);
14126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  } else {
1413756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    Label call_builtin;
1414756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
14156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Get the elements array of the object.
14166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
14176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
1418756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    // Check that the elements are in fast mode and writable.
14196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
14206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block           Immediate(Factory::fixed_array_map()));
1421756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    __ j(not_equal, &call_builtin);
14226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (argc == 1) {  // Otherwise fall through to call builtin.
1424756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      Label exit, with_write_barrier, attempt_to_grow_elements;
14256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // Get the array's length into eax and calculate new length.
14276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
14286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      STATIC_ASSERT(kSmiTagSize == 1);
14296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      STATIC_ASSERT(kSmiTag == 0);
14306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ add(Operand(eax), Immediate(Smi::FromInt(argc)));
14316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // Get the element's length into ecx.
14336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
14346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // Check if we could survive without allocation.
14366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ cmp(eax, Operand(ecx));
14376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ j(greater, &attempt_to_grow_elements);
14386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // Save new length.
14406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
14416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // Push the element.
14436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ lea(edx, FieldOperand(ebx,
14446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               eax, times_half_pointer_size,
14456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               FixedArray::kHeaderSize - argc * kPointerSize));
14466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(ecx, Operand(esp, argc * kPointerSize));
14476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(Operand(edx, 0), ecx);
14486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // Check if value is a smi.
14506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ test(ecx, Immediate(kSmiTagMask));
14517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ j(not_zero, &with_write_barrier);
14526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ bind(&exit);
14546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ ret((argc + 1) * kPointerSize);
14556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ bind(&with_write_barrier);
14576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ InNewSpace(ebx, ecx, equal, &exit);
14596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      __ RecordWriteHelper(ebx, edx, ecx);
14616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ ret((argc + 1) * kPointerSize);
14626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ bind(&attempt_to_grow_elements);
14646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      ExternalReference new_space_allocation_top =
14656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block          ExternalReference::new_space_allocation_top_address();
14666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      ExternalReference new_space_allocation_limit =
14676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block          ExternalReference::new_space_allocation_limit_address();
14686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      const int kAllocationDelta = 4;
14706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // Load top.
14716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
14726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // Check if it's the end of elements.
14746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ lea(edx, FieldOperand(ebx,
14756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               eax, times_half_pointer_size,
14766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               FixedArray::kHeaderSize - argc * kPointerSize));
14776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ cmp(edx, Operand(ecx));
14786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ j(not_equal, &call_builtin);
14796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ add(Operand(ecx), Immediate(kAllocationDelta * kPointerSize));
14806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
14816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ j(above, &call_builtin);
14826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // We fit and could grow elements.
14846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
14856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(ecx, Operand(esp, argc * kPointerSize));
14866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // Push the argument...
14886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(Operand(edx, 0), ecx);
14896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // ... and fill the rest with holes.
14906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      for (int i = 1; i < kAllocationDelta; i++) {
14916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov(Operand(edx, i * kPointerSize),
14926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block               Immediate(Factory::the_hole_value()));
14936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      }
14946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // Restore receiver to edx as finish sequence assumes it's here.
14966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
14976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
14986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      // Increment element's and array's sizes.
14996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ add(FieldOperand(ebx, FixedArray::kLengthOffset),
15007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch             Immediate(Smi::FromInt(kAllocationDelta)));
15016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
15026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15037f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      // Elements are in new space, so write barrier is not required.
15046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ ret((argc + 1) * kPointerSize);
15056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
15066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
1507756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    __ bind(&call_builtin);
15086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
15096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                 argc + 1,
15106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                 1);
15116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
15126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&miss);
1514bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Object* obj = GenerateMissBranch();
1515bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  if (obj->IsFailure()) return obj;
15166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Return the generated code.
151825f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  return GetCode(function);
15196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
15206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15226ded16be15dd865a9b21ea304d5273c8be299c87Steve BlockObject* CallStubCompiler::CompileArrayPopCall(Object* object,
15236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                              JSObject* holder,
152459151504615d929945dc59db37bf1166937748c6Steve Block                                              JSGlobalPropertyCell* cell,
15256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                              JSFunction* function,
152659151504615d929945dc59db37bf1166937748c6Steve Block                                              String* name) {
15276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ----------- S t a t e -------------
15286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx                 : name
15296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- esp[0]              : return address
15306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
15316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ...
15326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- esp[(argc + 1) * 4] : receiver
15336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // -----------------------------------
15346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // If object is not an array, bail out to regular call.
153659151504615d929945dc59db37bf1166937748c6Steve Block  if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
15376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label miss, return_undefined, call_builtin;
15396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateNameCheck(name, &miss);
15417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Get the receiver from the stack.
15436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  const int argc = arguments().immediate();
15446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
15456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the receiver isn't a smi.
15476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(edx, Immediate(kSmiTagMask));
15486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(zero, &miss);
15496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  CheckPrototypes(JSObject::cast(object), edx,
15506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                  holder, ebx,
15513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                  eax, edi, name, &miss);
15526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Get the elements array of the object.
15546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
15556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
1556756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Check that the elements are in fast mode and writable.
15576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
15586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block         Immediate(Factory::fixed_array_map()));
1559756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  __ j(not_equal, &call_builtin);
15606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Get the array's length into ecx and calculate new length.
15626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
15636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ sub(Operand(ecx), Immediate(Smi::FromInt(1)));
15646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(negative, &return_undefined);
15656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Get the last element.
15676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  STATIC_ASSERT(kSmiTagSize == 1);
15686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  STATIC_ASSERT(kSmiTag == 0);
15696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(eax, FieldOperand(ebx,
15706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                           ecx, times_half_pointer_size,
15716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                           FixedArray::kHeaderSize));
15726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
15736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(equal, &call_builtin);
15746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Set the array's length.
15766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
15776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Fill with the hole.
15796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(FieldOperand(ebx,
15806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                      ecx, times_half_pointer_size,
15816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                      FixedArray::kHeaderSize),
15826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block         Immediate(Factory::the_hole_value()));
15836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret((argc + 1) * kPointerSize);
15846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&return_undefined);
15866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(eax, Immediate(Factory::undefined_value()));
15876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret((argc + 1) * kPointerSize);
15886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&call_builtin);
15906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
15916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               argc + 1,
15926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               1);
15936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&miss);
1595bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Object* obj = GenerateMissBranch();
1596bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  if (obj->IsFailure()) return obj;
15977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Return the generated code.
15997f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  return GetCode(function);
16007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
16017f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16027f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
160359151504615d929945dc59db37bf1166937748c6Steve BlockObject* CallStubCompiler::CompileStringCharCodeAtCall(
160459151504615d929945dc59db37bf1166937748c6Steve Block    Object* object,
160559151504615d929945dc59db37bf1166937748c6Steve Block    JSObject* holder,
160659151504615d929945dc59db37bf1166937748c6Steve Block    JSGlobalPropertyCell* cell,
160759151504615d929945dc59db37bf1166937748c6Steve Block    JSFunction* function,
160859151504615d929945dc59db37bf1166937748c6Steve Block    String* name) {
16097f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ----------- S t a t e -------------
16107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ecx                 : function name
16117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[0]              : return address
16127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
16137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ...
16147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc + 1) * 4] : receiver
16157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // -----------------------------------
16167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
1617756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // If object is not a string, bail out to regular call.
161859151504615d929945dc59db37bf1166937748c6Steve Block  if (!object->IsString() || cell != NULL) return Heap::undefined_value();
1619756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
16207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  const int argc = arguments().immediate();
16217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label miss;
16237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label index_out_of_range;
16247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateNameCheck(name, &miss);
16257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Check that the maps starting from the prototype haven't changed.
16277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateDirectLoadGlobalFunctionPrototype(masm(),
16287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                            Context::STRING_FUNCTION_INDEX,
16297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                            eax);
1630756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  ASSERT(object != holder);
16317f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
16323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                  ebx, edx, edi, name, &miss);
16337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register receiver = ebx;
16357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register index = edi;
16367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register scratch = edx;
16377f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register result = eax;
16387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
16397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  if (argc > 0) {
16407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
16417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  } else {
16427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ Set(index, Immediate(Factory::undefined_value()));
16437f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  }
16447f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16457f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  StringCharCodeAtGenerator char_code_at_generator(receiver,
16467f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                                   index,
16477f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                                   scratch,
16487f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                                   result,
16497f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                                   &miss,  // When not a string.
16507f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                                   &miss,  // When not a number.
16517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                                   &index_out_of_range,
16527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                                   STRING_INDEX_IS_NUMBER);
16537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  char_code_at_generator.GenerateFast(masm());
16547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ ret((argc + 1) * kPointerSize);
16557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ICRuntimeCallHelper call_helper;
16577f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  char_code_at_generator.GenerateSlow(masm(), call_helper);
16587f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16597f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&index_out_of_range);
16607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ Set(eax, Immediate(Factory::nan_value()));
16617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ ret((argc + 1) * kPointerSize);
16627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16637f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&miss);
1664bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Object* obj = GenerateMissBranch();
1665bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  if (obj->IsFailure()) return obj;
16667f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16677f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Return the generated code.
16687f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  return GetCode(function);
16697f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
16707f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen MurdochObject* CallStubCompiler::CompileStringCharAtCall(Object* object,
16737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                                  JSObject* holder,
167459151504615d929945dc59db37bf1166937748c6Steve Block                                                  JSGlobalPropertyCell* cell,
16757f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                                  JSFunction* function,
167659151504615d929945dc59db37bf1166937748c6Steve Block                                                  String* name) {
16777f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ----------- S t a t e -------------
16787f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ecx                 : function name
16797f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[0]              : return address
16807f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
16817f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ...
16827f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc + 1) * 4] : receiver
16837f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // -----------------------------------
16847f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
1685756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // If object is not a string, bail out to regular call.
168659151504615d929945dc59db37bf1166937748c6Steve Block  if (!object->IsString() || cell != NULL) return Heap::undefined_value();
1687756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
16887f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  const int argc = arguments().immediate();
16897f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16907f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label miss;
16917f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label index_out_of_range;
16927f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16937f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateNameCheck(name, &miss);
16947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
16957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Check that the maps starting from the prototype haven't changed.
16967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateDirectLoadGlobalFunctionPrototype(masm(),
16977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                            Context::STRING_FUNCTION_INDEX,
16987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                            eax);
1699756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  ASSERT(object != holder);
17007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
17013bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                  ebx, edx, edi, name, &miss);
17027f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
17037f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register receiver = eax;
17047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register index = edi;
17057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register scratch1 = ebx;
17067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register scratch2 = edx;
17077f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register result = eax;
17087f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
17097f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  if (argc > 0) {
17107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
17117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  } else {
17127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ Set(index, Immediate(Factory::undefined_value()));
17137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  }
17147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
17157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  StringCharAtGenerator char_at_generator(receiver,
17167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          index,
17177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          scratch1,
17187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          scratch2,
17197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          result,
17207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          &miss,  // When not a string.
17217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          &miss,  // When not a number.
17227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          &index_out_of_range,
17237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          STRING_INDEX_IS_NUMBER);
17247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  char_at_generator.GenerateFast(masm());
17257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ ret((argc + 1) * kPointerSize);
17267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
17277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ICRuntimeCallHelper call_helper;
17287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  char_at_generator.GenerateSlow(masm(), call_helper);
17297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
17307f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&index_out_of_range);
17317f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ Set(eax, Immediate(Factory::empty_string()));
17327f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ ret((argc + 1) * kPointerSize);
17337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
17347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&miss);
1735bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Object* obj = GenerateMissBranch();
1736bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  if (obj->IsFailure()) return obj;
17376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
17386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Return the generated code.
173925f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  return GetCode(function);
17406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
17416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
17426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
174359151504615d929945dc59db37bf1166937748c6Steve BlockObject* CallStubCompiler::CompileStringFromCharCodeCall(
174459151504615d929945dc59db37bf1166937748c6Steve Block    Object* object,
174559151504615d929945dc59db37bf1166937748c6Steve Block    JSObject* holder,
174659151504615d929945dc59db37bf1166937748c6Steve Block    JSGlobalPropertyCell* cell,
174759151504615d929945dc59db37bf1166937748c6Steve Block    JSFunction* function,
174859151504615d929945dc59db37bf1166937748c6Steve Block    String* name) {
174959151504615d929945dc59db37bf1166937748c6Steve Block  // ----------- S t a t e -------------
175059151504615d929945dc59db37bf1166937748c6Steve Block  //  -- ecx                 : function name
175159151504615d929945dc59db37bf1166937748c6Steve Block  //  -- esp[0]              : return address
175259151504615d929945dc59db37bf1166937748c6Steve Block  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
175359151504615d929945dc59db37bf1166937748c6Steve Block  //  -- ...
175459151504615d929945dc59db37bf1166937748c6Steve Block  //  -- esp[(argc + 1) * 4] : receiver
175559151504615d929945dc59db37bf1166937748c6Steve Block  // -----------------------------------
175659151504615d929945dc59db37bf1166937748c6Steve Block
175759151504615d929945dc59db37bf1166937748c6Steve Block  const int argc = arguments().immediate();
175859151504615d929945dc59db37bf1166937748c6Steve Block
175959151504615d929945dc59db37bf1166937748c6Steve Block  // If the object is not a JSObject or we got an unexpected number of
176059151504615d929945dc59db37bf1166937748c6Steve Block  // arguments, bail out to the regular call.
176159151504615d929945dc59db37bf1166937748c6Steve Block  if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
176259151504615d929945dc59db37bf1166937748c6Steve Block
176359151504615d929945dc59db37bf1166937748c6Steve Block  Label miss;
176459151504615d929945dc59db37bf1166937748c6Steve Block  GenerateNameCheck(name, &miss);
176559151504615d929945dc59db37bf1166937748c6Steve Block
176659151504615d929945dc59db37bf1166937748c6Steve Block  if (cell == NULL) {
176759151504615d929945dc59db37bf1166937748c6Steve Block    __ mov(edx, Operand(esp, 2 * kPointerSize));
176859151504615d929945dc59db37bf1166937748c6Steve Block
176959151504615d929945dc59db37bf1166937748c6Steve Block    STATIC_ASSERT(kSmiTag == 0);
177059151504615d929945dc59db37bf1166937748c6Steve Block    __ test(edx, Immediate(kSmiTagMask));
177159151504615d929945dc59db37bf1166937748c6Steve Block    __ j(zero, &miss);
177259151504615d929945dc59db37bf1166937748c6Steve Block
177359151504615d929945dc59db37bf1166937748c6Steve Block    CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name,
177459151504615d929945dc59db37bf1166937748c6Steve Block                    &miss);
177559151504615d929945dc59db37bf1166937748c6Steve Block  } else {
177659151504615d929945dc59db37bf1166937748c6Steve Block    ASSERT(cell->value() == function);
177759151504615d929945dc59db37bf1166937748c6Steve Block    GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
177859151504615d929945dc59db37bf1166937748c6Steve Block    GenerateLoadFunctionFromCell(cell, function, &miss);
177959151504615d929945dc59db37bf1166937748c6Steve Block  }
178059151504615d929945dc59db37bf1166937748c6Steve Block
178159151504615d929945dc59db37bf1166937748c6Steve Block  // Load the char code argument.
178259151504615d929945dc59db37bf1166937748c6Steve Block  Register code = ebx;
178359151504615d929945dc59db37bf1166937748c6Steve Block  __ mov(code, Operand(esp, 1 * kPointerSize));
178459151504615d929945dc59db37bf1166937748c6Steve Block
178559151504615d929945dc59db37bf1166937748c6Steve Block  // Check the code is a smi.
178659151504615d929945dc59db37bf1166937748c6Steve Block  Label slow;
178759151504615d929945dc59db37bf1166937748c6Steve Block  STATIC_ASSERT(kSmiTag == 0);
178859151504615d929945dc59db37bf1166937748c6Steve Block  __ test(code, Immediate(kSmiTagMask));
178959151504615d929945dc59db37bf1166937748c6Steve Block  __ j(not_zero, &slow);
179059151504615d929945dc59db37bf1166937748c6Steve Block
179159151504615d929945dc59db37bf1166937748c6Steve Block  // Convert the smi code to uint16.
179259151504615d929945dc59db37bf1166937748c6Steve Block  __ and_(code, Immediate(Smi::FromInt(0xffff)));
179359151504615d929945dc59db37bf1166937748c6Steve Block
179459151504615d929945dc59db37bf1166937748c6Steve Block  StringCharFromCodeGenerator char_from_code_generator(code, eax);
179559151504615d929945dc59db37bf1166937748c6Steve Block  char_from_code_generator.GenerateFast(masm());
179659151504615d929945dc59db37bf1166937748c6Steve Block  __ ret(2 * kPointerSize);
179759151504615d929945dc59db37bf1166937748c6Steve Block
179859151504615d929945dc59db37bf1166937748c6Steve Block  ICRuntimeCallHelper call_helper;
179959151504615d929945dc59db37bf1166937748c6Steve Block  char_from_code_generator.GenerateSlow(masm(), call_helper);
180059151504615d929945dc59db37bf1166937748c6Steve Block
180159151504615d929945dc59db37bf1166937748c6Steve Block  // Tail call the full function. We do not have to patch the receiver
180259151504615d929945dc59db37bf1166937748c6Steve Block  // because the function makes no use of it.
180359151504615d929945dc59db37bf1166937748c6Steve Block  __ bind(&slow);
180459151504615d929945dc59db37bf1166937748c6Steve Block  __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
180559151504615d929945dc59db37bf1166937748c6Steve Block
180659151504615d929945dc59db37bf1166937748c6Steve Block  __ bind(&miss);
180759151504615d929945dc59db37bf1166937748c6Steve Block  // ecx: function name.
180859151504615d929945dc59db37bf1166937748c6Steve Block  Object* obj = GenerateMissBranch();
180959151504615d929945dc59db37bf1166937748c6Steve Block  if (obj->IsFailure()) return obj;
181059151504615d929945dc59db37bf1166937748c6Steve Block
181159151504615d929945dc59db37bf1166937748c6Steve Block  // Return the generated code.
181259151504615d929945dc59db37bf1166937748c6Steve Block  return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
181359151504615d929945dc59db37bf1166937748c6Steve Block}
181459151504615d929945dc59db37bf1166937748c6Steve Block
181559151504615d929945dc59db37bf1166937748c6Steve Block
1816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* CallStubCompiler::CompileCallConstant(Object* object,
1817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              JSObject* holder,
1818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              JSFunction* function,
1819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              String* name,
1820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              CheckType check) {
1821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1822e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1823e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1824e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1825e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1826e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
18286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  SharedFunctionInfo* function_info = function->shared();
18306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  if (function_info->HasCustomCallGenerator()) {
183125f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen    const int id = function_info->custom_call_generator_id();
183259151504615d929945dc59db37bf1166937748c6Steve Block    Object* result = CompileCustomCall(
183359151504615d929945dc59db37bf1166937748c6Steve Block        id, object, holder, NULL, function, name);
18346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // undefined means bail out to regular compiler.
183559151504615d929945dc59db37bf1166937748c6Steve Block    if (!result->IsUndefined()) return result;
18366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
18376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label miss_in_smi_check;
1839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateNameCheck(name, &miss_in_smi_check);
18417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
1842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver from the stack.
1843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int argc = arguments().immediate();
1844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
1847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (check != NUMBER_CHECK) {
1848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ test(edx, Immediate(kSmiTagMask));
18496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ j(zero, &miss_in_smi_check, not_taken);
1850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure that it's okay not to patch the on stack receiver
1853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // unless we're doing a receiver map check.
1854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
1855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1856402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  CallOptimization optimization(function);
1857402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  int depth = kInvalidProtoDepth;
18586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label miss;
1859402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
1860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (check) {
1861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case RECEIVER_MAP_CHECK:
1862402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ IncrementCounter(&Counters::call_const, 1);
1863402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
1864402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
1865402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        depth = optimization.GetPrototypeDepthOfExpectedType(
1866402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu            JSObject::cast(object), holder);
1867402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      }
1868402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
1869402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      if (depth != kInvalidProtoDepth) {
1870402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        __ IncrementCounter(&Counters::call_const_fast_api, 1);
1871402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        ReserveSpaceForFastApiCall(masm(), eax);
1872402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      }
1873402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
1874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Check that the maps haven't changed.
1875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CheckPrototypes(JSObject::cast(object), edx, holder,
18763bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                      ebx, eax, edi, name, depth, &miss);
1877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Patch the receiver on the stack with the global proxy if
1879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // necessary.
1880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (object->IsGlobalObject()) {
1881402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        ASSERT(depth == kInvalidProtoDepth);
1882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
1886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case STRING_CHECK:
1888e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      if (!function->IsBuiltin()) {
1889e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // Calling non-builtins with a value as receiver requires boxing.
1890e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ jmp(&miss);
1891e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      } else {
1892e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // Check that the object is a string or a symbol.
18937f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch        __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
1894e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ j(above_equal, &miss, not_taken);
1895e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // Check that the maps starting from the prototype haven't changed.
18967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch        GenerateDirectLoadGlobalFunctionPrototype(
18977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch            masm(), Context::STRING_FUNCTION_INDEX, eax);
1898e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
18993bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                        ebx, edx, edi, name, &miss);
1900e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      }
1901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
1902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case NUMBER_CHECK: {
1904e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      if (!function->IsBuiltin()) {
1905e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // Calling non-builtins with a value as receiver requires boxing.
1906e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ jmp(&miss);
1907e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      } else {
1908e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        Label fast;
1909e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // Check that the object is a smi or a heap number.
1910e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ test(edx, Immediate(kSmiTagMask));
1911e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ j(zero, &fast, taken);
1912e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
1913e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ j(not_equal, &miss, not_taken);
1914e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ bind(&fast);
1915e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // Check that the maps starting from the prototype haven't changed.
19167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch        GenerateDirectLoadGlobalFunctionPrototype(
19177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch            masm(), Context::NUMBER_FUNCTION_INDEX, eax);
1918e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
19193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                        ebx, edx, edi, name, &miss);
1920e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      }
1921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
1922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case BOOLEAN_CHECK: {
1925e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      if (!function->IsBuiltin()) {
1926e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // Calling non-builtins with a value as receiver requires boxing.
1927e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ jmp(&miss);
1928e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      } else {
1929e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        Label fast;
1930e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // Check that the object is a boolean.
1931e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ cmp(edx, Factory::true_value());
1932e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ j(equal, &fast, taken);
1933e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ cmp(edx, Factory::false_value());
1934e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ j(not_equal, &miss, not_taken);
1935e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ bind(&fast);
1936e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // Check that the maps starting from the prototype haven't changed.
19377f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch        GenerateDirectLoadGlobalFunctionPrototype(
19387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch            masm(), Context::BOOLEAN_FUNCTION_INDEX, eax);
1939e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
19403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                        ebx, edx, edi, name, &miss);
1941e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      }
1942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
1943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default:
1946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      UNREACHABLE();
1947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1949402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  if (depth != kInvalidProtoDepth) {
1950402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    GenerateFastApiCall(masm(), optimization, argc);
1951402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  } else {
1952402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1953402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
1954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle call cache miss.
1956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
1957402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  if (depth != kInvalidProtoDepth) {
1958402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    FreeSpaceForFastApiCall(masm(), eax);
1959402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
19606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&miss_in_smi_check);
1961bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Object* obj = GenerateMissBranch();
1962bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  if (obj->IsFailure()) return obj;
1963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
196525f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  return GetCode(function);
1966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1969402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei PopescuObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
1970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                 JSObject* holder,
1971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                 String* name) {
1972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1973e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1974e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1975e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1976e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1977e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
1980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19817f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateNameCheck(name, &miss);
19827f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
1983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the number of arguments.
1984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int argc = arguments().immediate();
1985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LookupResult lookup;
1987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LookupPostInterceptor(holder, name, &lookup);
1988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver from the stack.
1990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1992402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  CallInterceptorCompiler compiler(this, arguments(), ecx);
1993402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  compiler.Compile(masm(),
1994402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                   object,
1995402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                   holder,
1996402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                   name,
1997402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                   &lookup,
1998402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                   edx,
1999402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                   ebx,
2000402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                   edi,
20013bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                   eax,
2002402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                   &miss);
2003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore receiver.
2005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the function really is a function.
2008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(eax, Immediate(kSmiTagMask));
2009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &miss, not_taken);
2010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Patch the receiver on the stack with the global proxy if
2014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // necessary.
2015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (object->IsGlobalObject()) {
2016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function.
2021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edi, eax);
2022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
2023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle load cache miss.
2025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2026bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Object* obj = GenerateMissBranch();
2027bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  if (obj->IsFailure()) return obj;
2028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(INTERCEPTOR, name);
2031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
2035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            GlobalObject* holder,
2036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            JSGlobalPropertyCell* cell,
2037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            JSFunction* function,
2038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            String* name) {
2039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2040e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
2041e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
2042e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
2043e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
2044e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
2045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
204659151504615d929945dc59db37bf1166937748c6Steve Block
204759151504615d929945dc59db37bf1166937748c6Steve Block  SharedFunctionInfo* function_info = function->shared();
204859151504615d929945dc59db37bf1166937748c6Steve Block  if (function_info->HasCustomCallGenerator()) {
204959151504615d929945dc59db37bf1166937748c6Steve Block    const int id = function_info->custom_call_generator_id();
205059151504615d929945dc59db37bf1166937748c6Steve Block    Object* result = CompileCustomCall(
205159151504615d929945dc59db37bf1166937748c6Steve Block        id, object, holder, cell, function, name);
205259151504615d929945dc59db37bf1166937748c6Steve Block    // undefined means bail out to regular compiler.
205359151504615d929945dc59db37bf1166937748c6Steve Block    if (!result->IsUndefined()) return result;
205459151504615d929945dc59db37bf1166937748c6Steve Block  }
205559151504615d929945dc59db37bf1166937748c6Steve Block
2056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
20587f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateNameCheck(name, &miss);
20597f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
2060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the number of arguments.
2061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int argc = arguments().immediate();
2062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
206359151504615d929945dc59db37bf1166937748c6Steve Block  GenerateGlobalReceiverCheck(object, holder, name, &miss);
2064e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
206559151504615d929945dc59db37bf1166937748c6Steve Block  GenerateLoadFunctionFromCell(cell, function, &miss);
2066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Patch the receiver on the stack with the global proxy.
2068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (object->IsGlobalObject()) {
2069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Setup the context (function already in edi).
2074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Jump to the cached code (tail call).
2077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::call_global_inline, 1);
2078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(function->is_compiled());
2079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> code(function->code());
2080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount expected(function->shared()->formal_parameter_count());
2081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeCode(code, expected, arguments(),
2082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
2083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle call cache miss.
2085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::call_global_inline_miss, 1);
2087bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Object* obj = GenerateMissBranch();
2088bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  if (obj->IsFailure()) return obj;
2089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(NORMAL, name);
2092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* StoreStubCompiler::CompileStoreField(JSObject* object,
2096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             int index,
2097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             Map* transition,
2098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             String* name) {
2099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
2101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
21024515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- edx    : receiver
2103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate store field code.  Trashes the name register.
2108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateStoreField(masm(),
2109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     object,
2110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     index,
2111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     transition,
21124515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                     edx, ecx, ebx,
2113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     &miss);
2114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle store cache miss.
2116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ecx, Immediate(Handle<String>(name)));  // restore name
2118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(ic, RelocInfo::CODE_TARGET);
2120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
2127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                AccessorInfo* callback,
2128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                String* name) {
2129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
2131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
21324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- edx    : receiver
2133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
21384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ test(edx, Immediate(kSmiTagMask));
2139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &miss, not_taken);
2140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the map of the object hasn't changed.
21424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Immediate(Handle<Map>(object->map())));
2144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform global security token check if needed.
2147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (object->IsJSGlobalProxy()) {
21484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ CheckAccessGlobalProxy(edx, ebx, &miss);
2149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Stub never generated for non-global objects that require access
2152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // checks.
2153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);  // remove the return address
21564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ push(edx);  // receiver
2157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(Immediate(Handle<AccessorInfo>(callback)));  // callback info
2158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);  // name
2159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);  // value
2160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);  // restore return address
2161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to the runtime system.
2163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference store_callback_property =
2164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
21656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(store_callback_property, 4, 1);
2166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle store cache miss.
2168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(ic, RelocInfo::CODE_TARGET);
2171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(CALLBACKS, name);
2174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
2178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   String* name) {
2179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
2181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
21824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- edx    : receiver
2183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
21884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ test(edx, Immediate(kSmiTagMask));
2189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &miss, not_taken);
2190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the map of the object hasn't changed.
21924515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Immediate(Handle<Map>(receiver->map())));
2194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform global security token check if needed.
2197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (receiver->IsJSGlobalProxy()) {
21984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ CheckAccessGlobalProxy(edx, ebx, &miss);
2199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Stub never generated for non-global objects that require access
2202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // checks.
2203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);  // remove the return address
22064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ push(edx);  // receiver
2207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);  // name
2208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);  // value
2209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);  // restore return address
2210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to the runtime system.
2212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference store_ic_property =
2213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
22146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(store_ic_property, 3, 1);
2215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle store cache miss.
2217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(ic, RelocInfo::CODE_TARGET);
2220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(INTERCEPTOR, name);
2223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
2227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              JSGlobalPropertyCell* cell,
2228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              String* name) {
2229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
2231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
22324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- edx    : receiver
2233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the map of the global has not changed.
22384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Immediate(Handle<Map>(object->map())));
2240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Store the value in the cell.
2243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
2244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax);
2245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the value (register eax).
2247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::named_store_global_inline, 1);
2248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
2249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle store cache miss.
2251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
2253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(ic, RelocInfo::CODE_TARGET);
2255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(NORMAL, name);
2258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
2262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                  int index,
2263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                  Map* transition,
2264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                  String* name) {
2265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
22676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
22686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
2269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_store_field, 1);
2274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the name has not changed.
2276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
2277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate store field code.  Trashes the name register.
2280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateStoreField(masm(),
2281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     object,
2282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     index,
2283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     transition,
2284402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                     edx, ecx, ebx,
2285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     &miss);
2286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle store cache miss.
2288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ DecrementCounter(&Counters::keyed_store_field, 1);
2290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
2291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(ic, RelocInfo::CODE_TARGET);
2292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
22986ded16be15dd865a9b21ea304d5273c8be299c87Steve BlockObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
22996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                                 JSObject* object,
23006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                                 JSObject* last) {
23016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ----------- S t a t e -------------
23026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- eax    : receiver
23036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : name
23046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- esp[0] : return address
23056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // -----------------------------------
23066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label miss;
23076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
23086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the receiver isn't a smi.
23096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(eax, Immediate(kSmiTagMask));
23106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(zero, &miss, not_taken);
23116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
23128defd9ff6930b4e24729971a61cf7469daf119beSteve Block  ASSERT(last->IsGlobalObject() || last->HasFastProperties());
23138defd9ff6930b4e24729971a61cf7469daf119beSteve Block
23146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check the maps of the full prototype chain. Also check that
23156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // global property cells up to (but not including) the last object
23166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // in the prototype chain are empty.
23173bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CheckPrototypes(object, eax, last, ebx, edx, edi, name, &miss);
23186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
23196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // If the last object in the prototype chain is a global object,
23206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // check that the global property cell is empty.
23216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  if (last->IsGlobalObject()) {
23226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    Object* cell = GenerateCheckPropertyCell(masm(),
23236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                             GlobalObject::cast(last),
23246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                             name,
23256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                             edx,
23266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                             &miss);
23276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (cell->IsFailure()) return cell;
23286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
23296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
23306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Return undefined if maps of the full prototype chain are still the
23316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // same and no global property with this name contains a value.
23326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(eax, Factory::undefined_value());
23336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret(0);
23346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
23356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&miss);
23366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
23376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
23386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Return the generated code.
23396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  return GetCode(NONEXISTENT, Heap::empty_string());
23406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
23416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
2342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* LoadStubCompiler::CompileLoadField(JSObject* object,
2344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           JSObject* holder,
2345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           int index,
2346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           String* name) {
2347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2348402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
2349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
2350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
23543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  GenerateLoadField(object, holder, eax, ebx, edx, edi, index, name, &miss);
2355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
2357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(FIELD, name);
2360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2363e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon ClarkeObject* LoadStubCompiler::CompileLoadCallback(String* name,
2364e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                              JSObject* object,
2365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              JSObject* holder,
2366e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                              AccessorInfo* callback) {
2367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2368402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
2369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
2370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2374e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Failure* failure = Failure::InternalError();
23753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  bool success = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, edi,
2376e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                      callback, name, &miss, &failure);
2377e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (!success) return failure;
2378e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
2379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
2381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(CALLBACKS, name);
2384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
2388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              JSObject* holder,
2389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              Object* value,
2390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              String* name) {
2391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2392402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
2393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
2394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
23983bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  GenerateLoadConstant(object, holder, eax, ebx, edx, edi, value, name, &miss);
2399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
2401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(CONSTANT_FUNCTION, name);
2404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
2408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                 JSObject* holder,
2409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                 String* name) {
2410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2411402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
2412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
2413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LookupResult lookup;
2418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LookupPostInterceptor(holder, name, &lookup);
2419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(368): Compile in the whole chain: all the interceptors in
2421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // prototypes and ultimate answer.
2422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadInterceptor(receiver,
2423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          holder,
2424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &lookup,
2425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          eax,
2426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          ecx,
2427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          edx,
2428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          ebx,
24293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                          edi,
2430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          name,
2431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &miss);
2432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
2435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(INTERCEPTOR, name);
2438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
2442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            GlobalObject* holder,
2443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            JSGlobalPropertyCell* cell,
2444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            String* name,
2445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            bool is_dont_delete) {
2446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2447402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
2448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
2449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the object is the holder then we know that it's a global
2454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // object which can only happen for contextual loads. In this case,
2455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the receiver cannot be a smi.
2456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (object != holder) {
2457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ test(eax, Immediate(kSmiTagMask));
2458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(zero, &miss, not_taken);
2459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the maps haven't changed.
24623bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CheckPrototypes(object, eax, holder, ebx, edx, edi, name, &miss);
2463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the value from the cell.
2465402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
2466402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
2467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for deleted property if property can actually be deleted.
2469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!is_dont_delete) {
2470402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ cmp(ebx, Factory::the_hole_value());
2471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(equal, &miss, not_taken);
2472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (FLAG_debug_code) {
2473402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ cmp(ebx, Factory::the_hole_value());
2474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ Check(not_equal, "DontDelete cells can't contain the hole");
2475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::named_load_global_inline, 1);
2478402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, ebx);
2479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
2480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
2483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::LOAD_IC);
2484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(NORMAL, name);
2487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
2491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                JSObject* receiver,
2492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                JSObject* holder,
2493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                int index) {
2494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2495402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
2496402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
2497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_field, 1);
2502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the name has not changed.
2504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
2505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
25073bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss);
2508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ DecrementCounter(&Counters::keyed_load_field, 1);
2511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(FIELD, name);
2515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
2519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   JSObject* receiver,
2520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   JSObject* holder,
2521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   AccessorInfo* callback) {
2522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2523402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
2524402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
2525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_callback, 1);
2530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the name has not changed.
2532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
2533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2535e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Failure* failure = Failure::InternalError();
25363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  bool success = GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx, edi,
2537e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                      callback, name, &miss, &failure);
2538e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (!success) return failure;
2539e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
2540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ DecrementCounter(&Counters::keyed_load_callback, 1);
2542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(CALLBACKS, name);
2546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
2550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   JSObject* receiver,
2551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   JSObject* holder,
2552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   Object* value) {
2553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2554402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
2555402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
2556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
2561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the name has not changed.
2563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
2564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
25663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi,
2567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       value, name, &miss);
2568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
2570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(CONSTANT_FUNCTION, name);
2574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
2578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                      JSObject* holder,
2579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                      String* name) {
2580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2581402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
2582402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
2583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
2588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the name has not changed.
2590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
2591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LookupResult lookup;
2594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LookupPostInterceptor(holder, name, &lookup);
2595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadInterceptor(receiver,
2596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          holder,
2597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &lookup,
2598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          edx,
2599402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                          eax,
2600402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                          ecx,
2601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          ebx,
26023bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                          edi,
2603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          name,
2604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &miss);
2605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
2607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(INTERCEPTOR, name);
2611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
2617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2618402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
2619402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
2620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_array_length, 1);
2625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the name has not changed.
2627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
2628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2630402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateLoadArrayLength(masm(), edx, ecx, &miss);
2631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ DecrementCounter(&Counters::keyed_load_array_length, 1);
2633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(CALLBACKS, name);
2637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
2641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2642402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
2643402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
2644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_string_length, 1);
2649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the name has not changed.
2651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
2652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2654402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss);
2655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ DecrementCounter(&Counters::keyed_load_string_length, 1);
2657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(CALLBACKS, name);
2661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
2665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2666402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
2667402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
2668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
2671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
2673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the name has not changed.
2675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
2676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
2677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2678402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss);
2679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
2680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
2681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode(CALLBACKS, name);
2685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Specialized stub for constructing objects from functions which only have only
2689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// simple assignments of the form this.x = ...; in their body.
2690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* ConstructStubCompiler::CompileConstructStub(
2691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    SharedFunctionInfo* shared) {
2692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
2693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax : argc
2694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- edi : constructor
2695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
2696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[4] : last argument
2697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
2698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label generic_stub_call;
2699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT
2700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check to see whether there are any break points in the function code. If
2701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // there are jump to the generic constructor stub which calls the actual
2702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // code for the function thereby hitting the break points.
2703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset));
2705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(ebx, Factory::undefined_value());
2706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &generic_stub_call, not_taken);
2707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
2708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the initial map and verify that it is in fact a map.
2710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
2711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Will both indicate a NULL and a Smi.
2712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(kSmiTagMask));
2713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &generic_stub_call);
2714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(ebx, MAP_TYPE, ecx);
2715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &generic_stub_call);
2716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
2718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cannot construct functions this way.
2719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edi: constructor
2720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ebx: initial map
2721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
2722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Assert(not_equal, "Function constructed by construct stub.");
2723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
2724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Now allocate the JSObject on the heap by moving the new space allocation
2726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // top forward.
2727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edi: constructor
2728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ebx: initial map
2729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
2730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ shl(ecx, kPointerSizeLog2);
2731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ AllocateInNewSpace(ecx,
2732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        edx,
2733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        ecx,
2734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        no_reg,
2735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        &generic_stub_call,
2736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        NO_ALLOCATION_FLAGS);
2737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Allocated the JSObject, now initialize the fields and add the heap tag.
2739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ebx: initial map
2740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edx: JSObject (untagged)
2741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(Operand(edx, JSObject::kMapOffset), ebx);
2742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ebx, Factory::empty_fixed_array());
2743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
2744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(Operand(edx, JSObject::kElementsOffset), ebx);
2745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the allocated object to the stack. This is the object that will be
2747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // returned (after it is tagged).
2748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(edx);
2749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: argc
2751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edx: JSObject (untagged)
2752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the address of the first in-object property into edx.
2753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(edx, Operand(edx, JSObject::kHeaderSize));
2754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate the location of the first argument. The stack contains the
2755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // allocated object and the return address on top of the argc arguments.
2756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
2757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Use edi for holding undefined which is used in several places below.
2759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edi, Factory::undefined_value());
2760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: argc
2762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ecx: first argument
2763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edx: first in-object property of the JSObject
2764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edi: undefined
2765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fill the initialized properties with a constant value or a passed argument
2766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // depending on the this.x = ...; assignment in the function.
2767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < shared->this_property_assignments_count(); i++) {
2768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (shared->IsThisPropertyAssignmentArgument(i)) {
2769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Check if the argument assigned to the property is actually passed.
2770e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      // If argument is not passed the property is set to undefined,
2771e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      // otherwise find it on the stack.
2772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      int arg_number = shared->GetThisPropertyAssignmentArgument(i);
2773e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      __ mov(ebx, edi);
2774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ cmp(eax, arg_number);
2775e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      if (CpuFeatures::IsSupported(CMOV)) {
2776e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        CpuFeatures::Scope use_cmov(CMOV);
2777e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize));
2778e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      } else {
2779e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        Label not_passed;
2780e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ j(below_equal, &not_passed);
2781e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
2782e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ bind(&not_passed);
2783e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      }
2784e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      // Store value in the property.
2785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ mov(Operand(edx, i * kPointerSize), ebx);
2786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
2787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Set the property to the constant value.
2788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
2789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ mov(Operand(edx, i * kPointerSize), Immediate(constant));
2790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fill the unused in-object property fields with undefined.
2794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = shared->this_property_assignments_count();
2795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block       i < shared->CalculateInObjectProperties();
2796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block       i++) {
2797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(Operand(edx, i * kPointerSize), edi);
2798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Move argc to ebx and retrieve and tag the JSObject to return.
2801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ebx, eax);
2802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(eax);
2803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ or_(Operand(eax), Immediate(kHeapObjectTag));
2804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Remove caller arguments and receiver from the stack and return.
2806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ecx);
2807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
2808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);
2809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::constructed_objects, 1);
2810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::constructed_objects_stub, 1);
2811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
2812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Jump to the generic stub in case the specialized code cannot handle the
2814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // construction.
2815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&generic_stub_call);
2816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
2817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> generic_construct_stub(code);
2818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
2819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return the generated code.
2821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return GetCode();
2822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
2826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
2828f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
2829f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#endif  // V8_TARGET_ARCH_IA32
2830