~ubuntu-branches/ubuntu/precise/nodejs/precise

« back to all changes in this revision

Viewing changes to deps/v8/src/arm/ic-arm.cc

  • Committer: Bazaar Package Importer
  • Author(s): Jérémy Lal
  • Date: 2010-08-20 11:49:04 UTC
  • mfrom: (7.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20100820114904-lz22w6fkth7yh179
Tags: 0.2.0-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
47
47
 
48
48
#define __ ACCESS_MASM(masm)
49
49
 
50
 
// Helper function used from LoadIC/CallIC GenerateNormal.
51
 
static void GenerateDictionaryLoad(MacroAssembler* masm,
52
 
                                   Label* miss,
53
 
                                   Register t0,
54
 
                                   Register t1) {
55
 
  // Register use:
56
 
  //
57
 
  // t0 - used to hold the property dictionary.
58
 
  //
59
 
  // t1 - initially the receiver
60
 
  //    - used for the index into the property dictionary
61
 
  //    - holds the result on exit.
62
 
  //
63
 
  // r3 - used as temporary and to hold the capacity of the property
64
 
  //      dictionary.
65
 
  //
66
 
  // r2 - holds the name of the property and is unchanged.
67
 
  // r4 - used as temporary.
68
 
 
69
 
  Label done;
70
 
 
71
 
  // Check for the absence of an interceptor.
72
 
  // Load the map into t0.
73
 
  __ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset));
74
 
 
75
 
  // Bail out if the receiver has a named interceptor.
76
 
  __ ldrb(r3, FieldMemOperand(t0, Map::kBitFieldOffset));
77
 
  __ tst(r3, Operand(1 << Map::kHasNamedInterceptor));
 
50
 
 
51
static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
 
52
                                            Register type,
 
53
                                            Label* global_object) {
 
54
  // Register usage:
 
55
  //   type: holds the receiver instance type on entry.
 
56
  __ cmp(type, Operand(JS_GLOBAL_OBJECT_TYPE));
 
57
  __ b(eq, global_object);
 
58
  __ cmp(type, Operand(JS_BUILTINS_OBJECT_TYPE));
 
59
  __ b(eq, global_object);
 
60
  __ cmp(type, Operand(JS_GLOBAL_PROXY_TYPE));
 
61
  __ b(eq, global_object);
 
62
}
 
63
 
 
64
 
 
65
// Generated code falls through if the receiver is a regular non-global
 
66
// JS object with slow properties and no interceptors.
 
67
static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
 
68
                                                  Register receiver,
 
69
                                                  Register elements,
 
70
                                                  Register t0,
 
71
                                                  Register t1,
 
72
                                                  Label* miss) {
 
73
  // Register usage:
 
74
  //   receiver: holds the receiver on entry and is unchanged.
 
75
  //   elements: holds the property dictionary on fall through.
 
76
  // Scratch registers:
 
77
  //   t0: used to holds the receiver map.
 
78
  //   t1: used to holds the receiver instance type, receiver bit mask and
 
79
  //       elements map.
 
80
 
 
81
  // Check that the receiver isn't a smi.
 
82
  __ tst(receiver, Operand(kSmiTagMask));
 
83
  __ b(eq, miss);
 
84
 
 
85
  // Check that the receiver is a valid JS object.
 
86
  __ CompareObjectType(receiver, t0, t1, FIRST_JS_OBJECT_TYPE);
 
87
  __ b(lt, miss);
 
88
 
 
89
  // If this assert fails, we have to check upper bound too.
 
90
  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
 
91
 
 
92
  GenerateGlobalInstanceTypeCheck(masm, t1, miss);
 
93
 
 
94
  // Check that the global object does not require access checks.
 
95
  __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
 
96
  __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
 
97
                     (1 << Map::kHasNamedInterceptor)));
78
98
  __ b(nz, miss);
79
99
 
80
 
  // Bail out if we have a JS global proxy object.
81
 
  __ ldrb(r3, FieldMemOperand(t0, Map::kInstanceTypeOffset));
82
 
  __ cmp(r3, Operand(JS_GLOBAL_PROXY_TYPE));
83
 
  __ b(eq, miss);
84
 
 
85
 
  // Possible work-around for http://crbug.com/16276.
86
 
  // See also: http://codereview.chromium.org/155418.
87
 
  __ cmp(r3, Operand(JS_GLOBAL_OBJECT_TYPE));
88
 
  __ b(eq, miss);
89
 
  __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
90
 
  __ b(eq, miss);
91
 
 
92
 
  // Check that the properties array is a dictionary.
93
 
  __ ldr(t0, FieldMemOperand(t1, JSObject::kPropertiesOffset));
94
 
  __ ldr(r3, FieldMemOperand(t0, HeapObject::kMapOffset));
 
100
  __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
 
101
  __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
95
102
  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
96
 
  __ cmp(r3, ip);
97
 
  __ b(ne, miss);
98
 
 
 
103
  __ cmp(t1, ip);
 
104
  __ b(nz, miss);
 
105
}
 
106
 
 
107
 
 
108
// Probe the string dictionary in the |elements| register. Jump to the
 
109
// |done| label if a property with the given name is found. Jump to
 
110
// the |miss| label otherwise.
 
111
static void GenerateStringDictionaryProbes(MacroAssembler* masm,
 
112
                                           Label* miss,
 
113
                                           Label* done,
 
114
                                           Register elements,
 
115
                                           Register name,
 
116
                                           Register scratch1,
 
117
                                           Register scratch2) {
99
118
  // Compute the capacity mask.
100
119
  const int kCapacityOffset = StringDictionary::kHeaderSize +
101
120
      StringDictionary::kCapacityIndex * kPointerSize;
102
 
  __ ldr(r3, FieldMemOperand(t0, kCapacityOffset));
103
 
  __ mov(r3, Operand(r3, ASR, kSmiTagSize));  // convert smi to int
104
 
  __ sub(r3, r3, Operand(1));
 
121
  __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
 
122
  __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize));  // convert smi to int
 
123
  __ sub(scratch1, scratch1, Operand(1));
105
124
 
106
125
  const int kElementsStartOffset = StringDictionary::kHeaderSize +
107
126
      StringDictionary::kElementsStartIndex * kPointerSize;
112
131
  static const int kProbes = 4;
