The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / ia32 / ic-ia32.cc @ f230a1cf

History | View | Annotate | Download (57.8 KB)

1
// Copyright 2012 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27

    
28
#include "v8.h"
29

    
30
#if V8_TARGET_ARCH_IA32
31

    
32
#include "codegen.h"
33
#include "ic-inl.h"
34
#include "runtime.h"
35
#include "stub-cache.h"
36

    
37
namespace v8 {
38
namespace internal {
39

    
40
// ----------------------------------------------------------------------------
41
// Static IC stub generators.
42
//
43

    
44
#define __ ACCESS_MASM(masm)
45

    
46

    
47
static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
48
                                            Register type,
49
                                            Label* global_object) {
50
  // Register usage:
51
  //   type: holds the receiver instance type on entry.
52
  __ cmp(type, JS_GLOBAL_OBJECT_TYPE);
53
  __ j(equal, global_object);
54
  __ cmp(type, JS_BUILTINS_OBJECT_TYPE);
55
  __ j(equal, global_object);
56
  __ cmp(type, JS_GLOBAL_PROXY_TYPE);
57
  __ j(equal, global_object);
58
}
59

    
60

    
61
// Generated code falls through if the receiver is a regular non-global
62
// JS object with slow properties and no interceptors.
63
static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
64
                                                Register receiver,
65
                                                Register r0,
66
                                                Register r1,
67
                                                Label* miss) {
68
  // Register usage:
69
  //   receiver: holds the receiver on entry and is unchanged.
70
  //   r0: used to hold receiver instance type.
71
  //       Holds the property dictionary on fall through.
72
  //   r1: used to hold receivers map.
73

    
74
  // Check that the receiver isn't a smi.
75
  __ JumpIfSmi(receiver, miss);
76

    
77
  // Check that the receiver is a valid JS object.
78
  __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset));
79
  __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
80
  __ cmp(r0, FIRST_SPEC_OBJECT_TYPE);
81
  __ j(below, miss);
82

    
83
  // If this assert fails, we have to check upper bound too.
84
  STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
85

    
86
  GenerateGlobalInstanceTypeCheck(masm, r0, miss);
87

    
88
  // Check for non-global object that requires access check.
89
  __ test_b(FieldOperand(r1, Map::kBitFieldOffset),
90
            (1 << Map::kIsAccessCheckNeeded) |
91
            (1 << Map::kHasNamedInterceptor));
92
  __ j(not_zero, miss);
93

    
94
  __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
95
  __ CheckMap(r0, masm->isolate()->factory()->hash_table_map(), miss,
96
              DONT_DO_SMI_CHECK);
97
}
98

    
99

    
100
// Helper function used to load a property from a dictionary backing
101
// storage. This function may fail to load a property even though it is
102
// in the dictionary, so code at miss_label must always call a backup
103
// property load that is complete. This function is safe to call if
104
// name is not internalized, and will jump to the miss_label in that
105
// case. The generated code assumes that the receiver has slow
106
// properties, is not a global object and does not have interceptors.
107
static void GenerateDictionaryLoad(MacroAssembler* masm,
108
                                   Label* miss_label,
109
                                   Register elements,
110
                                   Register name,
111
                                   Register r0,
112
                                   Register r1,
113
                                   Register result) {
114
  // Register use:
115
  //
116
  // elements - holds the property dictionary on entry and is unchanged.
117
  //
118
  // name - holds the name of the property on entry and is unchanged.
119
  //
120
  // Scratch registers:
121
  //
122
  // r0   - used for the index into the property dictionary
123
  //
124
  // r1   - used to hold the capacity of the property dictionary.
125
  //
126
  // result - holds the result on exit.
127

    
128
  Label done;
129

    
130
  // Probe the dictionary.
131
  NameDictionaryLookupStub::GeneratePositiveLookup(masm,
132
                                                   miss_label,
133
                                                   &done,
134
                                                   elements,
135
                                                   name,
136
                                                   r0,
137
                                                   r1);
138

    
139
  // If probing finds an entry in the dictionary, r0 contains the
140
  // index into the dictionary. Check that the value is a normal
141
  // property.
142
  __ bind(&done);
143
  const int kElementsStartOffset =
144
      NameDictionary::kHeaderSize +
145
      NameDictionary::kElementsStartIndex * kPointerSize;
146
  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
147
  __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
148
          Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
149
  __ j(not_zero, miss_label);
150

    
151
  // Get the value at the masked, scaled index.
152
  const int kValueOffset = kElementsStartOffset + kPointerSize;
153
  __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
154
}
155

    
156

    
157
// Helper function used to store a property to a dictionary backing
158
// storage. This function may fail to store a property eventhough it
159
// is in the dictionary, so code at miss_label must always call a
160
// backup property store that is complete. This function is safe to
161
// call if name is not internalized, and will jump to the miss_label in
162
// that case. The generated code assumes that the receiver has slow
163
// properties, is not a global object and does not have interceptors.
164
static void GenerateDictionaryStore(MacroAssembler* masm,
165
                                    Label* miss_label,
166
                                    Register elements,
167
                                    Register name,
168
                                    Register value,
169
                                    Register r0,
170
                                    Register r1) {
171
  // Register use:
172
  //
173
  // elements - holds the property dictionary on entry and is clobbered.
174
  //
175
  // name - holds the name of the property on entry and is unchanged.
176
  //
177
  // value - holds the value to store and is unchanged.
178
  //
179
  // r0 - used for index into the property dictionary and is clobbered.
180
  //
181
  // r1 - used to hold the capacity of the property dictionary and is clobbered.
182
  Label done;
183

    
184

    
185
  // Probe the dictionary.
186
  NameDictionaryLookupStub::GeneratePositiveLookup(masm,
187
                                                   miss_label,
188
                                                   &done,
189
                                                   elements,
190
                                                   name,
191
                                                   r0,
192
                                                   r1);
193

    
194
  // If probing finds an entry in the dictionary, r0 contains the
195
  // index into the dictionary. Check that the value is a normal
196
  // property that is not read only.
197
  __ bind(&done);
198
  const int kElementsStartOffset =
199
      NameDictionary::kHeaderSize +
200
      NameDictionary::kElementsStartIndex * kPointerSize;
201
  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
202
  const int kTypeAndReadOnlyMask =
203
      (PropertyDetails::TypeField::kMask |
204
       PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
205
  __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
206
          Immediate(kTypeAndReadOnlyMask));
207
  __ j(not_zero, miss_label);
208

    
209
  // Store the value at the masked, scaled index.
210
  const int kValueOffset = kElementsStartOffset + kPointerSize;
211
  __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
212
  __ mov(Operand(r0, 0), value);
213

    
214
  // Update write barrier. Make sure not to clobber the value.
215
  __ mov(r1, value);
216
  __ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
217
}
218

    
219

    
220
// Checks the receiver for special cases (value type, slow case bits).
221
// Falls through for regular JS object.
222
static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
223
                                           Register receiver,
224
                                           Register map,
225
                                           int interceptor_bit,
226
                                           Label* slow) {
227
  // Register use:
228
  //   receiver - holds the receiver and is unchanged.
229
  // Scratch registers:
230
  //   map - used to hold the map of the receiver.
231

    
232
  // Check that the object isn't a smi.
233
  __ JumpIfSmi(receiver, slow);
234

    
235
  // Get the map of the receiver.
236
  __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset));
