ic-arm.cc revision e0cee9b3ed82e2391fd85d118aeaa4ea361c687d
17ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// Copyright 2006-2008 the V8 project authors. All rights reserved.
27ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// Redistribution and use in source and binary forms, with or without
37ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// modification, are permitted provided that the following conditions are
47ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// met:
57ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//
67ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//     * Redistributions of source code must retain the above copyright
77ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//       notice, this list of conditions and the following disclaimer.
87ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//     * Redistributions in binary form must reproduce the above
97ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//       copyright notice, this list of conditions and the following
107ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//       disclaimer in the documentation and/or other materials provided
117ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//       with the distribution.
127ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//     * Neither the name of Google Inc. nor the names of its
137ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//       contributors may be used to endorse or promote products derived
147ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//       from this software without specific prior written permission.
157ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//
167ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
287ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman#include "v8.h"
297ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
307ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman#if defined(V8_TARGET_ARCH_ARM)
317ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
327ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman#include "assembler-arm.h"
337ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman#include "code-stubs.h"
347ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman#include "codegen-inl.h"
357ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman#include "disasm.h"
367ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman#include "ic-inl.h"
377ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman#include "runtime.h"
387ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman#include "stub-cache.h"
397ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
407ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmannamespace v8 {
417ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmannamespace internal {
427ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
437ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
447ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// ----------------------------------------------------------------------------
4557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer// Static IC stub generators.
4657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer//
477ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
487ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman#define __ ACCESS_MASM(masm)
497ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
507ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
517ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmanstatic void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
527ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                            Register type,
537ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                            Label* global_object) {
547ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Register usage:
557ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //   type: holds the receiver instance type on entry.
567ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ cmp(type, Operand(JS_GLOBAL_OBJECT_TYPE));
577ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(eq, global_object);
587ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ cmp(type, Operand(JS_BUILTINS_OBJECT_TYPE));
597ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(eq, global_object);
60190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ cmp(type, Operand(JS_GLOBAL_PROXY_TYPE));
617ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(eq, global_object);
62190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer}
63190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
64190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
65190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// Generated code falls through if the receiver is a regular non-global
66190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// JS object with slow properties and no interceptors.
67190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramerstatic void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
68190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                                  Register receiver,
6957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                                  Register elements,
7057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                                  Register t0,
7157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                                  Register t1,
7257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                                  Label* miss) {
7357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Register usage:
7457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //   receiver: holds the receiver on entry and is unchanged.
7557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //   elements: holds the property dictionary on fall through.
767ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Scratch registers:
777ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //   t0: used to holds the receiver map.
787ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //   t1: used to holds the receiver instance type, receiver bit mask and
79e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  //       elements map.
80e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer
8157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Check that the receiver isn't a smi.
82e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ tst(receiver, Operand(kSmiTagMask));
83e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ b(eq, miss);
84e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer
85e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // Check that the receiver is a valid JS object.
86e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ CompareObjectType(receiver, t0, t1, FIRST_JS_OBJECT_TYPE);
87190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ b(lt, miss);
88190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
89190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // If this assert fails, we have to check upper bound too.
9057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
91e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer
927ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateGlobalInstanceTypeCheck(masm, t1, miss);
937ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
947ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check that the global object does not require access checks.
957ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
967ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
977ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                     (1 << Map::kHasNamedInterceptor)));
987ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(ne, miss);
997ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
100e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
1017ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
102e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
103e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ cmp(t1, ip);
104e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ b(ne, miss);
105e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer}
106e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer
107e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer
108e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer// Probe the string dictionary in the |elements| register. Jump to the
109e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer// |done| label if a property with the given name is found. Jump to
110e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer// the |miss| label otherwise.
111e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramerstatic void GenerateStringDictionaryProbes(MacroAssembler* masm,
112e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer                                           Label* miss,
11357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                           Label* done,
1147ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                           Register elements,
1157ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                           Register name,
1167ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                           Register scratch1,
117190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                           Register scratch2) {
118190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Assert that name contains a string.
11957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (FLAG_debug_code) __ AbortIfNotString(name);
1207ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
1217ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Compute the capacity mask.
1227ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  const int kCapacityOffset = StringDictionary::kHeaderSize +
1237ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      StringDictionary::kCapacityIndex * kPointerSize;
1247ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
1257ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize));  // convert smi to int
1267ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ sub(scratch1, scratch1, Operand(1));
1277ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
1287ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  const int kElementsStartOffset = StringDictionary::kHeaderSize +
1297ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      StringDictionary::kElementsStartIndex * kPointerSize;
1307ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
1317ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Generate an unrolled loop that performs a few probes before
1327ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // giving up. Measurements done on Gmail indicate that 2 probes
1337ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // cover ~93% of loads from dictionaries.
1347ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  static const int kProbes = 4;
1357ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  for (int i = 0; i < kProbes; i++) {
1367ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    // Compute the masked index: (hash + i + i * i) & mask.
1377ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
1387ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    if (i > 0) {
1397ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      // Add the probe offset (i + i * i) left shifted to avoid right shifting
1407ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      // the hash in a separate instruction. The value hash + i + i * i is right
1417ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      // shifted in the following and instruction.
1427ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      ASSERT(StringDictionary::GetProbeOffset(i) <
1437ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman             1 << (32 - String::kHashFieldOffset));
1447ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      __ add(scratch2, scratch2, Operand(
1457ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman          StringDictionary::GetProbeOffset(i) << String::kHashShift));
14657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    }
14757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
14857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
14957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    // Scale the index by multiplying by the element size.
1507ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    ASSERT(StringDictionary::kEntrySize == 3);
1517ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    // scratch2 = scratch2 * 3.
1527ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
1537ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
1547ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    // Check if the key is identical to the name.
1557ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ add(scratch2, elements, Operand(scratch2, LSL, 2));
1567ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
1577ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ cmp(name, Operand(ip));
1587ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    if (i != kProbes - 1) {
1597ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      __ b(eq, done);
1607ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    } else {
1617ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      __ b(ne, miss);
1627ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    }
1637ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  }
1647ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman}
1657ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
1667ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
1677ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// Helper function used from LoadIC/CallIC GenerateNormal.
1687ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//
1697ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// elements: Property dictionary. It is not clobbered if a jump to the miss
1707ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//           label is done.
1717ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// name:     Property name. It is not clobbered if a jump to the miss label is
172190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer//           done
1737ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// result:   Register for the result. It is only updated if a jump to the miss
1747ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman//           label is not done. Can be the same as elements or name clobbering
175190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer//           one of these in the case of not jumping to the miss label.
176190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// The two scratch registers need to be different from elements, name and
177190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// result.
178190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// The generated code assumes that the receiver has slow properties,
179190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// is not a global object and does not have interceptors.
180190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramerstatic void GenerateDictionaryLoad(MacroAssembler* masm,
18157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   Label* miss,
18257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   Register elements,
1837ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                   Register name,
184e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer                                   Register result,
185e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer                                   Register scratch1,
18657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   Register scratch2) {
187e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // Main use of the scratch registers.
188e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // scratch1: Used as temporary and to hold the capacity of the property
189e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  //           dictionary.
1907ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // scratch2: Used as temporary.
1917ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Label done;
1927ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
1937ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Probe the dictionary.
1947ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateStringDictionaryProbes(masm,
1957ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                 miss,
1967ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                 &done,
1977ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                 elements,
1987ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                 name,
1997ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                 scratch1,
200e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer                                 scratch2);
201190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
202e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // If probing finds an entry check that the value is a normal
203190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // property.
204e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ bind(&done);  // scratch2 == elements + 4 * index
205190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  const int kElementsStartOffset = StringDictionary::kHeaderSize +
206190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer      StringDictionary::kElementsStartIndex * kPointerSize;
207190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
208190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
209190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
210190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ b(ne, miss);
211190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
2127ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Get the value at the masked, scaled index and return.
213e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ ldr(result,
2147ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman         FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
215e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer}
2167ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
217e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer
2187ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// Helper function used from StoreIC::GenerateNormal.
219e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer//
22057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer// elements: Property dictionary. It is not clobbered if a jump to the miss
22157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer//           label is done.
222df40664a63a91a1ab4b40c7f2d356cf255071d56Edward O'Callaghan// name:     Property name. It is not clobbered if a jump to the miss label is
223df40664a63a91a1ab4b40c7f2d356cf255071d56Edward O'Callaghan//           done
224190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// value:    The value to store.
2257ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// The two scratch registers need to be different from elements, name and
226190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// result.
22757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer// The generated code assumes that the receiver has slow properties,
2287ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// is not a global object and does not have interceptors.
229e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramerstatic void GenerateDictionaryStore(MacroAssembler* masm,
230e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer                                    Label* miss,
231e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer                                    Register elements,
232e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer                                    Register name,
233e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer                                    Register value,
234190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                    Register scratch1,
235190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                    Register scratch2) {
23657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Main use of the scratch registers.
237190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // scratch1: Used as temporary and to hold the capacity of the property
238190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //           dictionary.
239e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // scratch2: Used as temporary.
240e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  Label done;
241190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
242190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Probe the dictionary.
243190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  GenerateStringDictionaryProbes(masm,
244190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                 miss,
245190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                 &done,
246190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                 elements,
247190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                 name,
248190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                 scratch1,
249190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                 scratch2);
250190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
251190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // If probing finds an entry in the dictionary check that the value
252e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // is a normal property that is not read only.
253e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ bind(&done);  // scratch2 == elements + 4 * index
254e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  const int kElementsStartOffset = StringDictionary::kHeaderSize +
255e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer      StringDictionary::kElementsStartIndex * kPointerSize;
256e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
257e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  const int kTypeAndReadOnlyMask
258190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer      = (PropertyDetails::TypeField::mask() |
25957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer         PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
2607ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
26157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ tst(scratch1, Operand(kTypeAndReadOnlyMask));
26257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ b(ne, miss);
26357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
264190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Store the value at the masked, scaled index and return.
265190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  const int kValueOffset = kElementsStartOffset + kPointerSize;
266190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
2677ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ str(value, MemOperand(scratch2));
268190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
2697ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Update the write barrier. Make sure not to clobber the value.
2707ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ mov(scratch1, value);
2717ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ RecordWrite(elements, scratch2, scratch1);
27257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
27357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
27457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
27557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramerstatic void GenerateNumberDictionaryLoad(MacroAssembler* masm,
27657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                         Label* miss,
27757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                         Register elements,
27857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                         Register key,
27957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                         Register result,
28057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                         Register t0,
28157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                         Register t1,
282e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer                                         Register t2) {
283e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // Register use:
28457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //
28557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // elements - holds the slow-case elements of the receiver on entry.
2867ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //            Unchanged unless 'result' is the same register.
287190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //
28857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // key      - holds the smi key on entry.
289e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  //            Unchanged unless 'result' is the same register.
29057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //
29157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // result   - holds the result on exit if the load succeeded.
29257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //            Allowed to be the same as 'key' or 'result'.
293e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  //            Unchanged on bailout so 'key' or 'result' can be used
29457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //            in further computation.
29557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //
29657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Scratch registers:
29757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //
2987ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // t0 - holds the untagged key on entry and holds the hash once computed.
2997ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //
3007ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // t1 - used to hold the capacity mask of the dictionary
3017ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //
3027ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // t2 - used for the index into the dictionary.
3037ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Label done;
3047ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
3057ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Compute the hash code from the untagged key.  This must be kept in sync
3067ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // with ComputeIntegerHash in utils.h.
3077ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //
3087ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // hash = ~hash + (hash << 15);
3097ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ mvn(t1, Operand(t0));
3107ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ add(t0, t1, Operand(t0, LSL, 15));
3117ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // hash = hash ^ (hash >> 12);
3127ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ eor(t0, t0, Operand(t0, LSR, 12));
313e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // hash = hash + (hash << 2);
314e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ add(t0, t0, Operand(t0, LSL, 2));
3157ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // hash = hash ^ (hash >> 4);
31621aa347c2816aa8fc635ad05c5ab786234b32c7eChris Lattner  __ eor(t0, t0, Operand(t0, LSR, 4));
31757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // hash = hash * 2057;
3187ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ mov(t1, Operand(2057));
3197ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ mul(t0, t0, t1);
3207ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // hash = hash ^ (hash >> 16);
3217ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ eor(t0, t0, Operand(t0, LSR, 16));
3227ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
3237ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Compute the capacity mask.
324e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
325e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ mov(t1, Operand(t1, ASR, kSmiTagSize));  // convert smi to int
3267ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ sub(t1, t1, Operand(1));
3277ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
3287ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Generate an unrolled loop that performs a few probes before giving up.
3297ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  static const int kProbes = 4;
3307ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  for (int i = 0; i < kProbes; i++) {
3317ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    // Use t2 for index calculations and keep the hash intact in t0.
3327ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ mov(t2, t0);
3337ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    // Compute the masked index: (hash + i + i * i) & mask.
3347ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    if (i > 0) {
3357ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      __ add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i)));
3367ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    }
3377ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ and_(t2, t2, Operand(t1));
3387ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
33957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    // Scale the index by multiplying by the element size.
3407ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    ASSERT(NumberDictionary::kEntrySize == 3);
3417ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ add(t2, t2, Operand(t2, LSL, 1));  // t2 = t2 * 3
34257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
34357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    // Check if the key is identical to the name.
3447ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
3457ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset));
3467ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ cmp(key, Operand(ip));
3477ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    if (i != kProbes - 1) {
3487ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      __ b(eq, &done);
34957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    } else {
35057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      __ b(ne, miss);
35157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    }
35257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  }
35357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
35457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&done);
3557ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check that the value is a normal property.
35657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // t2: elements + (index * kPointerSize)
35757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  const int kDetailsOffset =
35857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
3597ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(t1, FieldMemOperand(t2, kDetailsOffset));
3607ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
3617ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(ne, miss);
36257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
3637ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Get the value at the masked, scaled index and return.
3647ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  const int kValueOffset =
3657ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      NumberDictionary::kElementsStartOffset + kPointerSize;
3667ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(result, FieldMemOperand(t2, kValueOffset));
3677ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman}
3687ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
36957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
37057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramervoid LoadIC::GenerateArrayLength(MacroAssembler* masm) {
37157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // ----------- S t a t e -------------
37257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r2    : name
37357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- lr    : return address
37457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r0    : receiver
37557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- sp[0] : receiver
3767ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
37757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Label miss;
37857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
37957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss);
38057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&miss);
38157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
382e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer}
3837ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
3847ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
385190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramervoid LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
386190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // ----------- S t a t e -------------
387190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- r2    : name
3887ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- lr    : return address
389190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- r0    : receiver
390190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- sp[0] : receiver
391190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // -----------------------------------
392190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  Label miss;
393190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
394190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss,
395190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                         support_wrappers);
3967ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Cache miss: Jump to runtime.
3977ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ bind(&miss);
39857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
39957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
40057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
40157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
40257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramervoid LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
40357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // ----------- S t a t e -------------
40457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r2    : name
40557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- lr    : return address
40657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r0    : receiver
407190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- sp[0] : receiver
4087ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
409190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  Label miss;
41057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
411190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss);
412190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ bind(&miss);
4137ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
4147ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman}
4157ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
4167ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
4177ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// Checks the receiver for special cases (value type, slow case bits).
418190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// Falls through for regular JS object.
419190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramerstatic void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
420190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                           Register receiver,
421190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                           Register map,
422190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                           Register scratch,
423190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                           int interceptor_bit,
424190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                           Label* slow) {
425190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Check that the object isn't a smi.
426190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ JumpIfSmi(receiver, slow);
427190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Get the map of the receiver.
428190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
429190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Check bit field.
430190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
431190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ tst(scratch,
432190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer         Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
433190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ b(ne, slow);
434190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Check that the object is some kind of JS object EXCEPT JS Value type.
435190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // In the case that the object is a value-wrapper object,
436190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // we enter the runtime system to make sure that indexing into string
437190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // objects work as intended.
438190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
439190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
440190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ cmp(scratch, Operand(JS_OBJECT_TYPE));
441190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ b(lt, slow);
442190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer}
443190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
444190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
445190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// Loads an indexed element from a fast case array.
446190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// If not_fast_array is NULL, doesn't perform the elements map check.
447190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramerstatic void GenerateFastArrayLoad(MacroAssembler* masm,
4487ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                  Register receiver,
449190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                  Register key,
450190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                  Register elements,
4517ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                  Register scratch1,
45257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                  Register scratch2,
453190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                  Register result,
454190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                  Label* not_fast_array,
455190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                  Label* out_of_range) {
456190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Register use:
4577ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //
45857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // receiver - holds the receiver on entry.
459190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //            Unchanged unless 'result' is the same register.
460190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //
4617ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // key      - holds the smi key on entry.
4627ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //            Unchanged unless 'result' is the same register.
4637ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //
4647ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // elements - holds the elements of the receiver on exit.
4657ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //
4667ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // result   - holds the result on exit if the load succeeded.
4677ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //            Allowed to be the the same as 'receiver' or 'key'.
4687ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //            Unchanged on bailout so 'receiver' and 'key' can be safely
4697ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //            used by further computation.
470e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  //
4717ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Scratch registers:
4727ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //
4737ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // scratch1 - used to hold elements map and elements length.
474e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  //            Holds the elements map if not_fast_array branch is taken.
4757ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //
4767ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // scratch2 - used to hold the loaded value.
4777ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
47857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
47957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (not_fast_array != NULL) {
48057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    // Check that the object is in fast mode and writable.
48157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
48257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
48357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    __ cmp(scratch1, ip);
4847ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ b(ne, not_fast_array);
48557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  } else {
48657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    __ AssertFastElements(elements);
48757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  }
48857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Check that the key (index) is within bounds.
48957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
49057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ cmp(key, Operand(scratch1));
491e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ b(hs, out_of_range);
492190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Fast case: Do the load.
493e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4947ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // The key is a smi.
49557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
49657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ ldr(scratch2,
49757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer         MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
498e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
4997ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ cmp(scratch2, ip);
5007ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // In case the loaded value is the_hole we have to consult GetProperty
5017ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // to ensure the prototype chain is searched.
50257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ b(eq, out_of_range);
50357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ mov(result, scratch2);
50457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
50557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
506e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer
507e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer// Checks whether a key is an array index string or a symbol string.
50857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer// Falls through if a key is a symbol.
5097ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmanstatic void GenerateKeyStringCheck(MacroAssembler* masm,
5107ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                   Register key,
51157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   Register map,
51257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   Register hash,
51357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   Label* index_string,
51457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   Label* not_symbol) {
515e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // The key is not a smi.
51657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Is it a string?
5177ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
5187ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(ge, not_symbol);
519e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer
52057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Is the string an array index, with cached numeric value?
5217ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
5227ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
5237ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(eq, index_string);
5247ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
5257ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Is the string a symbol?
5267ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // map: key map
5277ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
5287ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  ASSERT(kSymbolTag != 0);
5297ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ tst(hash, Operand(kIsSymbolMask));
5307ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(eq, not_symbol);
5317ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman}
5327ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
5337ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
5347ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// Defined in ic.cc.
5357ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha BrukmanObject* CallIC_Miss(Arguments args);
5367ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
5377ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman// The generated code does not accept smi keys.
538190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer// The generated code falls through if both probes miss.
5397ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmanstatic void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
5407ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                          int argc,
5417ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                          Code::Kind kind) {
5427ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // ----------- S t a t e -------------
5437ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r1    : receiver
5447ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r2    : name
5457ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
546190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  Label number, non_number, non_string, boolean, probe, miss;
547190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
548190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Probe the stub cache.
5497ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Code::Flags flags = Code::ComputeFlags(kind,
5507ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                         NOT_IN_LOOP,
5517ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                         MONOMORPHIC,
5527ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                         Code::kNoExtraICState,
5537ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                         NORMAL,
5547ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                         argc);
55557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
55657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
55757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // If the stub cache probing failed, the receiver might be a value.
55857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // For value objects, we use the map of the prototype objects for
55957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // the corresponding JSValue for the cache and that is what we need
56057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // to probe.
5617ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //
5627ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check for number.
56357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ tst(r1, Operand(kSmiTagMask));
56457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ b(eq, &number);
5657ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE);
5667ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(ne, &non_number);
5677ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ bind(&number);
5687ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  StubCompiler::GenerateLoadGlobalFunctionPrototype(
5697ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      masm, Context::NUMBER_FUNCTION_INDEX, r1);
5707ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(&probe);
5717ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
5727ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check for string.
5737ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ bind(&non_number);
5747ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ cmp(r3, Operand(FIRST_NONSTRING_TYPE));
5757ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(hs, &non_string);
5767ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  StubCompiler::GenerateLoadGlobalFunctionPrototype(
577190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer      masm, Context::STRING_FUNCTION_INDEX, r1);
578190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ b(&probe);
579190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
580190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Check for boolean.
581190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ bind(&non_string);
582190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ LoadRoot(ip, Heap::kTrueValueRootIndex);
583190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ cmp(r1, ip);
584190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ b(eq, &boolean);
585190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ LoadRoot(ip, Heap::kFalseValueRootIndex);
586190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ cmp(r1, ip);
587190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ b(ne, &miss);
588190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ bind(&boolean);
589190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  StubCompiler::GenerateLoadGlobalFunctionPrototype(
590190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer      masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
591190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
592190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Probe the stub cache for the value object.
59357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&probe);
59457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
59557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
59657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&miss);
59757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
59857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
59957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
60057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramerstatic void GenerateFunctionTailCall(MacroAssembler* masm,
60157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                     int argc,
60257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                     Label* miss,
60357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                     Register scratch) {
60457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // r1: function
60557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
60657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Check that the value isn't a smi.
6077ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ tst(r1, Operand(kSmiTagMask));
6087ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(eq, miss);
6097ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6107ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check that the value is a JSFunction.
6117ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
6127ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(ne, miss);
6137ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6147ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Invoke the function.
6157ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  ParameterCount actual(argc);
6167ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ InvokeFunction(r1, actual, JUMP_FUNCTION);
617190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer}
618190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
61957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
620190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramerstatic void GenerateCallNormal(MacroAssembler* masm, int argc) {
6217ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // ----------- S t a t e -------------
6227ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r2    : name
6237ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- lr    : return address
6247ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
6257ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Label miss;
6267ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6277ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Get the receiver of the function from the stack into r1.
62857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
62957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
6307ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateStringDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
6317ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6327ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // r0: elements
6337ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Search the dictionary - put result in register r1.
6347ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
6357ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6367ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateFunctionTailCall(masm, argc, &miss, r4);
6377ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6387ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ bind(&miss);
6397ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman}
6407ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6417ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6427ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmanstatic void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
6437ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // ----------- S t a t e -------------
6447ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r2    : name
645190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- lr    : return address
6467ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
6477ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6487ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  if (id == IC::kCallIC_Miss) {
6497ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ IncrementCounter(&Counters::call_miss, 1, r3, r4);
6507ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  } else {
6517ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ IncrementCounter(&Counters::keyed_call_miss, 1, r3, r4);
6527ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  }
6537ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6547ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Get the receiver of the function from the stack.
6557ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(r3, MemOperand(sp, argc * kPointerSize));
6567ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6577ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ EnterInternalFrame();
6587ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
65957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Push the receiver and the name of the function.
6607ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ Push(r3, r2);
66157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
6627ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Call the entry.
66357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ mov(r0, Operand(2));
66457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ mov(r1, Operand(ExternalReference(IC_Utility(id))));
66557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
66657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  CEntryStub stub(1);
6677ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ CallStub(&stub);
6687ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6697ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Move result to r1 and leave the internal frame.
6707ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ mov(r1, Operand(r0));
6717ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ LeaveInternalFrame();
6727ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6737ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check if the receiver is a global object of some sort.
6747ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // This can happen only for regular CallIC but not KeyedCallIC.
6757ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  if (id == IC::kCallIC_Miss) {
6767ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    Label invoke, global;
6777ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ ldr(r2, MemOperand(sp, argc * kPointerSize));  // receiver
6787ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ tst(r2, Operand(kSmiTagMask));
6797ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ b(eq, &invoke);
6807ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
6817ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ b(eq, &global);
6827ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
6837ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ b(ne, &invoke);
6847ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6857ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    // Patch the receiver on the stack.
6867ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ bind(&global);
6877ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
6887ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ str(r2, MemOperand(sp, argc * kPointerSize));
6897ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman    __ bind(&invoke);
6907ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  }
6917ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6927ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Invoke the function.
6937ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  ParameterCount actual(argc);
6947ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ InvokeFunction(r1, actual, JUMP_FUNCTION);
6957ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman}
6967ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6977ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
6987ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmanvoid CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
6997ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // ----------- S t a t e -------------
7007ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r2    : name
7017ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- lr    : return address
7027ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
7037ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
7047ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
7057ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman}
7067ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
7077ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
7087ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmanvoid CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
7097ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // ----------- S t a t e -------------
7107ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r2    : name
7117ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- lr    : return address
7127ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
7137ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
714e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // Get the receiver of the function from the stack into r1.
715e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
7167ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
7177ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateMiss(masm, argc);
718e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer}
719e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer
720e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer
7217ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmanvoid CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
72257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // ----------- S t a t e -------------
723e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  //  -- r2    : name
7247ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- lr    : return address
7257ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
726190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
727190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  GenerateCallNormal(masm, argc);
7287ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateMiss(masm, argc);
7297ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman}
7307ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
7317ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
7327ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmanvoid KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
7337ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // ----------- S t a t e -------------
7347ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r2    : name
7357ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- lr    : return address
7367ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
7377ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
738190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
739190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer}
740190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
74157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
742190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramervoid KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
743190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // ----------- S t a t e -------------
7447ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r2    : name
745190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- lr    : return address
746190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // -----------------------------------
747190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
748190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Get the receiver of the function from the stack into r1.
749190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
750190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
751190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  Label do_call, slow_call, slow_load, slow_reload_receiver;
752190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  Label check_number_dictionary, check_string, lookup_monomorphic_cache;
753190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  Label index_smi, index_string;
754190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
755190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Check that the key is a smi.
756190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ JumpIfNotSmi(r2, &check_string);
757190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ bind(&index_smi);
758190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Now the key is known to be a smi. This place is also jumped to from below
7597ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // where a numeric string is converted to a smi.
7607ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
7617ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateKeyedLoadReceiverCheck(
7627ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
76357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
76457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateFastArrayLoad(
76557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
76657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1, r0, r3);
76757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
76857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&do_call);
76957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // receiver in r1 is not used after this point.
77057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // r2: key
77157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // r1: function
77257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateFunctionTailCall(masm, argc, &slow_call, r0);
77357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
77457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&check_number_dictionary);
77557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // r2: key
77657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // r3: elements map
77757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // r4: elements
77857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Check whether the elements is a number dictionary.
77957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
78057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ cmp(r3, ip);
78157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ b(ne, &slow_load);
78257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ mov(r0, Operand(r2, ASR, kSmiTagSize));
78357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // r0: untagged index
78457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateNumberDictionaryLoad(masm, &slow_load, r4, r2, r1, r0, r3, r5);
78557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1, r0, r3);
78657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ jmp(&do_call);
78757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
78857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&slow_load);
78957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // This branch is taken when calling KeyedCallIC_Miss is neither required
79057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // nor beneficial.
79157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1, r0, r3);
79257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ EnterInternalFrame();
79357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ push(r2);  // save the key
79457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ Push(r1, r2);  // pass the receiver and the key
79557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ CallRuntime(Runtime::kKeyedGetProperty, 2);
79657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ pop(r2);  // restore the key
79757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ LeaveInternalFrame();
79857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ mov(r1, r0);
79957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ jmp(&do_call);
80057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
80157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&check_string);
80257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
80357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
80457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // The key is known to be a symbol.
80557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // If the receiver is a regular JS object with slow properties then do
80657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // a quick inline probe of the receiver's dictionary.
80757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Otherwise do the monomorphic cache probe.
80857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateKeyedLoadReceiverCheck(
80957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
81057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
81157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
81257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
8137ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
81457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ cmp(r3, ip);
81557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ b(ne, &lookup_monomorphic_cache);
8167ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
8177ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
81857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3);
81957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ jmp(&do_call);
82057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
82157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&lookup_monomorphic_cache);
82257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1, r0, r3);
82357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
82457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Fall through on miss.
8257ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
826e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ bind(&slow_call);
827e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // This branch is taken if:
8287ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // - the receiver requires boxing or access check,
8297ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // - the key is neither smi nor symbol,
8307ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // - the value loaded is not a function,
8317ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // - there is hope that the runtime will create a monomorphic call stub
8327ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //   that will get fetched next time.
8337ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ IncrementCounter(&Counters::keyed_call_generic_slow, 1, r0, r3);
8347ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateMiss(masm, argc);
8357ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
8367ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ bind(&index_string);
8377ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ IndexFromHash(r3, r2);
8387ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Now jump to the place where smi keys are handled.
83957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ jmp(&index_smi);
84057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
84157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
84257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
84357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramervoid KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
84457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // ----------- S t a t e -------------
84557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r2    : name
84657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- lr    : return address
84757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // -----------------------------------
84857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
84957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Check if the name is a string.
85057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Label miss;
85157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ tst(r2, Operand(kSmiTagMask));
85257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ b(eq, &miss);
85357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ IsObjectJSStringType(r2, r0, &miss);
85457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
85557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateCallNormal(masm, argc);
85657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&miss);
85757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateMiss(masm, argc);
85857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
85957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
86057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
86157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer// Defined in ic.cc.
86257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin KramerObject* LoadIC_Miss(Arguments args);
86357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
86457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramervoid LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
86557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // ----------- S t a t e -------------
86657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r2    : name
86757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- lr    : return address
86857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r0    : receiver
86957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- sp[0] : receiver
87057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // -----------------------------------
87157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
87257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Probe the stub cache.
87357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
87457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                         NOT_IN_LOOP,
87557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                         MONOMORPHIC);
87657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  StubCache::GenerateProbe(masm, flags, r0, r2, r3, r4, r5);
87757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
87857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Cache miss: Jump to runtime.
87957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateMiss(masm);
88057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
88157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
88257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
88357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramervoid LoadIC::GenerateNormal(MacroAssembler* masm) {
88457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // ----------- S t a t e -------------
88557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r2    : name
88657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- lr    : return address
88757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r0    : receiver
88857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- sp[0] : receiver
88957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // -----------------------------------
89057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Label miss;
89157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
89257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
89357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
89457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // r1: elements
89557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
89657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ Ret();
89757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
89857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Cache miss: Jump to runtime.
89957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&miss);
90057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateMiss(masm);
90157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
90257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
90357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
90457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramervoid LoadIC::GenerateMiss(MacroAssembler* masm) {
90557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // ----------- S t a t e -------------
90657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r2    : name
90757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- lr    : return address
90857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r0    : receiver
90957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- sp[0] : receiver
91057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // -----------------------------------
91157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
91257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ IncrementCounter(&Counters::load_miss, 1, r3, r4);
91357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
91457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ mov(r3, r0);
91557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ Push(r3, r2);
91657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
91757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Perform tail call to the entry.
91857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
91957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ TailCallExternalReference(ref, 2, 1);
92057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
92157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
92257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer// Returns the code marker, or the 0 if the code is not marked.
92357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramerstatic inline int InlinedICSiteMarker(Address address,
92457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                      Address* inline_end_address) {
92557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (V8::UseCrankshaft()) return false;
92657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
92757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // If the instruction after the call site is not the pseudo instruction nop1
92857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // then this is not related to an inlined in-object property load. The nop1
92957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // instruction is located just after the call to the IC in the deferred code
93057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // handling the miss in the inlined code. After the nop1 instruction there is
93157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // a branch instruction for jumping back from the deferred code.
93257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address address_after_call = address + Assembler::kCallTargetAddressOffset;
93357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Instr instr_after_call = Assembler::instr_at(address_after_call);
93457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  int code_marker = MacroAssembler::GetCodeMarker(instr_after_call);
93557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
93657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // A negative result means the code is not marked.
93757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (code_marker <= 0) return 0;
93857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
93957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address address_after_nop = address_after_call + Assembler::kInstrSize;
94057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Instr instr_after_nop = Assembler::instr_at(address_after_nop);
94157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // There may be some reg-reg move and frame merging code to skip over before
94257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // the branch back from the DeferredReferenceGetKeyedValue code to the inlined
94357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // code.
94457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  while (!Assembler::IsBranch(instr_after_nop)) {
94557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    address_after_nop += Assembler::kInstrSize;
94657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    instr_after_nop = Assembler::instr_at(address_after_nop);
94757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  }
94857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
94957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Find the end of the inlined code for handling the load.
95057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  int b_offset =
95157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      Assembler::GetBranchOffset(instr_after_nop) + Assembler::kPcLoadDelta;
95257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  ASSERT(b_offset < 0);  // Jumping back from deferred code.
95357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  *inline_end_address = address_after_nop + b_offset;
95457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
95557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  return code_marker;
95657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
95757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
95857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
95957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramerbool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
96057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (V8::UseCrankshaft()) return false;
96157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
96257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Find the end of the inlined code for handling the load if this is an
96357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // inlined IC call site.
96457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address inline_end_address;
96557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (InlinedICSiteMarker(address, &inline_end_address)
96657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      != Assembler::PROPERTY_ACCESS_INLINED) {
96757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    return false;
96857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  }
96957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
97057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Patch the offset of the property load instruction (ldr r0, [r1, #+XXX]).
97157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // The immediate must be representable in 12 bits.
97257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  ASSERT((JSObject::kMaxInstanceSize - JSObject::kHeaderSize) < (1 << 12));
97357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address ldr_property_instr_address =
97457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      inline_end_address - Assembler::kInstrSize;
97557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  ASSERT(Assembler::IsLdrRegisterImmediate(
97657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      Assembler::instr_at(ldr_property_instr_address)));
97757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Instr ldr_property_instr = Assembler::instr_at(ldr_property_instr_address);
97857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  ldr_property_instr = Assembler::SetLdrRegisterImmediateOffset(
97957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      ldr_property_instr, offset - kHeapObjectTag);
98057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Assembler::instr_at_put(ldr_property_instr_address, ldr_property_instr);
98157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
98257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Indicate that code has changed.
98357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  CPU::FlushICache(ldr_property_instr_address, 1 * Assembler::kInstrSize);
98457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
98557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Patch the map check.
98657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // For PROPERTY_ACCESS_INLINED, the load map instruction is generated
98757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // 4 instructions before the end of the inlined code.
98857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // See codgen-arm.cc CodeGenerator::EmitNamedLoad.
98957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  int ldr_map_offset = -4;
99057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address ldr_map_instr_address =
99157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      inline_end_address + ldr_map_offset * Assembler::kInstrSize;
99257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Assembler::set_target_address_at(ldr_map_instr_address,
99357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   reinterpret_cast<Address>(map));
99457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  return true;
99557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
99657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
99757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
99857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramerbool LoadIC::PatchInlinedContextualLoad(Address address,
99957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                        Object* map,
100057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                        Object* cell,
100157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                        bool is_dont_delete) {
100257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Find the end of the inlined code for handling the contextual load if
100357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // this is inlined IC call site.
100457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address inline_end_address;
100557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  int marker = InlinedICSiteMarker(address, &inline_end_address);
100657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (!((marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT) ||
100757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer        (marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE))) {
100857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    return false;
100957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  }
101057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // On ARM we don't rely on the is_dont_delete argument as the hint is already
101157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // embedded in the code marker.
101257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  bool marker_is_dont_delete =
101357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE;
101457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
101557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // These are the offsets from the end of the inlined code.
101657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // See codgen-arm.cc CodeGenerator::EmitNamedLoad.
101757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  int ldr_map_offset = marker_is_dont_delete ? -5: -8;
101857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  int ldr_cell_offset = marker_is_dont_delete ? -2: -5;
101957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (FLAG_debug_code && marker_is_dont_delete) {
102057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    // Three extra instructions were generated to check for the_hole_value.
102157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    ldr_map_offset -= 3;
102257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    ldr_cell_offset -= 3;
102357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  }
102457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address ldr_map_instr_address =
102557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      inline_end_address + ldr_map_offset * Assembler::kInstrSize;
102657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address ldr_cell_instr_address =
102757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      inline_end_address + ldr_cell_offset * Assembler::kInstrSize;
102857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
102957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Patch the map check.
103057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Assembler::set_target_address_at(ldr_map_instr_address,
103157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   reinterpret_cast<Address>(map));
103257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Patch the cell address.
103357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Assembler::set_target_address_at(ldr_cell_instr_address,
103457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   reinterpret_cast<Address>(cell));
103557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
103657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  return true;
103757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
103857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
103957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
104057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramerbool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
104157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (V8::UseCrankshaft()) return false;
104257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
104357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Find the end of the inlined code for the store if there is an
104457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // inlined version of the store.
104557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address inline_end_address;
104657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (InlinedICSiteMarker(address, &inline_end_address)
104757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      != Assembler::PROPERTY_ACCESS_INLINED) {
104857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    return false;
104957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  }
105057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
105157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Compute the address of the map load instruction.
105257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address ldr_map_instr_address =
105357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      inline_end_address -
105457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      (CodeGenerator::GetInlinedNamedStoreInstructionsAfterPatch() *
105557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer       Assembler::kInstrSize);
105657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
105757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Update the offsets if initializing the inlined store. No reason
105857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // to update the offsets when clearing the inlined version because
105957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // it will bail out in the map check.
106057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (map != Heap::null_value()) {
106157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    // Patch the offset in the actual store instruction.
106257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    Address str_property_instr_address =
106357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer        ldr_map_instr_address + 3 * Assembler::kInstrSize;
106457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    Instr str_property_instr = Assembler::instr_at(str_property_instr_address);
106557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    ASSERT(Assembler::IsStrRegisterImmediate(str_property_instr));
106657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    str_property_instr = Assembler::SetStrRegisterImmediateOffset(
106757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer        str_property_instr, offset - kHeapObjectTag);
106857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    Assembler::instr_at_put(str_property_instr_address, str_property_instr);
106957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
107057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    // Patch the offset in the add instruction that is part of the
107157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    // write barrier.
107257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    Address add_offset_instr_address =
107357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer        str_property_instr_address + Assembler::kInstrSize;
107457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    Instr add_offset_instr = Assembler::instr_at(add_offset_instr_address);
107557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    ASSERT(Assembler::IsAddRegisterImmediate(add_offset_instr));
107657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    add_offset_instr = Assembler::SetAddRegisterImmediateOffset(
107757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer        add_offset_instr, offset - kHeapObjectTag);
107857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    Assembler::instr_at_put(add_offset_instr_address, add_offset_instr);
107957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
108057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    // Indicate that code has changed.
108157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    CPU::FlushICache(str_property_instr_address, 2 * Assembler::kInstrSize);
108257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  }
108357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
108457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Patch the map check.
108557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Assembler::set_target_address_at(ldr_map_instr_address,
108657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   reinterpret_cast<Address>(map));
108757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
108857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  return true;
108957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
109057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
109157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
109257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramerbool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
109357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (V8::UseCrankshaft()) return false;
109457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
109557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address inline_end_address;
109657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (InlinedICSiteMarker(address, &inline_end_address)
109757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      != Assembler::PROPERTY_ACCESS_INLINED) {
109857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    return false;
109957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  }
110057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
110157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Patch the map check.
110257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address ldr_map_instr_address =
110357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      inline_end_address -
110457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      (CodeGenerator::GetInlinedKeyedLoadInstructionsAfterPatch() *
110557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      Assembler::kInstrSize);
110657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Assembler::set_target_address_at(ldr_map_instr_address,
110757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   reinterpret_cast<Address>(map));
110857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  return true;
110957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
111057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
111157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
111257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramerbool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
111357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (V8::UseCrankshaft()) return false;
111457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
111557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Find the end of the inlined code for handling the store if this is an
111657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // inlined IC call site.
111757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address inline_end_address;
111857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  if (InlinedICSiteMarker(address, &inline_end_address)
111957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      != Assembler::PROPERTY_ACCESS_INLINED) {
112057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer    return false;
112157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  }
112257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
112357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Patch the map check.
112457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Address ldr_map_instr_address =
112557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      inline_end_address -
112657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      (CodeGenerator::kInlinedKeyedStoreInstructionsAfterPatch *
112757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      Assembler::kInstrSize);
112857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  Assembler::set_target_address_at(ldr_map_instr_address,
112957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                                   reinterpret_cast<Address>(map));
113057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  return true;
113157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
113257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
113357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
113457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin KramerObject* KeyedLoadIC_Miss(Arguments args);
113557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
113657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
113757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramervoid KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
113857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // ---------- S t a t e --------------
113957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- lr     : return address
114057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r0     : key
114157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r1     : receiver
114257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // -----------------------------------
114357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
114457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ IncrementCounter(&Counters::keyed_load_miss, 1, r3, r4);
114557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
114657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ Push(r1, r0);
114757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
114857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
114957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ TailCallExternalReference(ref, 2, 1);
115057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
115157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
115257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
115357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramervoid KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
115457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // ---------- S t a t e --------------
115557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- lr     : return address
115657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r0     : key
115757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r1     : receiver
115857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // -----------------------------------
115957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
116057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ Push(r1, r0);
116157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
116257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
116357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer}
116457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
116557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
116657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramervoid KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
116757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // ---------- S t a t e --------------
116857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- lr     : return address
116957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r0     : key
117057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  //  -- r1     : receiver
11717ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
11727ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Label slow, check_string, index_smi, index_string, property_array_property;
11737ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Label check_pixel_array, probe_dictionary, check_number_dictionary;
11747ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
11757ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Register key = r0;
11767ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Register receiver = r1;
11777ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
11787ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check that the key is a smi.
11797ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ JumpIfNotSmi(key, &check_string);
11807ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ bind(&index_smi);
11817ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Now the key is known to be a smi. This place is also jumped to from below
118257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // where a numeric string is converted to a smi.
118357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
118457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateKeyedLoadReceiverCheck(
118557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer      masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
118657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
11877ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check the "has fast elements" bit in the receiver's map which is
11887ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // now in r2.
11897ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldrb(r3, FieldMemOperand(r2, Map::kBitField2Offset));
11907ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ tst(r3, Operand(1 << Map::kHasFastElements));
11917ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(eq, &check_pixel_array);
11927ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
11937ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateFastArrayLoad(
11947ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      masm, receiver, key, r4, r3, r2, r0, NULL, &slow);
11957ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3);
11967ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ Ret();
11977ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
11987ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check whether the elements is a pixel array.
11997ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // r0: key
12007ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // r1: receiver
12017ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ bind(&check_pixel_array);
12027ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
12037ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateFastPixelArrayLoad(masm,
12047ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                             r1,
12057ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                             r0,
12067ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                             r3,
12077ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                             r4,
12087ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                             r2,
12097ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                             r5,
12107ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                             r0,
121157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                             &check_number_dictionary,
121257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                             NULL,
121357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                             &slow);
121457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
121557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&check_number_dictionary);
12167ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check whether the elements is a number dictionary.
12177ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // r0: key
121857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // r3: elements map
121957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // r4: elements
122057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
122157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ cmp(r3, ip);
122257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ b(ne, &slow);
122357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ mov(r2, Operand(r0, ASR, kSmiTagSize));
122457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r0, r2, r3, r5);
122557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ Ret();
122657240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
122757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Slow case, key and receiver still in r0 and r1.
122857240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ bind(&slow);
122957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3);
12307ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateRuntimeGetProperty(masm);
12317ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
12327ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ bind(&check_string);
12337ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
12347ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
123557240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateKeyedLoadReceiverCheck(
12367ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman      masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
123757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer
12387ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // If the receiver is a fast-case object, check the keyed lookup
12397ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // cache. Otherwise probe the dictionary.
12407ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
12417ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
12427ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
12437ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ cmp(r4, ip);
12447ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(eq, &probe_dictionary);
12457ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
12467ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Load the map of the receiver, compute the keyed lookup cache hash
12477ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // based on 32 bits of the map pointer and the string hash.
12487ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
12497ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
12507ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
12517ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
12527ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask));
12537ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
12547ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Load the key (consisting of map and symbol) from the cache and
1255e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  // check for match.
1256e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys();
125757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ mov(r4, Operand(cache_keys));
1258190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
1259190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex));  // Move r4 to symbol.
1260e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ cmp(r2, r5);
1261e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ b(ne, &slow);
126257240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ ldr(r5, MemOperand(r4));
1263190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ cmp(r0, r5);
1264e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ b(ne, &slow);
1265e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer
1266190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Get field offset.
1267190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // r0     : key
1268190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // r1     : receiver
1269190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // r2     : receiver's map
1270190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // r3     : lookup cache index
1271190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  ExternalReference cache_field_offsets
1272190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer      = ExternalReference::keyed_lookup_cache_field_offsets();
1273190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ mov(r4, Operand(cache_field_offsets));
1274190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
1275190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
1276e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ sub(r5, r5, r6, SetCC);
1277190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ b(ge, &property_array_property);
1278190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1279190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Load in-object property.
1280190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1281190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ add(r6, r6, r5);  // Index from start of object.
1282190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ sub(r1, r1, Operand(kHeapObjectTag));  // Remove the heap tag.
1283190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
1284190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
1285190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ Ret();
1286190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1287190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Load property array property.
1288190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ bind(&property_array_property);
12897ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1290190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1291190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
1292190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
1293190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ Ret();
1294190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1295190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Do a quick inline probe of the receiver's dictionary, if it
1296190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // exists.
1297190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ bind(&probe_dictionary);
1298190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // r1: receiver
1299190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // r0: key
1300190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // r3: elements
1301190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1302190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
1303190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
1304190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Load the property to r0.
1305190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
1306190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3);
1307190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ Ret();
1308190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1309190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ bind(&index_string);
1310190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ IndexFromHash(r3, key);
1311190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Now jump to the place where smi keys are handled.
1312190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ jmp(&index_smi);
1313190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer}
1314190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1315190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1316190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramervoid KeyedLoadIC::GenerateString(MacroAssembler* masm) {
1317190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // ---------- S t a t e --------------
1318190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- lr     : return address
1319190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- r0     : key (index)
1320190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- r1     : receiver
1321190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // -----------------------------------
1322190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  Label miss;
1323190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1324190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  Register receiver = r1;
13257ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Register index = r0;
13267ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Register scratch1 = r2;
1327190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  Register scratch2 = r3;
1328190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  Register result = r0;
1329190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1330190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  StringCharAtGenerator char_at_generator(receiver,
1331190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                          index,
1332190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                          scratch1,
1333190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                          scratch2,
1334190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                          result,
1335190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                          &miss,  // When not a string.
1336190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                          &miss,  // When not a number.
1337190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                          &miss,  // When index out of range.
1338190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer                                          STRING_INDEX_IS_ARRAY_INDEX);
1339190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  char_at_generator.GenerateFast(masm);
1340190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ Ret();
1341190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1342190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  StubRuntimeCallHelper call_helper;
1343190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  char_at_generator.GenerateSlow(masm, call_helper);
1344190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1345190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ bind(&miss);
1346190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  GenerateMiss(masm);
1347190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer}
1348190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1349190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1350190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramervoid KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1351190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // ---------- S t a t e --------------
1352190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- lr     : return address
1353190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- r0     : key
1354190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- r1     : receiver
1355190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // -----------------------------------
1356190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  Label slow;
1357190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1358190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Check that the receiver isn't a smi.
1359190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ JumpIfSmi(r1, &slow);
1360190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1361190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Check that the key is an array index, that is Uint32.
1362190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ tst(r0, Operand(kSmiTagMask | kSmiSignMask));
1363190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ b(ne, &slow);
1364190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1365190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Get the map of the receiver.
1366190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1367190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1368190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Check that it has indexed interceptor and access checks
1369190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // are not enabled for this object.
137057240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1371190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
1372190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
1373190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ b(ne, &slow);
1374190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1375190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Everything is fine, call runtime.
1376190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ Push(r1, r0);  // Receiver, key.
1377190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1378190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // Perform tail call to the entry.
1379190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ TailCallExternalReference(ExternalReference(
1380190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer        IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
1381190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1382190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  __ bind(&slow);
1383190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  GenerateMiss(masm);
1384190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer}
1385190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1386190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
1387190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramervoid KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
1388190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // ---------- S t a t e --------------
1389190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- r0     : value
1390190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- r1     : key
1391190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- r2     : receiver
1392190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  //  -- lr     : return address
1393190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer  // -----------------------------------
1394190f8ee25a6977ac6eb71b816498df42f17ad9a7Benjamin Kramer
13957ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Push receiver, key and value for runtime call.
13967ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ Push(r2, r1, r0);
13977ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
13987ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
13997ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ TailCallExternalReference(ref, 3, 1);
14007ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman}
14017ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
14027ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
14037ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmanvoid KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
14047ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                              StrictModeFlag strict_mode) {
14057ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // ---------- S t a t e --------------
14067ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r0     : value
14077ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r1     : key
14087ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r2     : receiver
14097ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- lr     : return address
14107ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
14117ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
14127ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Push receiver, key and value for runtime call.
14137ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ Push(r2, r1, r0);
14147ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
14157ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ mov(r1, Operand(Smi::FromInt(NONE)));          // PropertyAttributes
14167ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ mov(r0, Operand(Smi::FromInt(strict_mode)));   // Strict mode.
14177ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ Push(r1, r0);
14187ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
14197ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
14207ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman}
14217ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
14227ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
14237ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukmanvoid KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
14247ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                                   StrictModeFlag strict_mode) {
14257ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // ---------- S t a t e --------------
14267ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r0     : value
14277ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r1     : key
14287ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- r2     : receiver
14297ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  //  -- lr     : return address
14307ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // -----------------------------------
14317ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Label slow, fast, array, extra, check_pixel_array;
14327ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
14337ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Register usage.
14347ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Register value = r0;
14357ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Register key = r1;
14367ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Register receiver = r2;
14377ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  Register elements = r3;  // Elements array of the receiver.
14387ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // r4 and r5 are used as general scratch registers.
14397ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
14407ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check that the key is a smi.
14417ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ tst(key, Operand(kSmiTagMask));
14427ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(ne, &slow);
14437ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check that the object isn't a smi.
14447ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ tst(receiver, Operand(kSmiTagMask));
14457ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(eq, &slow);
14467ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Get the map of the object.
1447e4b9c93fc1b531fe0cfe25a042f6b81c1e7c15c0Benjamin Kramer  __ ldr(r4, FieldMemOperand(receiver, HeapObject::kMapOffset));
14487ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check that the receiver does not require access checks.  We need
14497ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // to do this because this generic stub does not perform map checks.
14507ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldrb(ip, FieldMemOperand(r4, Map::kBitFieldOffset));
14517ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
14527ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(ne, &slow);
14537ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check if the object is a JS array or not.
14547ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
14557ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ cmp(r4, Operand(JS_ARRAY_TYPE));
14567ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(eq, &array);
14577ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check that the object is some kind of JS object.
14587ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
14597ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(lt, &slow);
14607ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
14617ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Object case: Check key against length in the elements array.
14627ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
14637ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check that the object is in fast mode and writable.
14647ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
14657ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
14667ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ cmp(r4, ip);
14677ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ b(ne, &check_pixel_array);
14687ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Check array bounds. Both the key and the length of FixedArray are smis.
146957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
14707ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ cmp(key, Operand(ip));
147157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  __ b(lo, &fast);
14727ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
147357240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Slow case, handle jump to runtime.
14747ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ bind(&slow);
14757ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Entry registers are intact.
14767ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // r0: value.
147757240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // r1: key.
14787ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // r2: receiver.
147957240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  GenerateRuntimeSetProperty(masm, strict_mode);
14807ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
148157240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer  // Check whether the elements is a pixel array.
14827ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // r4: elements map.
14837ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  __ bind(&check_pixel_array);
14847ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  GenerateFastPixelArrayStore(masm,
14857ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              r2,
14867ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              r1,
14877ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              r0,
14887ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              elements,
14897ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              r4,
14907ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              r5,
14917ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              r6,
14927ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              false,
14937ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              false,
149457240ff6e2252f8986f6e47e4010bc52fbae25d1Benjamin Kramer                              NULL,
14957ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              &slow,
14967ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              &slow,
14977ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman                              &slow);
14987ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman
14997ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // Extra capacity case: Check if there is extra capacity to
15007ae6ff442a26212a0cc4c1929b8b0a105dc988e4Misha Brukman  // perform the store and update the length. Used for adding one
1501  // element to the array by writing to array[array.length].
1502  __ bind(&extra);
1503  // Condition code from comparing key and array length is still available.
1504  __ b(ne, &slow);  // Only support writing to writing to array[array.length].
1505  // Check for room in the elements backing store.
1506  // Both the key and the length of FixedArray are smis.
1507  __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
1508  __ cmp(key, Operand(ip));
1509  __ b(hs, &slow);
1510  // Calculate key + 1 as smi.
1511  ASSERT_EQ(0, kSmiTag);
1512  __ add(r4, key, Operand(Smi::FromInt(1)));
1513  __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
1514  __ b(&fast);
1515
1516  // Array case: Get the length and the elements array from the JS
1517  // array. Check that the array is in fast mode (and writable); if it
1518  // is the length is always a smi.
1519  __ bind(&array);
1520  __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1521  __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
1522  __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
1523  __ cmp(r4, ip);
1524  __ b(ne, &slow);
1525
1526  // Check the key against the length in the array.
1527  __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
1528  __ cmp(key, Operand(ip));
1529  __ b(hs, &extra);
1530  // Fall through to fast case.
1531
1532  __ bind(&fast);
1533  // Fast case, store the value to the elements backing store.
1534  __ add(r5, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1535  __ add(r5, r5, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
1536  __ str(value, MemOperand(r5));
1537  // Skip write barrier if the written value is a smi.
1538  __ tst(value, Operand(kSmiTagMask));
1539  __ Ret(eq);
1540  // Update write barrier for the elements array address.
1541  __ sub(r4, r5, Operand(elements));
1542  __ RecordWrite(elements, Operand(r4), r5, r6);
1543
1544  __ Ret();
1545}
1546
1547
1548void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
1549                                  StrictModeFlag strict_mode) {
1550  // ----------- S t a t e -------------
1551  //  -- r0    : value
1552  //  -- r1    : receiver
1553  //  -- r2    : name
1554  //  -- lr    : return address
1555  // -----------------------------------
1556
1557  // Get the receiver from the stack and probe the stub cache.
1558  Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1559                                         NOT_IN_LOOP,
1560                                         MONOMORPHIC,
1561                                         strict_mode);
1562  StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
1563
1564  // Cache miss: Jump to runtime.
1565  GenerateMiss(masm);
1566}
1567
1568
1569void StoreIC::GenerateMiss(MacroAssembler* masm) {
1570  // ----------- S t a t e -------------
1571  //  -- r0    : value
1572  //  -- r1    : receiver
1573  //  -- r2    : name
1574  //  -- lr    : return address
1575  // -----------------------------------
1576
1577  __ Push(r1, r2, r0);
1578
1579  // Perform tail call to the entry.
1580  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
1581  __ TailCallExternalReference(ref, 3, 1);
1582}
1583
1584
1585void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1586  // ----------- S t a t e -------------
1587  //  -- r0    : value
1588  //  -- r1    : receiver
1589  //  -- r2    : name
1590  //  -- lr    : return address
1591  // -----------------------------------
1592  //
1593  // This accepts as a receiver anything JSObject::SetElementsLength accepts
1594  // (currently anything except for external and pixel arrays which means
1595  // anything with elements of FixedArray type.), but currently is restricted
1596  // to JSArray.
1597  // Value must be a number, but only smis are accepted as the most common case.
1598
1599  Label miss;
1600
1601  Register receiver = r1;
1602  Register value = r0;
1603  Register scratch = r3;
1604
1605  // Check that the receiver isn't a smi.
1606  __ JumpIfSmi(receiver, &miss);
1607
1608  // Check that the object is a JS array.
1609  __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
1610  __ b(ne, &miss);
1611
1612  // Check that elements are FixedArray.
1613  // We rely on StoreIC_ArrayLength below to deal with all types of
1614  // fast elements (including COW).
1615  __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
1616  __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
1617  __ b(ne, &miss);
1618
1619  // Check that value is a smi.
1620  __ JumpIfNotSmi(value, &miss);
1621
1622  // Prepare tail call to StoreIC_ArrayLength.
1623  __ Push(receiver, value);
1624
1625  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
1626  __ TailCallExternalReference(ref, 2, 1);
1627
1628  __ bind(&miss);
1629
1630  GenerateMiss(masm);
1631}
1632
1633
1634void StoreIC::GenerateNormal(MacroAssembler* masm) {
1635  // ----------- S t a t e -------------
1636  //  -- r0    : value
1637  //  -- r1    : receiver
1638  //  -- r2    : name
1639  //  -- lr    : return address
1640  // -----------------------------------
1641  Label miss;
1642
1643  GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
1644
1645  GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
1646  __ IncrementCounter(&Counters::store_normal_hit, 1, r4, r5);
1647  __ Ret();
1648
1649  __ bind(&miss);
1650  __ IncrementCounter(&Counters::store_normal_miss, 1, r4, r5);
1651  GenerateMiss(masm);
1652}
1653
1654
1655void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1656                                  StrictModeFlag strict_mode) {
1657  // ----------- S t a t e -------------
1658  //  -- r0    : value
1659  //  -- r1    : receiver
1660  //  -- r2    : name
1661  //  -- lr    : return address
1662  // -----------------------------------
1663
1664  __ Push(r1, r2, r0);
1665
1666  __ mov(r1, Operand(Smi::FromInt(NONE)));  // PropertyAttributes
1667  __ mov(r0, Operand(Smi::FromInt(strict_mode)));
1668  __ Push(r1, r0);
1669
1670  // Do tail-call to runtime routine.
1671  __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1672}
1673
1674
1675#undef __
1676
1677
1678Condition CompareIC::ComputeCondition(Token::Value op) {
1679  switch (op) {
1680    case Token::EQ_STRICT:
1681    case Token::EQ:
1682      return eq;
1683    case Token::LT:
1684      return lt;
1685    case Token::GT:
1686      // Reverse left and right operands to obtain ECMA-262 conversion order.
1687      return lt;
1688    case Token::LTE:
1689      // Reverse left and right operands to obtain ECMA-262 conversion order.
1690      return ge;
1691    case Token::GTE:
1692      return ge;
1693    default:
1694      UNREACHABLE();
1695      return kNoCondition;
1696  }
1697}
1698
1699
1700void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1701  HandleScope scope;
1702  Handle<Code> rewritten;
1703  State previous_state = GetState();
1704  State state = TargetState(previous_state, false, x, y);
1705  if (state == GENERIC) {
1706    CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
1707    rewritten = stub.GetCode();
1708  } else {
1709    ICCompareStub stub(op_, state);
1710    rewritten = stub.GetCode();
1711  }
1712  set_target(*rewritten);
1713
1714#ifdef DEBUG
1715  if (FLAG_trace_ic) {
1716    PrintF("[CompareIC (%s->%s)#%s]\n",
1717           GetStateName(previous_state),
1718           GetStateName(state),
1719           Token::Name(op_));
1720  }
1721#endif
1722
1723  // Activate inlined smi code.
1724  if (previous_state == UNINITIALIZED) {
1725    PatchInlinedSmiCode(address());
1726  }
1727}
1728
1729
1730void PatchInlinedSmiCode(Address address) {
1731  Address cmp_instruction_address =
1732      address + Assembler::kCallTargetAddressOffset;
1733
1734  // If the instruction following the call is not a cmp rx, #yyy, nothing
1735  // was inlined.
1736  Instr instr = Assembler::instr_at(cmp_instruction_address);
1737  if (!Assembler::IsCmpImmediate(instr)) {
1738    return;
1739  }
1740
1741  // The delta to the start of the map check instruction and the
1742  // condition code uses at the patched jump.
1743  int delta = Assembler::GetCmpImmediateRawImmediate(instr);
1744  delta +=
1745      Assembler::GetCmpImmediateRegister(instr).code() * kOff12Mask;
1746  // If the delta is 0 the instruction is cmp r0, #0 which also signals that
1747  // nothing was inlined.
1748  if (delta == 0) {
1749    return;
1750  }
1751
1752#ifdef DEBUG
1753  if (FLAG_trace_ic) {
1754    PrintF("[  patching ic at %p, cmp=%p, delta=%d\n",
1755           address, cmp_instruction_address, delta);
1756  }
1757#endif
1758
1759  Address patch_address =
1760      cmp_instruction_address - delta * Instruction::kInstrSize;
1761  Instr instr_at_patch = Assembler::instr_at(patch_address);
1762  Instr branch_instr =
1763      Assembler::instr_at(patch_address + Instruction::kInstrSize);
1764  ASSERT(Assembler::IsCmpRegister(instr_at_patch));
1765  ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(),
1766            Assembler::GetRm(instr_at_patch).code());
1767  ASSERT(Assembler::IsBranch(branch_instr));
1768  if (Assembler::GetCondition(branch_instr) == eq) {
1769    // This is patching a "jump if not smi" site to be active.
1770    // Changing
1771    //   cmp rx, rx
1772    //   b eq, <target>
1773    // to
1774    //   tst rx, #kSmiTagMask
1775    //   b ne, <target>
1776    CodePatcher patcher(patch_address, 2);
1777    Register reg = Assembler::GetRn(instr_at_patch);
1778    patcher.masm()->tst(reg, Operand(kSmiTagMask));
1779    patcher.EmitCondition(ne);
1780  } else {
1781    ASSERT(Assembler::GetCondition(branch_instr) == ne);
1782    // This is patching a "jump if smi" site to be active.
1783    // Changing
1784    //   cmp rx, rx
1785    //   b ne, <target>
1786    // to
1787    //   tst rx, #kSmiTagMask
1788    //   b eq, <target>
1789    CodePatcher patcher(patch_address, 2);
1790    Register reg = Assembler::GetRn(instr_at_patch);
1791    patcher.masm()->tst(reg, Operand(kSmiTagMask));
1792    patcher.EmitCondition(eq);
1793  }
1794}
1795
1796
1797} }  // namespace v8::internal
1798
1799#endif  // V8_TARGET_ARCH_ARM
1800