113
132
  for (int i = 0; i < kProbes; i++) {
114
133
    // Compute the masked index: (hash + i + i * i) & mask.
115
 
    __ ldr(r4, FieldMemOperand(r2, String::kHashFieldOffset));
 
134
    __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
116
135
    if (i > 0) {
117
136
      // Add the probe offset (i + i * i) left shifted to avoid right shifting
118
137
      // the hash in a separate instruction. The value hash + i + i * i is right
119
138
      // shifted in the following and instruction.
120
139
      ASSERT(StringDictionary::GetProbeOffset(i) <
121
140
             1 << (32 - String::kHashFieldOffset));
122
 
      __ add(r4, r4, Operand(
 
141
      __ add(scratch2, scratch2, Operand(
123
142
          StringDictionary::GetProbeOffset(i) << String::kHashShift));
124
143
    }
125
 
    __ and_(r4, r3, Operand(r4, LSR, String::kHashShift));
 
144
    __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
126
145
 
127
146
    // Scale the index by multiplying by the element size.
128
147
    ASSERT(StringDictionary::kEntrySize == 3);
129
 
    __ add(r4, r4, Operand(r4, LSL, 1));  // r4 = r4 * 3
 
148
    // scratch2 = scratch2 * 3.
 
149
    __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
130
150
 
131
151
    // Check if the key is identical to the name.
132
 
    __ add(r4, t0, Operand(r4, LSL, 2));
133
 
    __ ldr(ip, FieldMemOperand(r4, kElementsStartOffset));
134
 
    __ cmp(r2, Operand(ip));
 
152
    __ add(scratch2, elements, Operand(scratch2, LSL, 2));
 
153
    __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
 
154
    __ cmp(name, Operand(ip));
135
155
    if (i != kProbes - 1) {
136
 
      __ b(eq, &done);
 
156
      __ b(eq, done);
137
157
    } else {
138
158
      __ b(ne, miss);
139
159
    }
140
160
  }
141
 
 
142
 
  // Check that the value is a normal property.
143
 
  __ bind(&done);  // r4 == t0 + 4*index
144
 
  __ ldr(r3, FieldMemOperand(r4, kElementsStartOffset + 2 * kPointerSize));
145
 
  __ tst(r3, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
 
161
}
 
162
 
 
163
 
 
164
// Helper function used from LoadIC/CallIC GenerateNormal.
 
165
//
 
166
// elements: Property dictionary. It is not clobbered if a jump to the miss
 
167
//           label is done.
 
168
// name:     Property name. It is not clobbered if a jump to the miss label is
 
169
//           done
 
170
// result:   Register for the result. It is only updated if a jump to the miss
 
171
//           label is not done. Can be the same as elements or name clobbering
 
172
//           one of these in the case of not jumping to the miss label.
 
173
// The two scratch registers need to be different from elements, name and
 
174
// result.
 
175
// The generated code assumes that the receiver has slow properties,
 
176
// is not a global object and does not have interceptors.
 
177
static void GenerateDictionaryLoad(MacroAssembler* masm,
 
178
                                   Label* miss,
 
179
                                   Register elements,
 
180
                                   Register name,
 
181
                                   Register result,
 
182
                                   Register scratch1,
 
183
                                   Register scratch2) {
 
184
  // Main use of the scratch registers.
 
185
  // scratch1: Used as temporary and to hold the capacity of the property
 
186
  //           dictionary.
 
187
  // scratch2: Used as temporary.
 
188
  Label done;
 
189
 
 
190
  // Probe the dictionary.
 
191
  GenerateStringDictionaryProbes(masm,
 
192
                                 miss,
 
193
                                 &done,
 
194
                                 elements,
 
195
                                 name,
 
196
                                 scratch1,
 
197
                                 scratch2);
 
198
 
 
199
  // If probing finds an entry check that the value is a normal
 
200
  // property.
 
201
  __ bind(&done);  // scratch2 == elements + 4 * index
 
202
  const int kElementsStartOffset = StringDictionary::kHeaderSize +
 
203
      StringDictionary::kElementsStartIndex * kPointerSize;
 
204
  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
 
205
  __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
 
206
  __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
146
207
  __ b(ne, miss);
147
208
 
148
209
  // Get the value at the masked, scaled index and return.
149
 
  __ ldr(t1, FieldMemOperand(r4, kElementsStartOffset + 1 * kPointerSize));
 
210
  __ ldr(result,
 
211
         FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
 
212
}
 
213
 
 
214
 
 
215
// Helper function used from StoreIC::GenerateNormal.
 
216
//
 
217
// elements: Property dictionary. It is not clobbered if a jump to the miss
 
218
//           label is done.
 
219
// name:     Property name. It is not clobbered if a jump to the miss label is
 
220
//           done
 
221
// value:    The value to store.
 
222
// The two scratch registers need to be different from elements, name and
 
223
// result.
 
224
// The generated code assumes that the receiver has slow properties,
 
225
// is not a global object and does not have interceptors.
 
226
static void GenerateDictionaryStore(MacroAssembler* masm,
 
227
                                    Label* miss,
 
228
                                    Register elements,
 
229
                                    Register name,
 
230
                                    Register value,
 
231
                                    Register scratch1,
 
232
                                    Register scratch2) {
 
233
  // Main use of the scratch registers.
 
234
  // scratch1: Used as temporary and to hold the capacity of the property
 
235
  //           dictionary.
 
236
  // scratch2: Used as temporary.
 
237
  Label done;
 
238
 
 
239
  // Probe the dictionary.
 
240
  GenerateStringDictionaryProbes(masm,
 
241
                                 miss,
 
242
                                 &done,
 
243
                                 elements,
 
244
                                 name,
 
245
                                 scratch1,
 
246
                                 scratch2);
 
247
 
 
248
  // If probing finds an entry in the dictionary check that the value
 
249
  // is a normal property that is not read only.
 
250
  __ bind(&done);  // scratch2 == elements + 4 * index
 
251
  const int kElementsStartOffset = StringDictionary::kHeaderSize +
 
252
      StringDictionary::kElementsStartIndex * kPointerSize;
 
253
  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
 
254
  const int kTypeAndReadOnlyMask
 
255
      = (PropertyDetails::TypeField::mask() |
 
256
         PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
 
257
  __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
 
258
  __ tst(scratch1, Operand(kTypeAndReadOnlyMask));
 
259
  __ b(ne, miss);
 
260
 
 
261
  // Store the value at the masked, scaled index and return.
 
262
  const int kValueOffset = kElementsStartOffset + kPointerSize;
 
263
  __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
 
264
  __ str(value, MemOperand(scratch2));
 
265
 
 
266
  // Update the write barrier. Make sure not to clobber the value.
 
267
  __ mov(scratch1, value);
 
268
  __ RecordWrite(elements, scratch2, scratch1);
150
269
}
151
270
 
152
271
 
154
273
                                         Label* miss,
155
274
                                         Register elements,
156
275
                                         Register key,
 
276
                                         Register result,
157
277
                                         Register t0,
158
278
                                         Register t1,
159
279
                                         Register t2) {
160
280
  // Register use:
161
281
  //
162
 
  // elements - holds the slow-case elements of the receiver and is unchanged.
163
 
  //
164
 
  // key      - holds the smi key on entry and is unchanged if a branch is
165
 
  //            performed to the miss label.
 
282
  // elements - holds the slow-case elements of the receiver on entry.
 
283
  //            Unchanged unless 'result' is the same register.
 
284
  //
 
285
  // key      - holds the smi key on entry.
 
286
  //            Unchanged unless 'result' is the same register.
 
287
  //
 
288
  // result   - holds the result on exit if the load succeeded.
 
289
  //            Allowed to be the same as 'key' or 'result'.
 
290
  //            Unchanged on bailout so 'key' or 'result' can be used
 
291
  //            in further computation.
166
292
  //
167
293
  // Scratch registers:
168
294
  //
169
295
  // t0 - holds the untagged key on entry and holds the hash once computed.
170
 
  //      Holds the result on exit if the load succeeded.
171
296
  //
172
297
  // t1 - used to hold the capacity mask of the dictionary
173
298
  //
235
360
  // Get the value at the masked, scaled index and return.
236
361
  const int kValueOffset =
237
362
      NumberDictionary::kElementsStartOffset + kPointerSize;
238
 
  __ ldr(t0, FieldMemOperand(t2, kValueOffset));
 
363
  __ ldr(result, FieldMemOperand(t2, kValueOffset));
239
364
}
240
365
 
241
366
 
285
410
}
286
411
 
287
412
 
 
413
// Checks the receiver for special cases (value type, slow case bits).
 
414
// Falls through for regular JS object.
 
415
static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
 
416
                                           Register receiver,
 
417
                                           Register scratch1,
 
418
                                           Register scratch2,
 
419
                                           int interceptor_bit,
 
420
                                           Label* slow) {
 
421
  // Check that the object isn't a smi.
 
422
  __ BranchOnSmi(receiver, slow);
 
423
  // Get the map of the receiver.
 
424
  __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
 
425
  // Check bit field.
 
426
  __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
 
427
  __ tst(scratch2,
 
428
         Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
 
429
  __ b(nz, slow);
 
430
  // Check that the object is some kind of JS object EXCEPT JS Value type.
 
431
  // In the case that the object is a value-wrapper object,
 
432
  // we enter the runtime system to make sure that indexing into string
 
433
  // objects work as intended.
 
434
  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
 
435
  __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
 
436
  __ cmp(scratch1, Operand(JS_OBJECT_TYPE));
 
437
  __ b(lt, slow);
 
438
}
 
439
 
 
440
 
 
441
// Loads an indexed element from a fast case array.
 
442
static void GenerateFastArrayLoad(MacroAssembler* masm,
 
443
                                  Register receiver,
 
444
                                  Register key,
 
445
                                  Register elements,
 
446
                                  Register scratch1,
 
447
                                  Register scratch2,
 
448
                                  Register result,
 
449
                                  Label* not_fast_array,
 
450
                                  Label* out_of_range) {
 
451
  // Register use:
 
452
  //
 
453
  // receiver - holds the receiver on entry.
 
454
  //            Unchanged unless 'result' is the same register.
 
455
  //
 
456
  // key      - holds the smi key on entry.
 
457
  //            Unchanged unless 'result' is the same register.
 
458
  //
 
459
  // elements - holds the elements of the receiver on exit.
 
460
  //
 
461
  // result   - holds the result on exit if the load succeeded.
 
462
  //            Allowed to be the the same as 'receiver' or 'key'.
 
463
  //            Unchanged on bailout so 'receiver' and 'key' can be safely
 
464
  //            used by further computation.
 
465
  //
 
466
  // Scratch registers:
 
467
  //
 
468
  // scratch1 - used to hold elements map and elements length.
 
469
  //            Holds the elements map if not_fast_array branch is taken.
 
470
  //
 
471
  // scratch2 - used to hold the loaded value.
 
472
 
 
473
  __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
 
474
  // Check that the object is in fast mode (not dictionary).
 
475
  __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
 
476
  __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
 
477
  __ cmp(scratch1, ip);
 
478
  __ b(ne, not_fast_array);
 
479
  // Check that the key (index) is within bounds.
 
480
  __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
 
481
  __ cmp(key, Operand(scratch1));
 
482
  __ b(hs, out_of_range);
 
483
  // Fast case: Do the load.
 
484
  __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
 
485
  // The key is a smi.
 
486
  ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
 
487
  __ ldr(scratch2,
 
488
         MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
 
489
  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
 
490
  __ cmp(scratch2, ip);
 
491
  // In case the loaded value is the_hole we have to consult GetProperty
 
492
  // to ensure the prototype chain is searched.
 
493
  __ b(eq, out_of_range);
 
494
  __ mov(result, scratch2);
 
495
}
 
496
 
 
497
 
 
498
// Checks whether a key is an array index string or a symbol string.
 
499
// Falls through if a key is a symbol.
 
500
static void GenerateKeyStringCheck(MacroAssembler* masm,
 
501
                                   Register key,
 
502
                                   Register map,
 
503
                                   Register hash,
 
504
                                   Label* index_string,
 
505
                                   Label* not_symbol) {
 
506
  // The key is not a smi.
 
507
  // Is it a string?
 
508
  __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
 
509
  __ b(ge, not_symbol);
 
510
 
 
511
  // Is the string an array index, with cached numeric value?
 
512
  __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
 
513
  __ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
 
514
  __ b(eq, index_string);
 
515
 
 
516
  // Is the string a symbol?
 
517
  // map: key map
 
518
  __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
 
519
  ASSERT(kSymbolTag != 0);
 
520
  __ tst(hash, Operand(kIsSymbolMask));
 
521
  __ b(eq, not_symbol);
 
522
}
 
523
 
 
524
 
 
525
// Picks out an array index from the hash field.
 
526
static void GenerateIndexFromHash(MacroAssembler* masm,
 
527
                                  Register key,
 
528
                                  Register hash) {
 
529
  // Register use:
 
530
  //   key - holds the overwritten key on exit.
 
531
  //   hash - holds the key's hash. Clobbered.
 
532
 
 
533
  // If the hash field contains an array index pick it out. The assert checks
 
534
  // that the constants for the maximum number of digits for an array index
 
535
  // cached in the hash field and the number of bits reserved for it does not
 
536
  // conflict.
 
537
  ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
 
538
         (1 << String::kArrayIndexValueBits));
 
539
  // We want the smi-tagged index in key.  kArrayIndexValueMask has zeros in
 
540
  // the low kHashShift bits.
 
541
  ASSERT(String::kHashShift >= kSmiTagSize);
 
542
  // Here we actually clobber the key which will be used if calling into
 
543
  // runtime later. However as the new key is the numeric value of a string key
 
544
  // there is no difference in using either key.
 
545
  ASSERT(String::kHashShift >= kSmiTagSize);
 
546
  __ Ubfx(hash, hash, String::kHashShift, String::kArrayIndexValueBits);
 
547
  __ mov(key, Operand(hash, LSL, kSmiTagSize));
 
548
}
 
549
 
 
550
 
288
551
// Defined in ic.cc.
289
552
Object* CallIC_Miss(Arguments args);
290
553
 
291
 
void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
 
554
// The generated code does not accept smi keys.
 
555
// The generated code falls through if both probes miss.
 
556
static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
 
557
                                          int argc,
 
558
                                          Code::Kind kind) {
292
559
  // ----------- S t a t e -------------
 
560
  //  -- r1    : receiver
293
561
  //  -- r2    : name
294
 
  //  -- lr    : return address
295
562
  // -----------------------------------
296
563
  Label number, non_number, non_string, boolean, probe, miss;
297
564
 
298
 
  // Get the receiver of the function from the stack into r1.
299
 
  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
300
 
 
301
565
  // Probe the stub cache.
302
566
  Code::Flags flags =
303
 
      Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
 
567
      Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
304
568
  StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
305
569
 
306
570
  // If the stub cache probing failed, the receiver might be a value.
342
606
  __ bind(&probe);
343
607
  StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
344
608
 
345
 
  // Cache miss: Jump to runtime.
346
609
  __ bind(&miss);
347
 
  GenerateMiss(masm, argc);
348
610
}
349
611
 
350
612
 
351
 
static void GenerateNormalHelper(MacroAssembler* masm,
352
 
                                 int argc,
353
 
                                 bool is_global_object,
354
 
                                 Label* miss,
355
 
                                 Register scratch) {
356
 
  // Search dictionary - put result in register r1.
357
 
  GenerateDictionaryLoad(masm, miss, r0, r1);
 
613
static void GenerateFunctionTailCall(MacroAssembler* masm,
 
614
                                     int argc,
 
615
                                     Label* miss,
 
616
                                     Register scratch) {
 
617
  // r1: function
358
618
 
359
619
  // Check that the value isn't a smi.
360
620
  __ tst(r1, Operand(kSmiTagMask));
364
624
  __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
365
625
  __ b(ne, miss);
366
626
 
367
 
  // Patch the receiver with the global proxy if necessary.
368
 
  if (is_global_object) {
369
 
    __ ldr(r0, MemOperand(sp, argc * kPointerSize));
370
 
    __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
371
 
    __ str(r0, MemOperand(sp, argc * kPointerSize));
372
 
  }
373
 
 
374
627
  // Invoke the function.
375
628
  ParameterCount actual(argc);
376
629
  __ InvokeFunction(r1, actual, JUMP_FUNCTION);
377
630
}
378
631
 
379
632
 
380
 
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
 
633
static void GenerateCallNormal(MacroAssembler* masm, int argc) {
381
634
  // ----------- S t a t e -------------
382
635
  //  -- r2    : name
383
636
  //  -- lr    : return address
384
637
  // -----------------------------------
385
 
  Label miss, global_object, non_global_object;
 
638
  Label miss;
386
639
 
387
640
  // Get the receiver of the function from the stack into r1.
388
641
  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
389
642
 
390
 
  // Check that the receiver isn't a smi.
391
 
  __ tst(r1, Operand(kSmiTagMask));
392
 
  __ b(eq, &miss);
393
 
 
394
 
  // Check that the receiver is a valid JS object.  Put the map in r3.
395
 
  __ CompareObjectType(r1, r3, r0, FIRST_JS_OBJECT_TYPE);
396
 
  __ b(lt, &miss);
397
 
 
398
 
  // If this assert fails, we have to check upper bound too.
399
 
  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
400
 
 
401
 
  // Check for access to global object.
402
 
  __ cmp(r0, Operand(JS_GLOBAL_OBJECT_TYPE));
403
 
  __ b(eq, &global_object);
404
 
  __ cmp(r0, Operand(JS_BUILTINS_OBJECT_TYPE));
405
 
  __ b(ne, &non_global_object);
406
 
 
407
 
  // Accessing global object: Load and invoke.
408
 
  __ bind(&global_object);
409
 
  // Check that the global object does not require access checks.
410
 
  __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
411
 
  __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
412
 
  __ b(ne, &miss);
413
 
  GenerateNormalHelper(masm, argc, true, &miss, r4);
414
 
 
415
 
  // Accessing non-global object: Check for access to global proxy.
416
 
  Label global_proxy, invoke;
417
 
  __ bind(&non_global_object);
418
 
  __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE));
419
 
  __ b(eq, &global_proxy);
420
 
  // Check that the non-global, non-global-proxy object does not
421
 
  // require access checks.
422
 
  __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
423
 
  __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
424
 
  __ b(ne, &miss);
425
 
  __ bind(&invoke);
426
 
  GenerateNormalHelper(masm, argc, false, &miss, r4);
427
 
 
428
 
  // Global object access: Check access rights.
429
 
  __ bind(&global_proxy);
430
 
  __ CheckAccessGlobalProxy(r1, r0, &miss);
431
 
  __ b(&invoke);
432
 
 
433
 
  // Cache miss: Jump to runtime.
 
643
  GenerateStringDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
 
644
 
 
645
  // r0: elements
 
646
  // Search the dictionary - put result in register r1.
 
647
  GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
 
648
 
 
649
  GenerateFunctionTailCall(masm, argc, &miss, r4);
 
650
 
434
651
  __ bind(&miss);
435
 
  GenerateMiss(masm, argc);
436
652
}
437
653
 