237

    
238
  // Check bit field.
239
  __ test_b(FieldOperand(map, Map::kBitFieldOffset),
240
            (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
241
  __ j(not_zero, slow);
242
  // Check that the object is some kind of JS object EXCEPT JS Value type.
243
  // In the case that the object is a value-wrapper object,
244
  // we enter the runtime system to make sure that indexing
245
  // into string objects works as intended.
246
  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
247

    
248
  __ CmpInstanceType(map, JS_OBJECT_TYPE);
249
  __ j(below, slow);
250
}
251

    
252

    
253
// Loads an indexed element from a fast case array.
254
// If not_fast_array is NULL, doesn't perform the elements map check.
255
static void GenerateFastArrayLoad(MacroAssembler* masm,
256
                                  Register receiver,
257
                                  Register key,
258
                                  Register scratch,
259
                                  Register result,
260
                                  Label* not_fast_array,
261
                                  Label* out_of_range) {
262
  // Register use:
263
  //   receiver - holds the receiver and is unchanged.
264
  //   key - holds the key and is unchanged (must be a smi).
265
  // Scratch registers:
266
  //   scratch - used to hold elements of the receiver and the loaded value.
267
  //   result - holds the result on exit if the load succeeds and
268
  //            we fall through.
269

    
270
  __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
271
  if (not_fast_array != NULL) {
272
    // Check that the object is in fast mode and writable.
273
    __ CheckMap(scratch,
274
                masm->isolate()->factory()->fixed_array_map(),
275
                not_fast_array,
276
                DONT_DO_SMI_CHECK);
277
  } else {
278
    __ AssertFastElements(scratch);
279
  }
280
  // Check that the key (index) is within bounds.
281
  __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
282
  __ j(above_equal, out_of_range);
283
  // Fast case: Do the load.
284
  STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
285
  __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
286
  __ cmp(scratch, Immediate(masm->isolate()->factory()->the_hole_value()));
287
  // In case the loaded value is the_hole we have to consult GetProperty
288
  // to ensure the prototype chain is searched.
289
  __ j(equal, out_of_range);
290
  if (!result.is(scratch)) {
291
    __ mov(result, scratch);
292
  }
293
}
294

    
295

    
296
// Checks whether a key is an array index string or a unique name.
297
// Falls through if the key is a unique name.
298
static void GenerateKeyNameCheck(MacroAssembler* masm,
299
                                 Register key,
300
                                 Register map,
301
                                 Register hash,
302
                                 Label* index_string,
303
                                 Label* not_unique) {
304
  // Register use:
305
  //   key - holds the key and is unchanged. Assumed to be non-smi.
306
  // Scratch registers:
307
  //   map - used to hold the map of the key.
308
  //   hash - used to hold the hash of the key.
309
  Label unique;
310
  __ CmpObjectType(key, LAST_UNIQUE_NAME_TYPE, map);
311
  __ j(above, not_unique);
312
  STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
313
  __ j(equal, &unique);
314

    
315
  // Is the string an array index, with cached numeric value?
316
  __ mov(hash, FieldOperand(key, Name::kHashFieldOffset));
317
  __ test(hash, Immediate(Name::kContainsCachedArrayIndexMask));
318
  __ j(zero, index_string);
319

    
320
  // Is the string internalized? We already know it's a string so a single
321
  // bit test is enough.
322
  STATIC_ASSERT(kNotInternalizedTag != 0);
323
  __ test_b(FieldOperand(map, Map::kInstanceTypeOffset),
324
            kIsNotInternalizedMask);
325
  __ j(not_zero, not_unique);
326

    
327
  __ bind(&unique);
328
}
329

    
330

    
331
static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
332
                                             Register object,
333
                                             Register key,
334
                                             Register scratch1,
335
                                             Register scratch2,
336
                                             Label* unmapped_case,
337
                                             Label* slow_case) {
338
  Heap* heap = masm->isolate()->heap();
339
  Factory* factory = masm->isolate()->factory();
340

    
341
  // Check that the receiver is a JSObject. Because of the elements
342
  // map check later, we do not need to check for interceptors or
343
  // whether it requires access checks.
344
  __ JumpIfSmi(object, slow_case);
345
  // Check that the object is some kind of JSObject.
346
  __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1);
347
  __ j(below, slow_case);
348

    
349
  // Check that the key is a positive smi.
350
  __ test(key, Immediate(0x80000001));
351
  __ j(not_zero, slow_case);
352

    
353
  // Load the elements into scratch1 and check its map.
354
  Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
355
  __ mov(scratch1, FieldOperand(object, JSObject::kElementsOffset));
356
  __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
357

    
358
  // Check if element is in the range of mapped arguments. If not, jump
359
  // to the unmapped lookup with the parameter map in scratch1.
360
  __ mov(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
361
  __ sub(scratch2, Immediate(Smi::FromInt(2)));
362
  __ cmp(key, scratch2);
363
  __ j(above_equal, unmapped_case);
364

    
365
  // Load element index and check whether it is the hole.
366
  const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
367
  __ mov(scratch2, FieldOperand(scratch1,
368
                                key,
369
                                times_half_pointer_size,
370
                                kHeaderSize));
371
  __ cmp(scratch2, factory->the_hole_value());
372
  __ j(equal, unmapped_case);
373

    
374
  // Load value from context and return it. We can reuse scratch1 because
375
  // we do not jump to the unmapped lookup (which requires the parameter
376
  // map in scratch1).
377
  const int kContextOffset = FixedArray::kHeaderSize;
378
  __ mov(scratch1, FieldOperand(scratch1, kContextOffset));
379
  return FieldOperand(scratch1,
380
                      scratch2,
381
                      times_half_pointer_size,
382
                      Context::kHeaderSize);
383
}
384

    
385

    
386
static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
387
                                               Register key,
388
                                               Register parameter_map,
389
                                               Register scratch,
390
                                               Label* slow_case) {
391
  // Element is in arguments backing store, which is referenced by the
392
  // second element of the parameter_map.
393
  const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
394
  Register backing_store = parameter_map;
395
  __ mov(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
396
  Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
397
  __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
398
  __ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
399
  __ cmp(key, scratch);
400
  __ j(greater_equal, slow_case);
401
  return FieldOperand(backing_store,
402
                      key,
403
                      times_half_pointer_size,
404
                      FixedArray::kHeaderSize);
405
}
406

    
407

    
408
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
409
  // ----------- S t a t e -------------
410
  //  -- ecx    : key
411
  //  -- edx    : receiver
412
  //  -- esp[0] : return address
413
  // -----------------------------------
414
  Label slow, check_name, index_smi, index_name, property_array_property;
415
  Label probe_dictionary, check_number_dictionary;
416

    
417
  // Check that the key is a smi.
418
  __ JumpIfNotSmi(ecx, &check_name);
419
  __ bind(&index_smi);
420
  // Now the key is known to be a smi. This place is also jumped to from
421
  // where a numeric string is converted to a smi.
422

    
423
  GenerateKeyedLoadReceiverCheck(
424
      masm, edx, eax, Map::kHasIndexedInterceptor, &slow);
425

    
426
  // Check the receiver's map to see if it has fast elements.
427
  __ CheckFastElements(eax, &check_number_dictionary);
428

    
429
  GenerateFastArrayLoad(masm, edx, ecx, eax, eax, NULL, &slow);
430
  Isolate* isolate = masm->isolate();
431
  Counters* counters = isolate->counters();
432
  __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
433
  __ ret(0);
434

    
435
  __ bind(&check_number_dictionary);
436
  __ mov(ebx, ecx);
437
  __ SmiUntag(ebx);
438
  __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
439

    
440
  // Check whether the elements is a number dictionary.
441
  // edx: receiver
442
  // ebx: untagged index
443
  // ecx: key
444
  // eax: elements
445
  __ CheckMap(eax,
446
              isolate->factory()->hash_table_map(),
447
              &slow,
448
              DONT_DO_SMI_CHECK);
449
  Label slow_pop_receiver;
450
  // Push receiver on the stack to free up a register for the dictionary
451
  // probing.
452
  __ push(edx);
453
  __ LoadFromNumberDictionary(&slow_pop_receiver, eax, ecx, ebx, edx, edi, eax);
454
  // Pop receiver before returning.
455
  __ pop(edx);
456
  __ ret(0);
457

    
458
  __ bind(&slow_pop_receiver);
459
  // Pop the receiver from the stack and jump to runtime.
460
  __ pop(edx);
461

    
462
  __ bind(&slow);
463
  // Slow case: jump to runtime.
464
  // edx: receiver
465
  // ecx: key
466
  __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
467
  GenerateRuntimeGetProperty(masm);
468

    
469
  __ bind(&check_name);
470
  GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow);
471

    
472
  GenerateKeyedLoadReceiverCheck(
473
      masm, edx, eax, Map::kHasNamedInterceptor, &slow);
474

    
475
  // If the receiver is a fast-case object, check the keyed lookup
476
  // cache. Otherwise probe the dictionary.
477
  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
478
  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
479
         Immediate(isolate->factory()->hash_table_map()));
480
  __ j(equal, &probe_dictionary);
481

    
482
  // The receiver's map is still in eax, compute the keyed lookup cache hash
483
  // based on 32 bits of the map pointer and the string hash.
484
  if (FLAG_debug_code) {
485
    __ cmp(eax, FieldOperand(edx, HeapObject::kMapOffset));
486
    __ Check(equal, kMapIsNoLongerInEax);
487
  }
488
  __ mov(ebx, eax);  // Keep the map around for later.
489
  __ shr(eax, KeyedLookupCache::kMapHashShift);
490
  __ mov(edi, FieldOperand(ecx, String::kHashFieldOffset));
491
  __ shr(edi, String::kHashShift);
492
  __ xor_(eax, edi);
493
  __ and_(eax, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
494

    
495
  // Load the key (consisting of map and internalized string) from the cache and
496
  // check for match.
497
  Label load_in_object_property;
498
  static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
499
  Label hit_on_nth_entry[kEntriesPerBucket];
500
  ExternalReference cache_keys =
501
      ExternalReference::keyed_lookup_cache_keys(masm->isolate());
502

    
503
  for (int i = 0; i < kEntriesPerBucket - 1; i++) {
504
    Label try_next_entry;
505
    __ mov(edi, eax);
506
    __ shl(edi, kPointerSizeLog2 + 1);
507
    if (i != 0) {
508
      __ add(edi, Immediate(kPointerSize * i * 2));
509
    }
510
    __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
511
    __ j(not_equal, &try_next_entry);
512
    __ add(edi, Immediate(kPointerSize));
513
    __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
514
    __ j(equal, &hit_on_nth_entry[i]);
515
    __ bind(&try_next_entry);
516
  }
517

    
518
  __ lea(edi, Operand(eax, 1));
519
  __ shl(edi, kPointerSizeLog2 + 1);
520
  __ add(edi, Immediate(kPointerSize * (kEntriesPerBucket - 1) * 2));
521
  __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
522
  __ j(not_equal, &slow);
523
  __ add(edi, Immediate(kPointerSize));
524
  __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
525
  __ j(not_equal, &slow);
526

    
527
  // Get field offset.
528
  // edx     : receiver
529
  // ebx     : receiver's map
530
  // ecx     : key
531
  // eax     : lookup cache index
532
  ExternalReference cache_field_offsets =
533
      ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
534

    
535
  // Hit on nth entry.
536
  for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
537
    __ bind(&hit_on_nth_entry[i]);
538
    if (i != 0) {
539
      __ add(eax, Immediate(i));
540
    }
541
    __ mov(edi,
542
           Operand::StaticArray(eax, times_pointer_size, cache_field_offsets));
543
    __ movzx_b(eax, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
544
    __ sub(edi, eax);
545
    __ j(above_equal, &property_array_property);
546
    if (i != 0) {
547
      __ jmp(&load_in_object_property);
548
    }
549
  }
550

    
551
  // Load in-object property.
552
  __ bind(&load_in_object_property);
553
  __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceSizeOffset));
554
  __ add(eax, edi);
555
  __ mov(eax, FieldOperand(edx, eax, times_pointer_size, 0));
556
  __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
557
  __ ret(0);
558

    
559
  // Load property array property.
560
  __ bind(&property_array_property);
561
  __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset));
562
  __ mov(eax, FieldOperand(eax, edi, times_pointer_size,
563
                           FixedArray::kHeaderSize));
564
  __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
565
  __ ret(0);
566

    
567
  // Do a quick inline probe of the receiver's dictionary, if it
568
  // exists.
569
  __ bind(&probe_dictionary);
570

    
571
  __ mov(eax, FieldOperand(edx, JSObject::kMapOffset));
572
  __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
573
  GenerateGlobalInstanceTypeCheck(masm, eax, &slow);
574

    
575
  GenerateDictionaryLoad(masm, &slow, ebx, ecx, eax, edi, eax);
576
  __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
577
  __ ret(0);
578

    
579
  __ bind(&index_name);
580
  __ IndexFromHash(ebx, ecx);
581
  // Now jump to the place where smi keys are handled.
582
  __ jmp(&index_smi);
583
}
584

    
585

    
586
void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
587
  // ----------- S t a t e -------------
588
  //  -- ecx    : key (index)
589
  //  -- edx    : receiver
590
  //  -- esp[0] : return address
591
  // -----------------------------------
592
  Label miss;
593

    
594
  Register receiver = edx;
595
  Register index = ecx;
596
  Register scratch = ebx;
597
  Register result = eax;
598

    
599
  StringCharAtGenerator char_at_generator(receiver,
600
                                          index,
601
                                          scratch,
602
                                          result,
603
                                          &miss,  // When not a string.
604
                                          &miss,  // When not a number.
605
                                          &miss,  // When index out of range.
606
                                          STRING_INDEX_IS_ARRAY_INDEX);
607
  char_at_generator.GenerateFast(masm);
608
  __ ret(0);
609

    
610
  StubRuntimeCallHelper call_helper;
611
  char_at_generator.GenerateSlow(masm, call_helper);
612

    
613
  __ bind(&miss);
614
  GenerateMiss(masm, MISS);
615
}
616

    
617

    
618
void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
619
  // ----------- S t a t e -------------