438
654
 
439
 
void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
 
655
static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
440
656
  // ----------- S t a t e -------------
441
657
  //  -- r2    : name
442
658
  //  -- lr    : return address
443
659
  // -----------------------------------
444
660
 
 
661
  if (id == IC::kCallIC_Miss) {
 
662
    __ IncrementCounter(&Counters::call_miss, 1, r3, r4);
 
663
  } else {
 
664
    __ IncrementCounter(&Counters::keyed_call_miss, 1, r3, r4);
 
665
  }
 
666
 
445
667
  // Get the receiver of the function from the stack.
446
668
  __ ldr(r3, MemOperand(sp, argc * kPointerSize));
447
669
 
452
674
 
453
675
  // Call the entry.
454
676
  __ mov(r0, Operand(2));
455
 
  __ mov(r1, Operand(ExternalReference(IC_Utility(kCallIC_Miss))));
 
677
  __ mov(r1, Operand(ExternalReference(IC_Utility(id))));
456
678
 
457
679
  CEntryStub stub(1);
458
680
  __ CallStub(&stub);
462
684
  __ LeaveInternalFrame();
463
685
 
464
686
  // Check if the receiver is a global object of some sort.
465
 
  Label invoke, global;
466
 
  __ ldr(r2, MemOperand(sp, argc * kPointerSize));  // receiver