620
  //  -- ecx    : key
621
  //  -- edx    : receiver
622
  //  -- esp[0] : return address
623
  // -----------------------------------
624
  Label slow;
625

    
626
  // Check that the receiver isn't a smi.
627
  __ JumpIfSmi(edx, &slow);
628

    
629
  // Check that the key is an array index, that is Uint32.
630
  __ test(ecx, Immediate(kSmiTagMask | kSmiSignMask));
631
  __ j(not_zero, &slow);
632

    
633
  // Get the map of the receiver.
634
  __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset));
635

    
636
  // Check that it has indexed interceptor and access checks
637
  // are not enabled for this object.
638
  __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset));
639
  __ and_(eax, Immediate(kSlowCaseBitFieldMask));
640
  __ cmp(eax, Immediate(1 << Map::kHasIndexedInterceptor));
641
  __ j(not_zero, &slow);
642

    
643
  // Everything is fine, call runtime.
644
  __ pop(eax);
645
  __ push(edx);  // receiver
646
  __ push(ecx);  // key
647
  __ push(eax);  // return address
648

    
649
  // Perform tail call to the entry.
650
  ExternalReference ref =
651
      ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
652
                        masm->isolate());
653
  __ TailCallExternalReference(ref, 2, 1);
654

    
655
  __ bind(&slow);
656
  GenerateMiss(masm, MISS);
657
}
658

    
659

    
660
void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
661
  // ----------- S t a t e -------------
662
  //  -- ecx    : key
663
  //  -- edx    : receiver
664
  //  -- esp[0] : return address
665
  // -----------------------------------
666
  Label slow, notin;
667
  Factory* factory = masm->isolate()->factory();
668
  Operand mapped_location =
669
      GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
670
  __ mov(eax, mapped_location);
671
  __ Ret();
672
  __ bind(&notin);
673
  // The unmapped lookup expects that the parameter map is in ebx.
674
  Operand unmapped_location =
675
      GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
676
  __ cmp(unmapped_location, factory->the_hole_value());
677
  __ j(equal, &slow);
678
  __ mov(eax, unmapped_location);
679
  __ Ret();
680
  __ bind(&slow);
681
  GenerateMiss(masm, MISS);
682
}
683

    
684

    
685
void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
686
  // ----------- S t a t e -------------
687
  //  -- eax    : value
688
  //  -- ecx    : key
689
  //  -- edx    : receiver
690
  //  -- esp[0] : return address
691
  // -----------------------------------
692
  Label slow, notin;
693
  Operand mapped_location =
694
      GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, edi, &notin, &slow);
695
  __ mov(mapped_location, eax);
696
  __ lea(ecx, mapped_location);
697
  __ mov(edx, eax);
698
  __ RecordWrite(ebx, ecx, edx, kDontSaveFPRegs);
699
  __ Ret();
700
  __ bind(&notin);
701
  // The unmapped lookup expects that the parameter map is in ebx.
702
  Operand unmapped_location =
703
      GenerateUnmappedArgumentsLookup(masm, ecx, ebx, edi, &slow);
704
  __ mov(unmapped_location, eax);
705
  __ lea(edi, unmapped_location);
706
  __ mov(edx, eax);
707
  __ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
708
  __ Ret();
709
  __ bind(&slow);
710
  GenerateMiss(masm, MISS);
711
}
712

    
713

    
714
static void KeyedStoreGenerateGenericHelper(
715
    MacroAssembler* masm,
716
    Label* fast_object,
717
    Label* fast_double,
718
    Label* slow,
719
    KeyedStoreCheckMap check_map,
720
    KeyedStoreIncrementLength increment_length) {
721
  Label transition_smi_elements;
722
  Label finish_object_store, non_double_value, transition_double_elements;
723
  Label fast_double_without_map_check;
724
  // eax: value
725
  // ecx: key (a smi)
726
  // edx: receiver
727
  // ebx: FixedArray receiver->elements
728
  // edi: receiver map
729
  // Fast case: Do the store, could either Object or double.
730
  __ bind(fast_object);
731
  if (check_map == kCheckMap) {
732
    __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
733
    __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
734
    __ j(not_equal, fast_double);
735
  }
736
  // Smi stores don't require further checks.
737
  Label non_smi_value;
738
  __ JumpIfNotSmi(eax, &non_smi_value);
739
  if (increment_length == kIncrementLength) {
740
    // Add 1 to receiver->length.
741
    __ add(FieldOperand(edx, JSArray::kLengthOffset),
742
           Immediate(Smi::FromInt(1)));
743
  }
744
  // It's irrelevant whether array is smi-only or not when writing a smi.
745
  __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
746
  __ ret(0);
747

    
748
  __ bind(&non_smi_value);
749
  // Escape to elements kind transition case.
750
  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
751
  __ CheckFastObjectElements(edi, &transition_smi_elements);
752

    
753
  // Fast elements array, store the value to the elements backing store.
754
  __ bind(&finish_object_store);
755
  if (increment_length == kIncrementLength) {
756
    // Add 1 to receiver->length.
757
    __ add(FieldOperand(edx, JSArray::kLengthOffset),
758
           Immediate(Smi::FromInt(1)));
759
  }
760
  __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
761
  // Update write barrier for the elements array address.
762
  __ mov(edx, eax);  // Preserve the value which is returned.
763
  __ RecordWriteArray(
764
      ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
765
  __ ret(0);
766

    
767
  __ bind(fast_double);
768
  if (check_map == kCheckMap) {
769
    // Check for fast double array case. If this fails, call through to the
770
    // runtime.
771
    __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
772
    __ j(not_equal, slow);
773
    // If the value is a number, store it as a double in the FastDoubleElements
774
    // array.
775
  }
776
  __ bind(&fast_double_without_map_check);
777
  __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0,
778
                                 &transition_double_elements, false);
779
  if (increment_length == kIncrementLength) {
780
    // Add 1 to receiver->length.
781
    __ add(FieldOperand(edx, JSArray::kLengthOffset),
782
           Immediate(Smi::FromInt(1)));
783
  }
784
  __ ret(0);
785

    
786
  __ bind(&transition_smi_elements);
787
  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
788

    
789
  // Transition the array appropriately depending on the value type.
790
  __ CheckMap(eax,
791
              masm->isolate()->factory()->heap_number_map(),
792
              &non_double_value,
793
              DONT_DO_SMI_CHECK);
794

    
795
  // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
796
  // and complete the store.
797
  __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
798
                                         FAST_DOUBLE_ELEMENTS,
799
                                         ebx,
800
                                         edi,
801
                                         slow);
802
  AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
803
                                                    FAST_DOUBLE_ELEMENTS);
804
  ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
805
  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
806
  __ jmp(&fast_double_without_map_check);
807

    
808
  __ bind(&non_double_value);
809
  // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
810
  __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
811
                                         FAST_ELEMENTS,
812
                                         ebx,
813
                                         edi,
814
                                         slow);
815
  mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
816
  ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
817
                                                                   slow);
818
  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
819
  __ jmp(&finish_object_store);
820

    
821
  __ bind(&transition_double_elements);
822
  // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
823
  // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
824
  // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
825
  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
826
  __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
827
                                         FAST_ELEMENTS,
828
                                         ebx,
829
                                         edi,
830
                                         slow);
831
  mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
832
  ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
833
  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
834
  __ jmp(&finish_object_store);
835
}
836

    
837

    
838
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
839
                                   StrictModeFlag strict_mode) {
840
  // ----------- S t a t e -------------
841
  //  -- eax    : value
842
  //  -- ecx    : key
843
  //  -- edx    : receiver
844
  //  -- esp[0] : return address
845
  // -----------------------------------
846
  Label slow, fast_object, fast_object_grow;
847
  Label fast_double, fast_double_grow;
848
  Label array, extra, check_if_double_array;
849

    
850
  // Check that the object isn't a smi.
851
  __ JumpIfSmi(edx, &slow);
852
  // Get the map from the receiver.
853
  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
854
  // Check that the receiver does not require access checks.  We need
855
  // to do this because this generic stub does not perform map checks.
856
  __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
857
            1 << Map::kIsAccessCheckNeeded);
858
  __ j(not_zero, &slow);
859
  // Check that the key is a smi.
860
  __ JumpIfNotSmi(ecx, &slow);
861
  __ CmpInstanceType(edi, JS_ARRAY_TYPE);
862
  __ j(equal, &array);
863
  // Check that the object is some kind of JSObject.
864
  __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
865
  __ j(below, &slow);
866

    
867
  // Object case: Check key against length in the elements array.
868
  // eax: value
869
  // edx: JSObject
870
  // ecx: key (a smi)
871
  // edi: receiver map
872
  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
873
  // Check array bounds. Both the key and the length of FixedArray are smis.
874
  __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
875
  __ j(below, &fast_object);
876

    
877
  // Slow case: call runtime.
878
  __ bind(&slow);
879
  GenerateRuntimeSetProperty(masm, strict_mode);
880

    
881
  // Extra capacity case: Check if there is extra capacity to
882
  // perform the store and update the length. Used for adding one
883
  // element to the array by writing to array[array.length].
884
  __ bind(&extra);
885
  // eax: value
886
  // edx: receiver, a JSArray
887
  // ecx: key, a smi.
888
  // ebx: receiver->elements, a FixedArray
889
  // edi: receiver map
890
  // flags: compare (ecx, edx.length())
891
  // do not leave holes in the array:
892
  __ j(not_equal, &slow);
893
  __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
894
  __ j(above_equal, &slow);
895
  __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
896
  __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
897
  __ j(not_equal, &check_if_double_array);
898
  __ jmp(&fast_object_grow);
899

    
900
  __ bind(&check_if_double_array);
901
  __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
902
  __ j(not_equal, &slow);
903
  __ jmp(&fast_double_grow);
904

    
905
  // Array case: Get the length and the elements array from the JS
906
  // array. Check that the array is in fast mode (and writable); if it
907
  // is the length is always a smi.
908
  __ bind(&array);
909
  // eax: value
910
  // edx: receiver, a JSArray
911
  // ecx: key, a smi.
912
  // edi: receiver map
913
  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
914

    
915
  // Check the key against the length in the array and fall through to the
916
  // common store code.
917
  __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // Compare smis.
918
  __ j(above_equal, &extra);
919

    
920
  KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
921
                                  &slow, kCheckMap, kDontIncrementLength);
922
  KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
923
                                  &slow, kDontCheckMap, kIncrementLength);
924
}
925

    
926

    
927
// The generated code does not accept smi keys.
928
// The generated code falls through if both probes miss.
929
void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
930
                                               int argc,
931
                                               Code::Kind kind,
932
                                               Code::ExtraICState extra_state) {
933
  // ----------- S t a t e -------------
934
  //  -- ecx                 : name
935
  //  -- edx                 : receiver
936
  // -----------------------------------
937
  Label number, non_number, non_string, boolean, probe, miss;
938

    
939
  // Probe the stub cache.
940
  Code::Flags flags = Code::ComputeFlags(kind,
941
                                         MONOMORPHIC,
942
                                         extra_state,
943
                                         Code::NORMAL,
944
                                         argc);
945
  Isolate* isolate = masm->isolate();
946
  isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, eax);
947

    
948
  // If the stub cache probing failed, the receiver might be a value.
949
  // For value objects, we use the map of the prototype objects for
950
  // the corresponding JSValue for the cache and that is what we need
951
  // to probe.
952
  //
953
  // Check for number.
954
  __ JumpIfSmi(edx, &number);
955
  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
956
  __ j(not_equal, &non_number);
957
  __ bind(&number);
958
  StubCompiler::GenerateLoadGlobalFunctionPrototype(
959
      masm, Context::NUMBER_FUNCTION_INDEX, edx);
960
  __ jmp(&probe);
961

    
962
  // Check for string.
963
  __ bind(&non_number);
964
  __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE);
965
  __ j(above_equal, &non_string);
966
  StubCompiler::GenerateLoadGlobalFunctionPrototype(
967
      masm, Context::STRING_FUNCTION_INDEX, edx);
968
  __ jmp(&probe);
969

    
970
  // Check for boolean.
971
  __ bind(&non_string);
972
  __ cmp(edx, isolate->factory()->true_value());
973
  __ j(equal, &boolean);
974
  __ cmp(edx, isolate->factory()->false_value());
975
  __ j(not_equal, &miss);
976
  __ bind(&boolean);
977
  StubCompiler::GenerateLoadGlobalFunctionPrototype(
978
      masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
979

    
980
  // Probe the stub cache for the value object.
981
  __ bind(&probe);
982
  isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
983
  __ bind(&miss);
984
}
985

    
986

    
987
static void GenerateFunctionTailCall(MacroAssembler* masm,
988
                                     int argc,
989
                                     Label* miss) {
990
  // ----------- S t a t e -------------
991
  //  -- ecx                 : name
992
  //  -- edi                 : function
993
  //  -- esp[0]              : return address
994
  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
995
  //  -- ...
996
  //  -- esp[(argc + 1) * 4] : receiver
997
  // -----------------------------------
998

    
999
  // Check that the result is not a smi.
1000
  __ JumpIfSmi(edi, miss);
1001

    
1002
  // Check that the value is a JavaScript function, fetching its map into eax.
1003
  __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
1004
  __ j(not_equal, miss);
1005

    
1006
  // Invoke the function.
1007
  ParameterCount actual(argc);
1008
  __ InvokeFunction(edi, actual, JUMP_FUNCTION,
1009
                    NullCallWrapper(), CALL_AS_METHOD);
1010
}
1011

    
1012

    
1013
// The generated code falls through if the call should be handled by runtime.
1014
void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
1015
  // ----------- S t a t e -------------
1016
  //  -- ecx                 : name
1017
  //  -- esp[0]              : return address
1018
  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1019
  //  -- ...
1020
  //  -- esp[(argc + 1) * 4] : receiver
1021
  // -----------------------------------
1022
  Label miss;
1023

    
1024
  // Get the receiver of the function from the stack; 1 ~ return address.
1025
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1026

    
1027
  GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
1028

    
1029
  // eax: elements
1030
  // Search the dictionary placing the result in edi.
1031
  GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
1032
  GenerateFunctionTailCall(masm, argc, &miss);
1033

    
1034
  __ bind(&miss);