467
 
  __ tst(r2, Operand(kSmiTagMask));
468
 
  __ b(eq, &invoke);
469
 
  __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
470
 
  __ b(eq, &global);
471
 
  __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
472
 
  __ b(ne, &invoke);
 
687
  // This can happen only for regular CallIC but not KeyedCallIC.
 
688
  if (id == IC::kCallIC_Miss) {
 
689
    Label invoke, global;
 
690
    __ ldr(r2, MemOperand(sp, argc * kPointerSize));  // receiver
 
691
    __ tst(r2, Operand(kSmiTagMask));
 
692
    __ b(eq, &invoke);
 
693
    __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
 
694
    __ b(eq, &global);
 
695
    __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
 
696
    __ b(ne, &invoke);
473
697
 
474
 
  // Patch the receiver on the stack.
475
 
  __ bind(&global);
476
 
  __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
477
 
  __ str(r2, MemOperand(sp, argc * kPointerSize));
 
698
    // Patch the receiver on the stack.
 
699
    __ bind(&global);
 
700
    __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
 
701
    __ str(r2, MemOperand(sp, argc * kPointerSize));
 
702
    __ bind(&invoke);
 
703
  }
478
704
 
479
705
  // Invoke the function.
480
706
  ParameterCount actual(argc);
481
 
  __ bind(&invoke);
482
707
  __ InvokeFunction(r1, actual, JUMP_FUNCTION);
483
708
}
484
709
 
485
710
 
 
711
void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
 
712
  // ----------- S t a t e -------------
 
713
  //  -- r2    : name
 
714
  //  -- lr    : return address
 
715
  // -----------------------------------
 
716
 
 
717
  GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
 
718
}
 
719
 
 
720
 
 
721
void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
 
722
  // ----------- S t a t e -------------
 
723
  //  -- r2    : name
 
724
  //  -- lr    : return address
 
725
  // -----------------------------------
 
726
 
 
727
  // Get the receiver of the function from the stack into r1.
 
728
  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
 
729
  GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
 
730
  GenerateMiss(masm, argc);
 
731
}
 
732
 
 
733
 
 
734
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
 
735
  // ----------- S t a t e -------------
 
736
  //  -- r2    : name
 
737
  //  -- lr    : return address
 
738
  // -----------------------------------
 
739
 
 
740
  GenerateCallNormal(masm, argc);
 
741
  GenerateMiss(masm, argc);
 
742
}
 
743
 
 
744
 
 
745
void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
 
746
  // ----------- S t a t e -------------
 
747
  //  -- r2    : name
 
748
  //  -- lr    : return address
 
749
  // -----------------------------------
 
750
 
 
751
  GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
 
752
}
 
753
 
 
754
 
 
755
void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
 
756
  // ----------- S t a t e -------------
 
757
  //  -- r2    : name
 
758
  //  -- lr    : return address
 
759
  // -----------------------------------
 
760
 
 
761
  // Get the receiver of the function from the stack into r1.
 
762
  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
 
763
 
 
764
  Label do_call, slow_call, slow_load, slow_reload_receiver;
 
765
  Label check_number_dictionary, check_string, lookup_monomorphic_cache;
 
766
  Label index_smi, index_string;
 
767
 
 
768
  // Check that the key is a smi.
 
769
  __ BranchOnNotSmi(r2, &check_string);
 
770
  __ bind(&index_smi);
 
771
  // Now the key is known to be a smi. This place is also jumped to from below
 
772
  // where a numeric string is converted to a smi.
 
773
 
 
774
  GenerateKeyedLoadReceiverCheck(
 
775
      masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
 
776
 
 
777
  GenerateFastArrayLoad(
 
778
      masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
 
779
  __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1, r0, r3);
 
780
 
 
781
  __ bind(&do_call);
 
782
  // receiver in r1 is not used after this point.
 
783
  // r2: key
 
784
  // r1: function
 
785
  GenerateFunctionTailCall(masm, argc, &slow_call, r0);
 
786
 
 
787
  __ bind(&check_number_dictionary);
 
788
  // r2: key
 
789
  // r3: elements map
 
790
  // r4: elements
 
791
  // Check whether the elements is a number dictionary.
 
792
  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
 
793
  __ cmp(r3, ip);
 
794
  __ b(ne, &slow_load);
 
795
  __ mov(r0, Operand(r2, ASR, kSmiTagSize));
 
796
  // r0: untagged index
 
797
  GenerateNumberDictionaryLoad(masm, &slow_load, r4, r2, r1, r0, r3, r5);
 
798
  __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1, r0, r3);
 
799
  __ jmp(&do_call);
 
800
 
 
801
  __ bind(&slow_load);
 
802
  // This branch is taken when calling KeyedCallIC_Miss is neither required
 
803
  // nor beneficial.
 
804
  __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1, r0, r3);
 
805
  __ EnterInternalFrame();
 
806
  __ push(r2);  // save the key
 
807
  __ Push(r1, r2);  // pass the receiver and the key
 
808
  __ CallRuntime(Runtime::kKeyedGetProperty, 2);
 
809
  __ pop(r2);  // restore the key
 
810
  __ LeaveInternalFrame();
 
811
  __ mov(r1, r0);
 
812
  __ jmp(&do_call);
 
813
 
 
814
  __ bind(&check_string);
 
815
  GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
 
816
 
 
817
  // The key is known to be a symbol.
 
818
  // If the receiver is a regular JS object with slow properties then do
 
819
  // a quick inline probe of the receiver's dictionary.
 
820
  // Otherwise do the monomorphic cache probe.
 
821
  GenerateKeyedLoadReceiverCheck(
 
822
      masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
 
823
 
 
824
  __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
 
825
  __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
 
826
  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
 
827
  __ cmp(r3, ip);
 
828
  __ b(ne, &lookup_monomorphic_cache);
 
829
 
 
830
  GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
 
831
  __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3);
 
832
  __ jmp(&do_call);
 
833
 
 
834
  __ bind(&lookup_monomorphic_cache);
 
835
  __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1, r0, r3);
 
836
  GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
 
837
  // Fall through on miss.
 
838
 
 
839
  __ bind(&slow_call);
 
840
  // This branch is taken if:
 
841
  // - the receiver requires boxing or access check,
 
842
  // - the key is neither smi nor symbol,
 
843
  // - the value loaded is not a function,
 
844
  // - there is hope that the runtime will create a monomorphic call stub
 
845
  //   that will get fetched next time.
 
846
  __ IncrementCounter(&Counters::keyed_call_generic_slow, 1, r0, r3);
 
847
  GenerateMiss(masm, argc);
 
848
 
 
849
  __ bind(&index_string);
 
850
  GenerateIndexFromHash(masm, r2, r3);
 
851
  // Now jump to the place where smi keys are handled.
 
852
  __ jmp(&index_smi);
 
853
}
 
854
 
 
855
 
 
856
void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
 
857
  // ----------- S t a t e -------------
 
858
  //  -- r2    : name
 
859
  //  -- lr    : return address
 
860
  // -----------------------------------
 
861
 
 
862
  GenerateCallNormal(masm, argc);
 
863
  GenerateMiss(masm, argc);
 
864
}
 
865
 
 
866
 
486
867
// Defined in ic.cc.
487
868
Object* LoadIC_Miss(Arguments args);
488
869
 
512
893
  //  -- r0    : receiver
513
894
  //  -- sp[0] : receiver
514
895
  // -----------------------------------
515
 
  Label miss, probe, global;
516
 
 
517
 
  // Check that the receiver isn't a smi.
518
 
  __ tst(r0, Operand(kSmiTagMask));
519
 
  __ b(eq, &miss);
520
 
 
521
 
  // Check that the receiver is a valid JS object.  Put the map in r3.
522
 
  __ CompareObjectType(r0, r3, r1, FIRST_JS_OBJECT_TYPE);
523
 
  __ b(lt, &miss);
524
 
  // If this assert fails, we have to check upper bound too.
525
 
  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
526
 
 
527
 
  // Check for access to global object (unlikely).
528
 
  __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE));
529
 
  __ b(eq, &global);
530
 
 
531
 
  // Check for non-global object that requires access check.
532
 
  __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
533
 
  __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
534
 
  __ b(ne, &miss);
535
 
 
536
 
  __ bind(&probe);
537
 
  GenerateDictionaryLoad(masm, &miss, r1, r0);
 
896
  Label miss;
 
897
 
 
898
  GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
 
899
 
 
900
  // r1: elements
 
901
  GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
538
902
  __ Ret();
539
903
 
540
 
  // Global object access: Check access rights.
541
 
  __ bind(&global);
542
 
  __ CheckAccessGlobalProxy(r0, r1, &miss);
543
 
  __ b(&probe);
544
 
 
545
 
  // Cache miss: Restore receiver from stack and jump to runtime.
 
904
  // Cache miss: Jump to runtime.
546
905
  __ bind(&miss);
547
906
  GenerateMiss(masm);
548
907
}
556
915
  //  -- sp[0] : receiver
557
916
  // -----------------------------------
558
917
 
 
918
  __ IncrementCounter(&Counters::load_miss, 1, r3, r4);
 
919
 
559
920
  __ mov(r3, r0);
560
921
  __ Push(r3, r2);
561
922
 
579
940
  }
580
941
  Address address_after_nop = address_after_call + Assembler::kInstrSize;
581
942
  Instr instr_after_nop = Assembler::instr_at(address_after_nop);
582
 
  ASSERT(Assembler::IsBranch(instr_after_nop));
 
943
  // There may be some reg-reg move and frame merging code to skip over before
 
944
  // the branch back from the DeferredReferenceGetKeyedValue code to the inlined
 
945
  // code.
 
946
  while (!Assembler::IsBranch(instr_after_nop)) {
 
947
    address_after_nop += Assembler::kInstrSize;
 
948
    instr_after_nop = Assembler::instr_at(address_after_nop);
 
949
  }
583
950
 
584
951
  // Find the end of the inlined code for handling the load.
585
952
  int b_offset =
591
958
}
592
959
 
593
960
 
594
 
void LoadIC::ClearInlinedVersion(Address address) {
595
 
  // Reset the map check of the inlined in-object property load (if present) to
596
 
  // guarantee failure by holding an invalid map (the null value). The offset
597
 
  // can be patched to anything.
598
 
  PatchInlinedLoad(address, Heap::null_value(), 0);
599
 
}
600
 
 
601
 
 
602
961
bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
603
962
  // Find the end of the inlined code for handling the load if this is an
604
963
  // inlined IC call site.
629
988
}
630
989
 
631
990
 
632
 
void KeyedLoadIC::ClearInlinedVersion(Address address) {
633
 
  // Reset the map check of the inlined keyed load (if present) to
634
 
  // guarantee failure by holding an invalid map (the null value).
635
 
  PatchInlinedLoad(address, Heap::null_value());
 
991
bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
 
992
  // Find the end of the inlined code for the store if there is an
 
993
  // inlined version of the store.
 
994
  Address inline_end_address;
 
995
  if (!IsInlinedICSite(address, &inline_end_address)) return false;
 
996
 
 
997
  // Compute the address of the map load instruction.
 
998
  Address ldr_map_instr_address =
 
999
      inline_end_address -
 
1000
      (CodeGenerator::GetInlinedNamedStoreInstructionsAfterPatch() *
 
1001
       Assembler::kInstrSize);
 
1002
 
 
1003
  // Update the offsets if initializing the inlined store. No reason
 
1004
  // to update the offsets when clearing the inlined version because
 
1005
  // it will bail out in the map check.
 
1006
  if (map != Heap::null_value()) {
 
1007
    // Patch the offset in the actual store instruction.
 
1008
    Address str_property_instr_address =
 
1009
        ldr_map_instr_address + 3 * Assembler::kInstrSize;
 
1010
    Instr str_property_instr = Assembler::instr_at(str_property_instr_address);
 
1011
    ASSERT(Assembler::IsStrRegisterImmediate(str_property_instr));
 
1012
    str_property_instr = Assembler::SetStrRegisterImmediateOffset(
 
1013
        str_property_instr, offset - kHeapObjectTag);
 
1014
    Assembler::instr_at_put(str_property_instr_address, str_property_instr);
 
1015
 
 
1016
    // Patch the offset in the add instruction that is part of the
 
1017
    // write barrier.
 
1018
    Address add_offset_instr_address =
 
1019
        str_property_instr_address + Assembler::kInstrSize;
 
1020
    Instr add_offset_instr = Assembler::instr_at(add_offset_instr_address);
 
1021
    ASSERT(Assembler::IsAddRegisterImmediate(add_offset_instr));
 
1022
    add_offset_instr = Assembler::SetAddRegisterImmediateOffset(
 
1023
        add_offset_instr, offset - kHeapObjectTag);
 
1024
    Assembler::instr_at_put(add_offset_instr_address, add_offset_instr);
 
1025
 
 
1026
    // Indicate that code has changed.
 
1027
    CPU::FlushICache(str_property_instr_address, 2 * Assembler::kInstrSize);
 
1028
  }
 
1029
 
 
1030
  // Patch the map check.
 
1031
  Assembler::set_target_address_at(ldr_map_instr_address,
 
1032
                                   reinterpret_cast<Address>(map));
 
1033
 
 
1034
  return true;
636
1035
}
637
1036
 