1035
}
1036

    
1037

    
1038
void CallICBase::GenerateMiss(MacroAssembler* masm,
1039
                              int argc,
1040
                              IC::UtilityId id,
1041
                              Code::ExtraICState extra_state) {
1042
  // ----------- S t a t e -------------
1043
  //  -- ecx                 : name
1044
  //  -- esp[0]              : return address
1045
  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1046
  //  -- ...
1047
  //  -- esp[(argc + 1) * 4] : receiver
1048
  // -----------------------------------
1049

    
1050
  Counters* counters = masm->isolate()->counters();
1051
  if (id == IC::kCallIC_Miss) {
1052
    __ IncrementCounter(counters->call_miss(), 1);
1053
  } else {
1054
    __ IncrementCounter(counters->keyed_call_miss(), 1);
1055
  }
1056

    
1057
  // Get the receiver of the function from the stack; 1 ~ return address.
1058
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1059

    
1060
  {
1061
    FrameScope scope(masm, StackFrame::INTERNAL);
1062

    
1063
    // Push the receiver and the name of the function.
1064
    __ push(edx);
1065
    __ push(ecx);
1066

    
1067
    // Call the entry.
1068
    CEntryStub stub(1);
1069
    __ mov(eax, Immediate(2));
1070
    __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate())));
1071
    __ CallStub(&stub);
1072

    
1073
    // Move result to edi and exit the internal frame.
1074
    __ mov(edi, eax);
1075
  }
1076

    
1077
  // Check if the receiver is a global object of some sort.
1078
  // This can happen only for regular CallIC but not KeyedCallIC.
1079
  if (id == IC::kCallIC_Miss) {
1080
    Label invoke, global;
1081
    __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
1082
    __ JumpIfSmi(edx, &invoke, Label::kNear);
1083
    __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1084
    __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1085
    __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
1086
    __ j(equal, &global, Label::kNear);
1087
    __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
1088
    __ j(not_equal, &invoke, Label::kNear);
1089

    
1090
    // Patch the receiver on the stack.
1091
    __ bind(&global);
1092
    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1093
    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1094
    __ bind(&invoke);
1095
  }
1096

    
1097
  // Invoke the function.
1098
  CallKind call_kind = CallICBase::Contextual::decode(extra_state)
1099
      ? CALL_AS_FUNCTION
1100
      : CALL_AS_METHOD;
1101
  ParameterCount actual(argc);
1102
  __ InvokeFunction(edi,
1103
                    actual,
1104
                    JUMP_FUNCTION,
1105
                    NullCallWrapper(),
1106
                    call_kind);
1107
}
1108

    
1109

    
1110
void CallIC::GenerateMegamorphic(MacroAssembler* masm,
1111
                                 int argc,
1112
                                 Code::ExtraICState extra_state) {
1113
  // ----------- S t a t e -------------
1114
  //  -- ecx                 : name
1115
  //  -- esp[0]              : return address
1116
  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1117
  //  -- ...
1118
  //  -- esp[(argc + 1) * 4] : receiver
1119
  // -----------------------------------
1120

    
1121
  // Get the receiver of the function from the stack; 1 ~ return address.
1122
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1123
  CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC,
1124
                                            extra_state);
1125

    
1126
  GenerateMiss(masm, argc, extra_state);
1127
}
1128

    
1129

    
1130
void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1131
  // ----------- S t a t e -------------
1132
  //  -- ecx                 : name
1133
  //  -- esp[0]              : return address
1134
  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1135
  //  -- ...
1136
  //  -- esp[(argc + 1) * 4] : receiver
1137
  // -----------------------------------
1138

    
1139
  // Get the receiver of the function from the stack; 1 ~ return address.
1140
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1141

    
1142
  Label do_call, slow_call, slow_load, slow_reload_receiver;
1143
  Label check_number_dictionary, check_name, lookup_monomorphic_cache;
1144
  Label index_smi, index_name;
1145

    
1146
  // Check that the key is a smi.
1147
  __ JumpIfNotSmi(ecx, &check_name);
1148

    
1149
  __ bind(&index_smi);
1150
  // Now the key is known to be a smi. This place is also jumped to from
1151
  // where a numeric string is converted to a smi.
1152

    
1153
  GenerateKeyedLoadReceiverCheck(
1154
      masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
1155

    
1156
  GenerateFastArrayLoad(
1157
      masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
1158
  Isolate* isolate = masm->isolate();
1159
  Counters* counters = isolate->counters();
1160
  __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
1161

    
1162
  __ bind(&do_call);
1163
  // receiver in edx is not used after this point.
1164
  // ecx: key
1165
  // edi: function
1166
  GenerateFunctionTailCall(masm, argc, &slow_call);
1167

    
1168
  __ bind(&check_number_dictionary);
1169
  // eax: elements
1170
  // ecx: smi key
1171
  // Check whether the elements is a number dictionary.
1172
  __ CheckMap(eax,
1173
              isolate->factory()->hash_table_map(),
1174
              &slow_load,
1175
              DONT_DO_SMI_CHECK);
1176
  __ mov(ebx, ecx);
1177
  __ SmiUntag(ebx);
1178
  // ebx: untagged index
1179
  // Receiver in edx will be clobbered, need to reload it on miss.
1180
  __ LoadFromNumberDictionary(
1181
      &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
1182
  __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
1183
  __ jmp(&do_call);
1184

    
1185
  __ bind(&slow_reload_receiver);
1186
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1187

    
1188
  __ bind(&slow_load);
1189
  // This branch is taken when calling KeyedCallIC_Miss is neither required
1190
  // nor beneficial.
1191
  __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
1192

    
1193
  {
1194
    FrameScope scope(masm, StackFrame::INTERNAL);
1195
    __ push(ecx);  // save the key
1196
    __ push(edx);  // pass the receiver
1197
    __ push(ecx);  // pass the key
1198
    __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1199
    __ pop(ecx);  // restore the key
1200
    // Leave the internal frame.
1201
  }
1202

    
1203
  __ mov(edi, eax);
1204
  __ jmp(&do_call);
1205

    
1206
  __ bind(&check_name);
1207
  GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow_call);
1208

    
1209
  // The key is known to be a unique name.
1210
  // If the receiver is a regular JS object with slow properties then do
1211
  // a quick inline probe of the receiver's dictionary.
1212
  // Otherwise do the monomorphic cache probe.
1213
  GenerateKeyedLoadReceiverCheck(
1214
      masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
1215

    
1216
  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
1217
  __ CheckMap(ebx,
1218
              isolate->factory()->hash_table_map(),
1219
              &lookup_monomorphic_cache,
1220
              DONT_DO_SMI_CHECK);
1221

    
1222
  GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
1223
  __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
1224
  __ jmp(&do_call);
1225

    
1226
  __ bind(&lookup_monomorphic_cache);
1227
  __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
1228
  CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC,
1229
                                            Code::kNoExtraICState);
1230
  // Fall through on miss.
1231

    
1232
  __ bind(&slow_call);
1233
  // This branch is taken if:
1234
  // - the receiver requires boxing or access check,
1235
  // - the key is neither smi nor a unique name,
1236
  // - the value loaded is not a function,
1237
  // - there is hope that the runtime will create a monomorphic call stub
1238
  //   that will get fetched next time.
1239
  __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
1240
  GenerateMiss(masm, argc);
1241

    
1242
  __ bind(&index_name);
1243
  __ IndexFromHash(ebx, ecx);
1244
  // Now jump to the place where smi keys are handled.
1245
  __ jmp(&index_smi);
1246
}
1247

    
1248

    
1249
void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
1250
                                             int argc) {
1251
  // ----------- S t a t e -------------
1252
  //  -- ecx                 : name
1253
  //  -- esp[0]              : return address
1254
  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1255
  //  -- ...
1256
  //  -- esp[(argc + 1) * 4] : receiver
1257
  // -----------------------------------
1258
  Label slow, notin;
1259
  Factory* factory = masm->isolate()->factory();
1260
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1261
  Operand mapped_location =
1262
      GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
1263
  __ mov(edi, mapped_location);
1264
  GenerateFunctionTailCall(masm, argc, &slow);
1265
  __ bind(&notin);
1266
  // The unmapped lookup expects that the parameter map is in ebx.
1267
  Operand unmapped_location =
1268
      GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
1269
  __ cmp(unmapped_location, factory->the_hole_value());
1270
  __ j(equal, &slow);
1271
  __ mov(edi, unmapped_location);
1272
  GenerateFunctionTailCall(masm, argc, &slow);
1273
  __ bind(&slow);
1274
  GenerateMiss(masm, argc);
1275
}
1276

    
1277

    
1278
void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
1279
  // ----------- S t a t e -------------