638
1037
 
643
1042
  // Patch the map check.
644
1043
  Address ldr_map_instr_address =
645
1044
      inline_end_address -
646
 
      (CodeGenerator::kInlinedKeyedLoadInstructionsAfterPatch *
 
1045
      (CodeGenerator::GetInlinedKeyedLoadInstructionsAfterPatch() *
647
1046
      Assembler::kInstrSize);
648
1047
  Assembler::set_target_address_at(ldr_map_instr_address,
649
1048
                                   reinterpret_cast<Address>(map));
651
1050
}
652
1051
 
653
1052
 
654
 
void KeyedStoreIC::ClearInlinedVersion(Address address) {
655
 
  // Insert null as the elements map to check for.  This will make
656
 
  // sure that the elements fast-case map check fails so that control
657
 
  // flows to the IC instead of the inlined version.
658
 
  PatchInlinedStore(address, Heap::null_value());
659
 
}
660
 
 
661
 
 
662
 
void KeyedStoreIC::RestoreInlinedVersion(Address address) {
663
 
  // Restore the fast-case elements map check so that the inlined
664
 
  // version can be used again.
665
 
  PatchInlinedStore(address, Heap::fixed_array_map());
666
 
}
667
 
 
668
 
 
669
1053
bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
670
1054
  // Find the end of the inlined code for handling the store if this is an
671
1055
  // inlined IC call site.
693
1077
  //  -- r1     : receiver
694
1078
  // -----------------------------------
695
1079
 
 
1080
  __ IncrementCounter(&Counters::keyed_load_miss, 1, r3, r4);
 
1081
 
696
1082
  __ Push(r1, r0);
697
1083
 
698
1084
  ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
709
1095
 
710
1096
  __ Push(r1, r0);
711
1097
 
712
 
  __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
 
1098
  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
713
1099
}
714
1100
 
715
1101
 
719
1105
  //  -- r0     : key
720
1106
  //  -- r1     : receiver
721
1107
  // -----------------------------------
722
 
  Label slow, fast, check_pixel_array, check_number_dictionary;
 
1108
  Label slow, check_string, index_smi, index_string, property_array_property;
 
1109
  Label check_pixel_array, probe_dictionary, check_number_dictionary;
723
1110
 
724
1111
  Register key = r0;
725
1112
  Register receiver = r1;
726
1113
 
727
 
  // Check that the object isn't a smi.
728
 
  __ BranchOnSmi(receiver, &slow);
729
 
  // Get the map of the receiver.
730
 
  __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset));
731
 
  // Check bit field.
732
 
  __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
733
 
  __ tst(r3, Operand(kSlowCaseBitFieldMask));
734
 
  __ b(ne, &slow);
735
 
  // Check that the object is some kind of JS object EXCEPT JS Value type.
736
 
  // In the case that the object is a value-wrapper object,
737
 
  // we enter the runtime system to make sure that indexing into string
738
 
  // objects work as intended.
739
 
  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
740
 
  __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
741
 
  __ cmp(r2, Operand(JS_OBJECT_TYPE));
742
 
  __ b(lt, &slow);
743
 
 
744
1114
  // Check that the key is a smi.
745
 
  __ BranchOnNotSmi(key, &slow);
746
 
  // Untag key into r2..
747
 
  __ mov(r2, Operand(key, ASR, kSmiTagSize));
748
 
 
749
 
  // Get the elements array of the object.
750
 
  __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
751
 
  // Check that the object is in fast mode (not dictionary).
752
 
  __ ldr(r3, FieldMemOperand(r4, HeapObject::kMapOffset));
753
 
  __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
754
 
  __ cmp(r3, ip);
755
 
  __ b(ne, &check_pixel_array);
756
 
  // Check that the key (index) is within bounds.
757
 
  __ ldr(r3, FieldMemOperand(r4, Array::kLengthOffset));
758
 
  __ cmp(r2, r3);
759
 
  __ b(hs, &slow);
760
 
  // Fast case: Do the load.
761
 
  __ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
762
 
  __ ldr(r2, MemOperand(r3, r2, LSL, kPointerSizeLog2));
763
 
  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
764
 
  __ cmp(r2, ip);
765
 
  // In case the loaded value is the_hole we have to consult GetProperty
766
 
  // to ensure the prototype chain is searched.
767
 
  __ b(eq, &slow);
768
 
  __ mov(r0, r2);
 
1115
  __ BranchOnNotSmi(key, &check_string);
 
1116
  __ bind(&index_smi);
 
1117
  // Now the key is known to be a smi. This place is also jumped to from below
 
1118
  // where a numeric string is converted to a smi.
 
1119
 
 
1120
  GenerateKeyedLoadReceiverCheck(
 
1121
      masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
 
1122
 
 
1123
  GenerateFastArrayLoad(
 
1124
      masm, receiver, key, r4, r3, r2, r0, &check_pixel_array, &slow);
 
1125
  __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3);
769
1126
  __ Ret();
770
1127
 
771
1128
  // Check whether the elements is a pixel array.
772
1129
  // r0: key
773
 
  // r2: untagged index
774
1130
  // r3: elements map
775
1131
  // r4: elements
776
1132
  __ bind(&check_pixel_array);
778
1134
  __ cmp(r3, ip);
779
1135
  __ b(ne, &check_number_dictionary);
780
1136
  __ ldr(ip, FieldMemOperand(r4, PixelArray::kLengthOffset));
 
1137
  __ mov(r2, Operand(key, ASR, kSmiTagSize));
781
1138
  __ cmp(r2, ip);
782
1139
  __ b(hs, &slow);
783
1140
  __ ldr(ip, FieldMemOperand(r4, PixelArray::kExternalPointerOffset));
788
1145
  __ bind(&check_number_dictionary);
789
1146
  // Check whether the elements is a number dictionary.
790
1147
  // r0: key
791
 
  // r2: untagged index
792
1148
  // r3: elements map
793
1149
  // r4: elements
794
1150
  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
795
1151
  __ cmp(r3, ip);
796
1152
  __ b(ne, &slow);
797
 
  GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r2, r3, r5);
798
 
  __ mov(r0, r2);
 
1153
  __ mov(r2, Operand(r0, ASR, kSmiTagSize));
 
1154
  GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r0, r2, r3, r5);
799
1155
  __ Ret();
800
1156
 
801
1157
  // Slow case, key and receiver still in r0 and r1.
802
1158
  __ bind(&slow);
803
1159
  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3);
804
1160
  GenerateRuntimeGetProperty(masm);
 
1161
 
 
1162
  __ bind(&check_string);
 
1163
  GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
 
1164
 
 
1165
  GenerateKeyedLoadReceiverCheck(
 
1166
      masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
 
1167
 
 
1168
  // If the receiver is a fast-case object, check the keyed lookup
 
1169
  // cache. Otherwise probe the dictionary.
 
1170
  __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
 
1171
  __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
 
1172
  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
 
1173
  __ cmp(r4, ip);
 
1174
  __ b(eq, &probe_dictionary);
 
1175
 
 
1176
  // Load the map of the receiver, compute the keyed lookup cache hash
 
1177
  // based on 32 bits of the map pointer and the string hash.
 
1178
  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
 
1179
  __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
 
1180
  __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
 
1181
  __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
 
1182
  __ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask));
 
1183
 
 
1184
  // Load the key (consisting of map and symbol) from the cache and
 
1185
  // check for match.
 
1186
  ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys();
 
1187
  __ mov(r4, Operand(cache_keys));
 
1188
  __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
 
1189
  __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex));  // Move r4 to symbol.
 
1190
  __ cmp(r2, r5);
 
1191
  __ b(ne, &slow);
 
1192
  __ ldr(r5, MemOperand(r4));
 
1193
  __ cmp(r0, r5);
 
1194
  __ b(ne, &slow);
 
1195
 
 
1196
  // Get field offset.
 
1197
  // r0     : key
 
1198
  // r1     : receiver
 
1199
  // r2     : receiver's map
 
1200
  // r3     : lookup cache index
 
1201
  ExternalReference cache_field_offsets
 
1202
      = ExternalReference::keyed_lookup_cache_field_offsets();
 
1203
  __ mov(r4, Operand(cache_field_offsets));
 
1204
  __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
 
1205
  __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
 
1206
  __ sub(r5, r5, r6, SetCC);
 
1207
  __ b(ge, &property_array_property);
 
1208
 
 
1209
  // Load in-object property.
 
1210
  __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
 
1211
  __ add(r6, r6, r5);  // Index from start of object.
 
1212
  __ sub(r1, r1, Operand(kHeapObjectTag));  // Remove the heap tag.
 
1213
  __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
 
1214
  __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
 
1215
  __ Ret();
 
1216
 
 
1217
  // Load property array property.
 
1218
  __ bind(&property_array_property);
 
1219
  __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
 
1220
  __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
 
1221
  __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
 
1222
  __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
 
1223
  __ Ret();
 
1224
 
 
1225
  // Do a quick inline probe of the receiver's dictionary, if it
 
1226
  // exists.
 
1227
  __ bind(&probe_dictionary);
 
1228
  // r1: receiver
 
1229
  // r0: key
 
1230
  // r3: elements
 
1231
  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
 
1232
  __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
 
1233
  GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
 
1234
  // Load the property to r0.
 
1235
  GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
 
1236
  __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3);
 
1237
  __ Ret();
 
1238
 
 
1239
  __ bind(&index_string);
 
1240
  GenerateIndexFromHash(masm, key, r3);
 
1241
  // Now jump to the place where smi keys are handled.
 
1242
  __ jmp(&index_smi);
805
1243
}
806
1244
 
807
1245
 
808
1246
void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
809
1247
  // ---------- S t a t e --------------
810
1248
  //  -- lr     : return address
811
 
  //  -- r0     : key
 
1249
  //  -- r0     : key (index)
812
1250
  //  -- r1     : receiver
813
1251
  // -----------------------------------
814
1252
  Label miss;
815
 
  Label index_not_smi;
816
1253
  Label index_out_of_range;
817
 
  Label slow_char_code;
818
 
  Label got_char_code;
819
1254
 
820
 
  Register object = r1;
 
1255
  Register receiver = r1;
821
1256
  Register index = r0;
822
 
  Register code = r2;
823
 
  Register scratch = r3;
824
 
 
825
 
  StringHelper::GenerateFastCharCodeAt(masm,
826
 
                                       object,
827
 
                                       index,
828
 
                                       scratch,
829
 
                                       code,
830
 
                                       &miss,  // When not a string.
831
 
                                       &index_not_smi,
832
 
                                       &index_out_of_range,
833
 
                                       &slow_char_code);
834
 
 
835
 
  // If we didn't bail out, code register contains smi tagged char
836
 
  // code.
837
 
  __ bind(&got_char_code);
838
 
  StringHelper::GenerateCharFromCode(masm, code, scratch, r0, JUMP_FUNCTION);
839
 
#ifdef DEBUG
840
 
  __ Abort("Unexpected fall-through from char from code tail call");
841
 
#endif
842
 
 
843
 
  // Check if key is a heap number.
844
 
  __ bind(&index_not_smi);
845
 
  __ CheckMap(index, scratch, Factory::heap_number_map(), &miss, true);
846
 
 
847
 
  // Push receiver and key on the stack (now that we know they are a
848
 
  // string and a number), and call runtime.
849
 
  __ bind(&slow_char_code);
850
 
  __ EnterInternalFrame();
851
 
  __ Push(object, index);
852
 
  __ CallRuntime(Runtime::kStringCharCodeAt, 2);
853
 
  ASSERT(!code.is(r0));
854
 
  __ mov(code, r0);
855
 
  __ LeaveInternalFrame();
856
 
 
857
 
  // Check if the runtime call returned NaN char code. If yes, return
858
 
  // undefined. Otherwise, we can continue.
859
 
  if (FLAG_debug_code) {
860
 
    __ BranchOnSmi(code, &got_char_code);
861
 
    __ ldr(scratch, FieldMemOperand(code, HeapObject::kMapOffset));
862
 
    __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
863
 
    __ cmp(scratch, ip);
864
 
    __ Assert(eq, "StringCharCodeAt must return smi or heap number");
865
 
  }
866
 
  __ LoadRoot(scratch, Heap::kNanValueRootIndex);
867
 
  __ cmp(code, scratch);
868
 
  __ b(ne, &got_char_code);
 
1257
  Register scratch1 = r2;
 
1258
  Register scratch2 = r3;
 
1259
  Register result = r0;
 
1260
 
 
1261
  StringCharAtGenerator char_at_generator(receiver,
 
1262
                                          index,
 
1263
                                          scratch1,
 
1264
                                          scratch2,
 
1265
                                          result,
 
1266
                                          &miss,  // When not a string.
 
1267
                                          &miss,  // When not a number.
 
1268
                                          &index_out_of_range,
 
1269
                                          STRING_INDEX_IS_ARRAY_INDEX);
 
1270
  char_at_generator.GenerateFast(masm);
 
1271
  __ Ret();
 
1272
 
 
1273
  ICRuntimeCallHelper call_helper;
 
1274
  char_at_generator.GenerateSlow(masm, call_helper);
 
1275
 
869
1276
  __ bind(&index_out_of_range);
870
1277
  __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
871
1278
  __ Ret();
872
1279
 
873
1280
  __ bind(&miss);
874
 
  GenerateGeneric(masm);
 
1281
  GenerateMiss(masm);
875
1282
}
876
1283
 
877
1284
 
1014
1421
    __ bind(&box_int);
1015
1422
    // Allocate a HeapNumber for the result and perform int-to-double
1016
1423
    // conversion. Use r0 for result as key is not needed any more.
1017
 
    __ AllocateHeapNumber(r0, r3, r4, &slow);
 
1424
    __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
 
1425
    __ AllocateHeapNumber(r0, r3, r4, r6, &slow);
1018
1426
 