1280
  //  -- ecx                 : name
1281
  //  -- esp[0]              : return address
1282
  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1283
  //  -- ...
1284
  //  -- esp[(argc + 1) * 4] : receiver
1285
  // -----------------------------------
1286

    
1287
  // Check if the name is really a name.
1288
  Label miss;
1289
  __ JumpIfSmi(ecx, &miss);
1290
  Condition cond = masm->IsObjectNameType(ecx, eax, eax);
1291
  __ j(NegateCondition(cond), &miss);
1292
  CallICBase::GenerateNormal(masm, argc);
1293
  __ bind(&miss);
1294
  GenerateMiss(masm, argc);
1295
}
1296

    
1297

    
1298
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1299
  // ----------- S t a t e -------------
1300
  //  -- ecx    : name
1301
  //  -- edx    : receiver
1302
  //  -- esp[0] : return address
1303
  // -----------------------------------
1304

    
1305
  // Probe the stub cache.
1306
  Code::Flags flags = Code::ComputeFlags(
1307
      Code::HANDLER, MONOMORPHIC, Code::kNoExtraICState,
1308
      Code::NORMAL, Code::LOAD_IC);
1309
  masm->isolate()->stub_cache()->GenerateProbe(
1310
      masm, flags, edx, ecx, ebx, eax);
1311

    
1312
  // Cache miss: Jump to runtime.
1313
  GenerateMiss(masm);
1314
}
1315

    
1316

    
1317
void LoadIC::GenerateNormal(MacroAssembler* masm) {
1318
  // ----------- S t a t e -------------
1319
  //  -- ecx    : name
1320
  //  -- edx    : receiver
1321
  //  -- esp[0] : return address
1322
  // -----------------------------------
1323
  Label miss;
1324

    
1325
  GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
1326

    
1327
  // eax: elements
1328
  // Search the dictionary placing the result in eax.
1329
  GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, eax);
1330
  __ ret(0);
1331

    
1332
  // Cache miss: Jump to runtime.
1333
  __ bind(&miss);
1334
  GenerateMiss(masm);
1335
}
1336

    
1337

    
1338
void LoadIC::GenerateMiss(MacroAssembler* masm) {
1339
  // ----------- S t a t e -------------
1340
  //  -- ecx    : name
1341
  //  -- edx    : receiver
1342
  //  -- esp[0] : return address
1343
  // -----------------------------------
1344

    
1345
  __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
1346

    
1347
  __ pop(ebx);
1348
  __ push(edx);  // receiver
1349
  __ push(ecx);  // name
1350
  __ push(ebx);  // return address
1351

    
1352
  // Perform tail call to the entry.
1353
  ExternalReference ref =
1354
      ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
1355
  __ TailCallExternalReference(ref, 2, 1);
1356
}
1357

    
1358

    
1359
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1360
  // ----------- S t a t e -------------
1361
  //  -- ecx    : key
1362
  //  -- edx    : receiver
1363
  //  -- esp[0] : return address
1364
  // -----------------------------------
1365

    
1366
  __ pop(ebx);
1367
  __ push(edx);  // receiver
1368
  __ push(ecx);  // name
1369
  __ push(ebx);  // return address
1370

    
1371
  // Perform tail call to the entry.
1372
  __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
1373
}
1374

    
1375

    
1376
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
1377
  // ----------- S t a t e -------------
1378
  //  -- ecx    : key
1379
  //  -- edx    : receiver
1380
  //  -- esp[0] : return address
1381
  // -----------------------------------
1382

    
1383
  __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1);
1384

    
1385
  __ pop(ebx);
1386
  __ push(edx);  // receiver
1387
  __ push(ecx);  // name
1388
  __ push(ebx);  // return address
1389

    
1390
  // Perform tail call to the entry.
1391
  ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
1392
      ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
1393
                          masm->isolate())
1394
      : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
1395
  __ TailCallExternalReference(ref, 2, 1);
1396
}
1397

    
1398

    
1399
void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1400
  // ----------- S t a t e -------------
1401
  //  -- ecx    : key
1402
  //  -- edx    : receiver
1403
  //  -- esp[0] : return address
1404
  // -----------------------------------
1405

    
1406
  __ pop(ebx);
1407
  __ push(edx);  // receiver
1408
  __ push(ecx);  // name
1409
  __ push(ebx);  // return address
1410

    
1411
  // Perform tail call to the entry.
1412
  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