1019
1427
    if (CpuFeatures::IsSupported(VFP3)) {
1020
1428
      CpuFeatures::Scope scope(VFP3);
1045
1453
      // Allocate a HeapNumber for the result and perform int-to-double
1046
1454
      // conversion. Don't use r0 and r1 as AllocateHeapNumber clobbers all
1047
1455
      // registers - also when jumping due to exhausted young space.
1048
 
      __ AllocateHeapNumber(r2, r3, r4, &slow);
 
1456
      __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
 
1457
      __ AllocateHeapNumber(r2, r3, r4, r6, &slow);
1049
1458
 
1050
1459
      __ vcvt_f64_u32(d0, s0);
1051
1460
      __ sub(r1, r2, Operand(kHeapObjectTag));
1082
1491
      // Wrap it into a HeapNumber. Don't use r0 and r1 as AllocateHeapNumber
1083
1492
      // clobbers all registers - also when jumping due to exhausted young
1084
1493
      // space.
1085
 
      __ AllocateHeapNumber(r4, r5, r6, &slow);
 
1494
      __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
 
1495
      __ AllocateHeapNumber(r4, r5, r7, r6, &slow);
1086
1496
 
1087
1497
      __ str(hiword, FieldMemOperand(r4, HeapNumber::kExponentOffset));
1088
1498
      __ str(loword, FieldMemOperand(r4, HeapNumber::kMantissaOffset));
1098
1508
      // Allocate a HeapNumber for the result. Don't use r0 and r1 as
1099
1509
      // AllocateHeapNumber clobbers all registers - also when jumping due to
1100
1510
      // exhausted young space.
1101
 
      __ AllocateHeapNumber(r2, r3, r4, &slow);
 
1511
      __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
 
1512
      __ AllocateHeapNumber(r2, r3, r4, r6, &slow);
1102
1513
      __ vcvt_f64_f32(d0, s0);
1103
1514
      __ sub(r1, r2, Operand(kHeapObjectTag));
1104
1515
      __ vstr(d0, r1, HeapNumber::kValueOffset);
1109
1520
      // Allocate a HeapNumber for the result. Don't use r0 and r1 as
1110
1521
      // AllocateHeapNumber clobbers all registers - also when jumping due to
1111
1522
      // exhausted young space.
1112
 
      __ AllocateHeapNumber(r3, r4, r5, &slow);
 
1523
      __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
 
1524
      __ AllocateHeapNumber(r3, r4, r5, r6, &slow);
1113
1525
      // VFP is not available, do manual single to double conversion.
1114
1526
 
1115
1527
      // r2: floating point value (binary32)
1283
1695
  __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
1284
1696
  __ cmp(r4, ip);
1285
1697
  __ b(ne, &check_pixel_array);
1286
 
  // Untag the key (for checking against untagged length in the fixed array).
1287
 
  __ mov(r4, Operand(key, ASR, kSmiTagSize));
1288
 
  // Compute address to store into and check array bounds.
 
1698
  // Check array bounds. Both the key and the length of FixedArray are smis.
1289
1699
  __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
1290
 
  __ cmp(r4, Operand(ip));
 
1700
  __ cmp(key, Operand(ip));
1291
1701
  __ b(lo, &fast);
1292
1702
 
1293
1703
  // Slow case, handle jump to runtime.
1312
1722
  __ cmp(r4, Operand(ip));
1313
1723
  __ b(hs, &slow);
1314
1724
  __ mov(r5, Operand(value, ASR, kSmiTagSize));  // Untag the value.
1315
 
  {  // Clamp the value to [0..255].
1316
 
    Label done;
1317
 
    __ tst(r5, Operand(0xFFFFFF00));
1318
 
    __ b(eq, &done);
1319
 
    __ mov(r5, Operand(0), LeaveCC, mi);  // 0 if negative.
1320
 
    __ mov(r5, Operand(255), LeaveCC, pl);  // 255 if positive.
1321
 
    __ bind(&done);
1322
 
  }
 
1725
  __ Usat(r5, 8, Operand(r5));  // Clamp the value to [0..255].
 
1726
 
1323
1727
  // Get the pointer to the external array. This clobbers elements.
1324
1728
  __ ldr(elements,
1325
1729
         FieldMemOperand(elements, PixelArray::kExternalPointerOffset));
1333
1737
  // Condition code from comparing key and array length is still available.
1334
1738
  __ b(ne, &slow);  // Only support writing to writing to array[array.length].
1335
1739
  // Check for room in the elements backing store.
1336
 
  __ mov(r4, Operand(key, ASR, kSmiTagSize));  // Untag key.
 
1740
  // Both the key and the length of FixedArray are smis.
1337
1741
  __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
1338
 
  __ cmp(r4, Operand(ip));
 
1742
  __ cmp(key, Operand(ip));
1339
1743
  __ b(hs, &slow);
1340
1744
  // Calculate key + 1 as smi.
1341
1745
  ASSERT_EQ(0, kSmiTag);
1369
1773
  __ Ret(eq);
1370
1774
  // Update write barrier for the elements array address.
1371
1775
  __ sub(r4, r5, Operand(elements));
1372
 
  __ RecordWrite(elements, r4, r5);
 
1776
  __ RecordWrite(elements, Operand(r4), r5, r6);
1373
1777
 
1374
1778
  __ Ret();
1375
1779
}
1416
1820
    // Count leading zeros.
1417
1821
    // Gets the wrong answer for 0, but we already checked for that case above.
1418
1822
    Register zeros = scratch2;
1419
 
    __ CountLeadingZeros(ival, scratch1, zeros);
 
1823
    __ CountLeadingZeros(zeros, ival, scratch1);
1420
1824
 
1421
1825
    // Compute exponent and or it into the exponent register.
1422
1826
    __ rsb(scratch1,
1561
1965
  if (CpuFeatures::IsSupported(VFP3)) {
1562
1966
    CpuFeatures::Scope scope(VFP3);
1563
1967
 
1564
 
    // vldr requires offset to be a multiple of 4 so we can not
1565
 
    // include -kHeapObjectTag into it.
1566
 
    __ sub(r5, r0, Operand(kHeapObjectTag));
1567
 
    __ vldr(d0, r5, HeapNumber::kValueOffset);
1568
1968
 
1569
1969
    if (array_type == kExternalFloatArray) {
 
1970
      // vldr requires offset to be a multiple of 4 so we can not
 
1971
      // include -kHeapObjectTag into it.
 
1972
      __ sub(r5, r0, Operand(kHeapObjectTag));
 
1973
      __ vldr(d0, r5, HeapNumber::kValueOffset);
1570
1974
      __ vcvt_f32_f64(s0, d0);
1571
1975
      __ vmov(r5, s0);
1572
1976
      __ str(r5, MemOperand(r3, r4, LSL, 2));
1573
1977
    } else {
1574
 
      Label done;
1575
 
 
1576
1978
      // Need to perform float-to-int conversion.
1577
 
      // Test for NaN.
1578
 
      __ vcmp(d0, d0);
1579
 
      // Move vector status bits to normal status bits.
1580
 
      __ vmrs(v8::internal::pc);
1581
 
      __ mov(r5, Operand(0), LeaveCC, vs);  // NaN converts to 0.
1582
 
      __ b(vs, &done);
1583
 
 
1584
 
      // Test whether exponent equal to 0x7FF (infinity or NaN).
1585
 
      __ vmov(r6, r7, d0);
1586
 
      __ mov(r5, Operand(0x7FF00000));
1587
 
      __ and_(r6, r6, Operand(r5));
1588
 
      __ teq(r6, Operand(r5));
1589
 
      __ mov(r6, Operand(0), LeaveCC, eq);
 
1979
      // Test for NaN or infinity (both give zero).
 
1980
      __ ldr(r6, FieldMemOperand(r5, HeapNumber::kExponentOffset));
 
1981
 
 
1982
      // Hoisted load.  vldr requires offset to be a multiple of 4 so we can not
 
1983
      // include -kHeapObjectTag into it.
 
1984
      __ sub(r5, r0, Operand(kHeapObjectTag));
 
1985
      __ vldr(d0, r5, HeapNumber::kValueOffset);
 
1986
 
 
1987
      __ Sbfx(r6, r6, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
 
1988
      // NaNs and Infinities have all-one exponents so they sign extend to -1.
 
1989
      __ cmp(r6, Operand(-1));
 
1990
      __ mov(r5, Operand(Smi::FromInt(0)), LeaveCC, eq);
1590
1991
 
1591
1992
      // Not infinity or NaN simply convert to int.
1592
1993
      if (IsElementTypeSigned(array_type)) {
1594
1995
      } else {
1595
1996
        __ vcvt_u32_f64(s0, d0, ne);
1596
1997
      }
1597
 
 
1598
1998
      __ vmov(r5, s0, ne);
1599
1999
 
1600
 
      __ bind(&done);
1601
2000
      switch (array_type) {
1602
2001
        case kExternalByteArray:
1603
2002
        case kExternalUnsignedByteArray:
1837
2236
}
1838
2237
 
1839
2238
 
 
2239
void StoreIC::GenerateNormal(MacroAssembler* masm) {
 
2240
  // ----------- S t a t e -------------
 
2241
  //  -- r0    : value
 
2242
  //  -- r1    : receiver
 
2243
  //  -- r2    : name
 
2244
  //  -- lr    : return address
 
2245
  // -----------------------------------
 
2246
  Label miss;
 
2247
 
 
2248
  GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
 
2249
 
 
2250
  GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
 
2251
  __ IncrementCounter(&Counters::store_normal_hit, 1, r4, r5);
 
2252
  __ Ret();
 
2253
 
 
2254
  __ bind(&miss);
 
2255
  __ IncrementCounter(&Counters::store_normal_miss, 1, r4, r5);
 
2256
  GenerateMiss(masm);
 
2257
}
 
2258
 
 
2259
 
1840
2260
#undef __
1841
2261
 
1842
2262