1413
}
1414

    
1415

    
1416
void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
1417
                                  StrictModeFlag strict_mode) {
1418
  // ----------- S t a t e -------------
1419
  //  -- eax    : value
1420
  //  -- ecx    : name
1421
  //  -- edx    : receiver
1422
  //  -- esp[0] : return address
1423
  // -----------------------------------
1424

    
1425
  Code::Flags flags = Code::ComputeFlags(
1426
      Code::HANDLER, MONOMORPHIC, strict_mode,
1427
      Code::NORMAL, Code::STORE_IC);
1428
  masm->isolate()->stub_cache()->GenerateProbe(
1429
      masm, flags, edx, ecx, ebx, no_reg);
1430

    
1431
  // Cache miss: Jump to runtime.
1432
  GenerateMiss(masm);
1433
}
1434

    
1435

    
1436
void StoreIC::GenerateMiss(MacroAssembler* masm) {
1437
  // ----------- S t a t e -------------
1438
  //  -- eax    : value
1439
  //  -- ecx    : name
1440
  //  -- edx    : receiver
1441
  //  -- esp[0] : return address
1442
  // -----------------------------------
1443

    
1444
  __ pop(ebx);
1445
  __ push(edx);
1446
  __ push(ecx);
1447
  __ push(eax);
1448
  __ push(ebx);
1449

    
1450
  // Perform tail call to the entry.
1451
  ExternalReference ref =
1452
      ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
1453
  __ TailCallExternalReference(ref, 3, 1);
1454
}
1455

    
1456

    
1457
void StoreIC::GenerateNormal(MacroAssembler* masm) {
1458
  // ----------- S t a t e -------------
1459
  //  -- eax    : value
1460
  //  -- ecx    : name
1461
  //  -- edx    : receiver
1462
  //  -- esp[0] : return address
1463
  // -----------------------------------
1464

    
1465
  Label miss, restore_miss;
1466

    
1467
  GenerateNameDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
1468

    
1469
  // A lot of registers are needed for storing to slow case
1470
  // objects. Push and restore receiver but rely on
1471
  // GenerateDictionaryStore preserving the value and name.
1472
  __ push(edx);
1473
  GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
1474
  __ Drop(1);
1475
  Counters* counters = masm->isolate()->counters();
1476
  __ IncrementCounter(counters->store_normal_hit(), 1);
1477
  __ ret(0);
1478

    
1479
  __ bind(&restore_miss);
1480
  __ pop(edx);
1481

    
1482
  __ bind(&miss);
1483
  __ IncrementCounter(counters->store_normal_miss(), 1);
1484
  GenerateMiss(masm);
1485
}
1486

    
1487

    
1488
void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1489
                                         StrictModeFlag strict_mode) {
1490
  // ----------- S t a t e -------------
1491
  //  -- eax    : value
1492
  //  -- ecx    : name
1493
  //  -- edx    : receiver
1494
  //  -- esp[0] : return address
1495
  // -----------------------------------
1496
  __ pop(ebx);
1497
  __ push(edx);
1498
  __ push(ecx);
1499
  __ push(eax);
1500
  __ push(Immediate(Smi::FromInt(NONE)));  // PropertyAttributes
1501
  __ push(Immediate(Smi::FromInt(strict_mode)));
1502
  __ push(ebx);  // return address
1503

    
1504
  // Do tail-call to runtime routine.
1505
  __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1506
}
1507

    
1508

    
1509
void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1510
                                              StrictModeFlag strict_mode) {
1511
  // ----------- S t a t e -------------
1512
  //  -- eax    : value
1513
  //  -- ecx    : key
1514
  //  -- edx    : receiver
1515
  //  -- esp[0] : return address
1516
  // -----------------------------------
1517

    
1518
  __ pop(ebx);
1519
  __ push(edx);
1520
  __ push(ecx);
1521
  __ push(eax);
1522
  __ push(Immediate(Smi::FromInt(NONE)));         // PropertyAttributes
1523
  __ push(Immediate(Smi::FromInt(strict_mode)));  // Strict mode.
1524
  __ push(ebx);   // return address
1525

    
1526
  // Do tail-call to runtime routine.
1527
  __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1528
}
1529

    
1530

    
1531
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
1532
  // ----------- S t a t e -------------
1533
  //  -- eax    : value
1534
  //  -- ecx    : key
1535
  //  -- edx    : receiver
1536
  //  -- esp[0] : return address
1537
  // -----------------------------------
1538

    
1539
  __ pop(ebx);
1540
  __ push(edx);
1541
  __ push(ecx);
1542
  __ push(eax);
1543
  __ push(ebx);
1544

    
1545
  // Do tail-call to runtime routine.
1546
  ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
1547
      ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1548
                          masm->isolate())
1549
      : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1550
  __ TailCallExternalReference(ref, 3, 1);
1551
}
1552

    
1553

    
1554
void StoreIC::GenerateSlow(MacroAssembler* masm) {
1555
  // ----------- S t a t e -------------
1556
  //  -- eax    : value
1557
  //  -- ecx    : key
1558
  //  -- edx    : receiver
1559
  //  -- esp[0] : return address
1560
  // -----------------------------------
1561

    
1562
  __ pop(ebx);
1563
  __ push(edx);
1564
  __ push(ecx);
1565
  __ push(eax);
1566
  __ push(ebx);   // return address
1567

    
1568
  // Do tail-call to runtime routine.
1569
  ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate());
1570
  __ TailCallExternalReference(ref, 3, 1);
1571
}
1572

    
1573

    
1574
void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1575
  // ----------- S t a t e -------------
1576
  //  -- eax    : value
1577
  //  -- ecx    : key
1578
  //  -- edx    : receiver
1579
  //  -- esp[0] : return address
1580
  // -----------------------------------
1581

    
1582
  __ pop(ebx);
1583
  __ push(edx);
1584
  __ push(ecx);
1585
  __ push(eax);
1586
  __ push(ebx);   // return address
1587

    
1588
  // Do tail-call to runtime routine.
1589
  ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1590
  __ TailCallExternalReference(ref, 3, 1);
1591
}
1592

    
1593

    
1594
#undef __
1595

    
1596

    
1597
Condition CompareIC::ComputeCondition(Token::Value op) {
1598
  switch (op) {
1599
    case Token::EQ_STRICT:
1600
    case Token::EQ:
1601
      return equal;
1602
    case Token::LT:
1603
      return less;
1604
    case Token::GT:
1605
      return greater;
1606
    case Token::LTE:
1607
      return less_equal;
1608
    case Token::GTE:
1609
      return greater_equal;
1610
    default:
1611
      UNREACHABLE();
1612
      return no_condition;
1613
  }
1614
}
1615

    
1616

    
1617
bool CompareIC::HasInlinedSmiCode(Address address) {
1618
  // The address of the instruction following the call.
1619
  Address test_instruction_address =
1620
      address + Assembler::kCallTargetAddressOffset;
1621

    
1622
  // If the instruction following the call is not a test al, nothing
1623
  // was inlined.
1624
  return *test_instruction_address == Assembler::kTestAlByte;
1625
}
1626

    
1627

    
1628
void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
1629
  // The address of the instruction following the call.
1630
  Address test_instruction_address =
1631
      address + Assembler::kCallTargetAddressOffset;
1632

    
1633
  // If the instruction following the call is not a test al, nothing
1634
  // was inlined.
1635
  if (*test_instruction_address != Assembler::kTestAlByte) {
1636
    ASSERT(*test_instruction_address == Assembler::kNopByte);
1637
    return;
1638
  }
1639

    
1640
  Address delta_address = test_instruction_address + 1;
1641
  // The delta to the start of the map check instruction and the
1642
  // condition code uses at the patched jump.
1643
  int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
1644
  if (FLAG_trace_ic) {
1645
    PrintF("[  patching ic at %p, test=%p, delta=%d\n",
1646
           address, test_instruction_address, delta);
1647
  }
1648

    
1649
  // Patch with a short conditional jump. Enabling means switching from a short
1650
  // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the
1651
  // reverse operation of that.
1652
  Address jmp_address = test_instruction_address - delta;
1653
  ASSERT((check == ENABLE_INLINED_SMI_CHECK)
1654
         ? (*jmp_address == Assembler::kJncShortOpcode ||
1655
            *jmp_address == Assembler::kJcShortOpcode)
1656
         : (*jmp_address == Assembler::kJnzShortOpcode ||
1657
            *jmp_address == Assembler::kJzShortOpcode));
1658
  Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
1659
      ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
1660
      : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
1661
  *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
1662
}
1663

    
1664

    
1665
} }  // namespace v8::internal
1666

    
1667
#endif  // V8_TARGET_ARCH_IA32