~yolanda.robla/ubuntu/trusty/nodejs/add_distribution

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2013-08-14 00:16:46 UTC
  • mfrom: (7.1.40 sid)
  • Revision ID: package-import@ubuntu.com-20130814001646-bzlysfh8sd6mukbo
Tags: 0.10.15~dfsg1-4
* Update 2005 patch, adding a handful of tests that can fail on
  slow platforms.
* Add 1004 patch to fix test failures when writing NaN to buffer
  on mipsel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2011 the V8 project authors. All rights reserved.
 
1
// Copyright 2012 the V8 project authors. All rights reserved.
2
2
// Redistribution and use in source and binary forms, with or without
3
3
// modification, are permitted provided that the following conditions are
4
4
// met:
212
212
 
213
213
  // Update write barrier. Make sure not to clobber the value.
214
214
  __ mov(r1, value);
215
 
  __ RecordWrite(elements, r0, r1);
 
215
  __ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
216
216
}
217
217
 
218
218
 
219
219
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
220
220
  // ----------- S t a t e -------------
221
 
  //  -- eax    : receiver
222
221
  //  -- ecx    : name
 
222
  //  -- edx    : receiver
223
223
  //  -- esp[0] : return address
224
224
  // -----------------------------------
225
225
  Label miss;
226
226
 
227
 
  StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
 
227
  StubCompiler::GenerateLoadArrayLength(masm, edx, eax, &miss);
228
228
  __ bind(&miss);
229
229
  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
230
230
}
233
233
void LoadIC::GenerateStringLength(MacroAssembler* masm,
234
234
                                  bool support_wrappers) {
235
235
  // ----------- S t a t e -------------
236
 
  //  -- eax    : receiver
237
236
  //  -- ecx    : name
 
237
  //  -- edx    : receiver
238
238
  //  -- esp[0] : return address
239
239
  // -----------------------------------
240
240
  Label miss;
241
241
 
242
 
  StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss,
 
242
  StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss,
243
243
                                         support_wrappers);
244
244
  __ bind(&miss);
245
245
  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
248
248
 
249
249
void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
250
250
  // ----------- S t a t e -------------
251
 
  //  -- eax    : receiver
252
251
  //  -- ecx    : name
 
252
  //  -- edx    : receiver
253
253
  //  -- esp[0] : return address
254
254
  // -----------------------------------
255
255
  Label miss;
256
256
 
257
 
  StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
 
257
  StubCompiler::GenerateLoadFunctionPrototype(masm, edx, eax, ebx, &miss);
258
258
  __ bind(&miss);
259
259
  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
260
260
}
326
326
  // Fast case: Do the load.
327
327
  STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
328
328
  __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
329
 
  __ cmp(Operand(scratch), Immediate(FACTORY->the_hole_value()));
 
329
  __ cmp(scratch, Immediate(FACTORY->the_hole_value()));
330
330
  // In case the loaded value is the_hole we have to consult GetProperty
331
331
  // to ensure the prototype chain is searched.
332
332
  __ j(equal, out_of_range);
383
383
  __ j(below, slow_case);
384
384
 
385
385
  // Check that the key is a positive smi.
386
 
  __ test(key, Immediate(0x8000001));
 
386
  __ test(key, Immediate(0x80000001));
387
387
  __ j(not_zero, slow_case);
388
388
 
389
389
  // Load the elements into scratch1 and check its map.
394
394
  // Check if element is in the range of mapped arguments. If not, jump
395
395
  // to the unmapped lookup with the parameter map in scratch1.
396
396
  __ mov(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
397
 
  __ sub(Operand(scratch2), Immediate(Smi::FromInt(2)));
398
 
  __ cmp(key, Operand(scratch2));
399
 
  __ j(greater_equal, unmapped_case);
 
397
  __ sub(scratch2, Immediate(Smi::FromInt(2)));
 
398
  __ cmp(key, scratch2);
 
399
  __ j(above_equal, unmapped_case);
400
400
 
401
401
  // Load element index and check whether it is the hole.
402
402
  const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
432
432
  Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
433
433
  __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
434
434
  __ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
435
 
  __ cmp(key, Operand(scratch));
 
435
  __ cmp(key, scratch);
436
436
  __ j(greater_equal, slow_case);
437
437
  return FieldOperand(backing_store,
438
438
                      key,
443
443
 
444
444
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
445
445
  // ----------- S t a t e -------------
446
 
  //  -- eax    : key
 
446
  //  -- ecx    : key
447
447
  //  -- edx    : receiver
448
448
  //  -- esp[0] : return address
449
449
  // -----------------------------------
451
451
  Label probe_dictionary, check_number_dictionary;
452
452
 
453
453
  // Check that the key is a smi.
454
 
  __ JumpIfNotSmi(eax, &check_string);
 
454
  __ JumpIfNotSmi(ecx, &check_string);
455
455
  __ bind(&index_smi);
456
456
  // Now the key is known to be a smi. This place is also jumped to from
457
457
  // where a numeric string is converted to a smi.
458
458
 
459
459
  GenerateKeyedLoadReceiverCheck(
460
 
      masm, edx, ecx, Map::kHasIndexedInterceptor, &slow);
 
460
      masm, edx, eax, Map::kHasIndexedInterceptor, &slow);
461
461
 
462
462
  // Check the receiver's map to see if it has fast elements.
463
 
  __ CheckFastElements(ecx, &check_number_dictionary);
 
463
  __ CheckFastElements(eax, &check_number_dictionary);
464
464
 
465
 
  GenerateFastArrayLoad(masm,
466
 
                        edx,
467
 
                        eax,
468
 
                        ecx,
469
 
                        eax,
470
 
                        NULL,
471
 
                        &slow);
 
465
  GenerateFastArrayLoad(masm, edx, ecx, eax, eax, NULL, &slow);
472
466
  Isolate* isolate = masm->isolate();
473
467
  Counters* counters = isolate->counters();
474
468
  __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
475
469
  __ ret(0);
476
470
 
477
471
  __ bind(&check_number_dictionary);
478
 
  __ mov(ebx, eax);
 
472
  __ mov(ebx, ecx);
479
473
  __ SmiUntag(ebx);
480
 
  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
 
474
  __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
481
475
 
482
476
  // Check whether the elements is a number dictionary.
483
477
  // edx: receiver
484
478
  // ebx: untagged index
485
 
  // eax: key
486
 
  // ecx: elements
487
 
  __ CheckMap(ecx,
 
479
  // ecx: key
 
480
  // eax: elements
 
481
  __ CheckMap(eax,
488
482
              isolate->factory()->hash_table_map(),
489
483
              &slow,
490
484
              DONT_DO_SMI_CHECK);
492
486
  // Push receiver on the stack to free up a register for the dictionary
493
487
  // probing.
494
488
  __ push(edx);
495
 
  __ LoadFromNumberDictionary(&slow_pop_receiver,
496
 
                              ecx,
497
 
                              eax,
498
 
                              ebx,
499
 
                              edx,
500
 
                              edi,
501
 
                              eax);
 
489
  __ LoadFromNumberDictionary(&slow_pop_receiver, eax, ecx, ebx, edx, edi, eax);
502
490
  // Pop receiver before returning.
503
491
  __ pop(edx);
504
492
  __ ret(0);
510
498
  __ bind(&slow);
511
499
  // Slow case: jump to runtime.
512
500
  // edx: receiver
513
 
  // eax: key
 
501
  // ecx: key
514
502
  __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
515
503
  GenerateRuntimeGetProperty(masm);
516
504
 
517
505
  __ bind(&check_string);
518
 
  GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow);
 
506
  GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow);
519
507
 
520
508
  GenerateKeyedLoadReceiverCheck(
521
 
      masm, edx, ecx, Map::kHasNamedInterceptor, &slow);
 
509
      masm, edx, eax, Map::kHasNamedInterceptor, &slow);
522
510
 
523
511
  // If the receiver is a fast-case object, check the keyed lookup
524
512
  // cache. Otherwise probe the dictionary.
527
515
         Immediate(isolate->factory()->hash_table_map()));
528
516
  __ j(equal, &probe_dictionary);
529
517
 
530
 
  // Load the map of the receiver, compute the keyed lookup cache hash
 
518
  // The receiver's map is still in eax, compute the keyed lookup cache hash
531
519
  // based on 32 bits of the map pointer and the string hash.
532
 
  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
533
 
  __ mov(ecx, ebx);
534
 
  __ shr(ecx, KeyedLookupCache::kMapHashShift);
535
 
  __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
 
520
  if (FLAG_debug_code) {
 
521
    __ cmp(eax, FieldOperand(edx, HeapObject::kMapOffset));
 
522
    __ Check(equal, "Map is no longer in eax.");
 
523
  }
 
524
  __ mov(ebx, eax);  // Keep the map around for later.
 
525
  __ shr(eax, KeyedLookupCache::kMapHashShift);
 
526
  __ mov(edi, FieldOperand(ecx, String::kHashFieldOffset));
536
527
  __ shr(edi, String::kHashShift);
537
 
  __ xor_(ecx, Operand(edi));
538
 
  __ and_(ecx, KeyedLookupCache::kCapacityMask);
 
528
  __ xor_(eax, edi);
 
529
  __ and_(eax, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
539
530
 
540
531
  // Load the key (consisting of map and symbol) from the cache and
541
532
  // check for match.
 
533
  Label load_in_object_property;
 
534
  static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
 
535
  Label hit_on_nth_entry[kEntriesPerBucket];
542
536
  ExternalReference cache_keys =
543
537
      ExternalReference::keyed_lookup_cache_keys(masm->isolate());
544
 
  __ mov(edi, ecx);
 
538
 
 
539
  for (int i = 0; i < kEntriesPerBucket - 1; i++) {
 
540
    Label try_next_entry;
 
541
    __ mov(edi, eax);
 
542
    __ shl(edi, kPointerSizeLog2 + 1);
 
543
    if (i != 0) {
 
544
      __ add(edi, Immediate(kPointerSize * i * 2));
 
545
    }
 
546
    __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
 
547
    __ j(not_equal, &try_next_entry);
 
548
    __ add(edi, Immediate(kPointerSize));
 
549
    __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
 
550
    __ j(equal, &hit_on_nth_entry[i]);
 
551
    __ bind(&try_next_entry);
 
552
  }
 
553
 
 
554
  __ lea(edi, Operand(eax, 1));
545
555
  __ shl(edi, kPointerSizeLog2 + 1);
 
556
  __ add(edi, Immediate(kPointerSize * (kEntriesPerBucket - 1) * 2));
546
557
  __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
547
558
  __ j(not_equal, &slow);
548
 
  __ add(Operand(edi), Immediate(kPointerSize));
549
 
  __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
 
559
  __ add(edi, Immediate(kPointerSize));
 
560
  __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
550
561
  __ j(not_equal, &slow);
551
562
 
552
563
  // Get field offset.
553
564
  // edx     : receiver
554
565
  // ebx     : receiver's map
555
 
  // eax     : key
556
 
  // ecx     : lookup cache index
 
566
  // ecx     : key
 
567
  // eax     : lookup cache index
557
568
  ExternalReference cache_field_offsets =
558
569
      ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
559
 
  __ mov(edi,
560
 
         Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
561
 
  __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
562
 
  __ sub(edi, Operand(ecx));
563
 
  __ j(above_equal, &property_array_property);
 
570
 
 
571
  // Hit on nth entry.
 
572
  for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
 
573
    __ bind(&hit_on_nth_entry[i]);
 
574
    if (i != 0) {
 
575
      __ add(eax, Immediate(i));
 
576
    }
 
577
    __ mov(edi,
 
578
           Operand::StaticArray(eax, times_pointer_size, cache_field_offsets));
 
579
    __ movzx_b(eax, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
 
580
    __ sub(edi, eax);
 
581
    __ j(above_equal, &property_array_property);
 
582
    if (i != 0) {
 
583
      __ jmp(&load_in_object_property);
 
584
    }
 
585
  }
564
586
 
565
587
  // Load in-object property.
566
 
  __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
567
 
  __ add(ecx, Operand(edi));
568
 
  __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
 
588
  __ bind(&load_in_object_property);
 
589
  __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceSizeOffset));
 
590
  __ add(eax, edi);
 
591
  __ mov(eax, FieldOperand(edx, eax, times_pointer_size, 0));
569
592
  __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
570
593
  __ ret(0);
571
594
 
581
604
  // exists.
582
605
  __ bind(&probe_dictionary);
583
606
 
584
 
  __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset));
585
 
  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
586
 
  GenerateGlobalInstanceTypeCheck(masm, ecx, &slow);
 
607
  __ mov(eax, FieldOperand(edx, JSObject::kMapOffset));
 
608
  __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
 
609
  GenerateGlobalInstanceTypeCheck(masm, eax, &slow);
587
610
 
588
 
  GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax);
 
611
  GenerateDictionaryLoad(masm, &slow, ebx, ecx, eax, edi, eax);
589
612
  __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
590
613
  __ ret(0);
591
614
 
592
615
  __ bind(&index_string);
593
 
  __ IndexFromHash(ebx, eax);
 
616
  __ IndexFromHash(ebx, ecx);
594
617
  // Now jump to the place where smi keys are handled.
595
618
  __ jmp(&index_smi);
596
619
}
598
621
 
599
622
void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
600
623
  // ----------- S t a t e -------------
601
 
  //  -- eax    : key (index)
 
624
  //  -- ecx    : key (index)
602
625
  //  -- edx    : receiver
603
626
  //  -- esp[0] : return address
604
627
  // -----------------------------------
605
628
  Label miss;
606
629
 
607
630
  Register receiver = edx;
608
 
  Register index = eax;
609
 
  Register scratch1 = ebx;
610
 
  Register scratch2 = ecx;
 
631
  Register index = ecx;
 
632
  Register scratch = ebx;
611
633
  Register result = eax;
612
634
 
613
635
  StringCharAtGenerator char_at_generator(receiver,
614
636
                                          index,
615
 
                                          scratch1,
616
 
                                          scratch2,
 
637
                                          scratch,
617
638
                                          result,
618
639
                                          &miss,  // When not a string.
619
640
                                          &miss,  // When not a number.
632
653
 
633
654
void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
634
655
  // ----------- S t a t e -------------
635
 
  //  -- eax    : key
 
656
  //  -- ecx    : key
636
657
  //  -- edx    : receiver
637
658
  //  -- esp[0] : return address
638
659
  // -----------------------------------
642
663
  __ JumpIfSmi(edx, &slow);
643
664
 
644
665
  // Check that the key is an array index, that is Uint32.
645
 
  __ test(eax, Immediate(kSmiTagMask | kSmiSignMask));
 
666
  __ test(ecx, Immediate(kSmiTagMask | kSmiSignMask));
646
667
  __ j(not_zero, &slow);
647
668
 
648
669
  // Get the map of the receiver.
649
 
  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
 
670
  __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset));
650
671
 
651
672
  // Check that it has indexed interceptor and access checks
652
673
  // are not enabled for this object.
653
 
  __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
654
 
  __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask));
655
 
  __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor));
 
674
  __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset));
 
675
  __ and_(eax, Immediate(kSlowCaseBitFieldMask));
 
676
  __ cmp(eax, Immediate(1 << Map::kHasIndexedInterceptor));
656
677
  __ j(not_zero, &slow);
657
678
 
658
679
  // Everything is fine, call runtime.
659
 
  __ pop(ecx);
 
680
  __ pop(eax);
660
681
  __ push(edx);  // receiver
661
 
  __ push(eax);  // key
662
 
  __ push(ecx);  // return address
 
682
  __ push(ecx);  // key
 
683
  __ push(eax);  // return address
663
684
 
664
685
  // Perform tail call to the entry.
665
686
  ExternalReference ref =
674
695
 
675
696
void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
676
697
  // ----------- S t a t e -------------
677
 
  //  -- eax    : key
 
698
  //  -- ecx    : key
678
699
  //  -- edx    : receiver
679
700
  //  -- esp[0] : return address
680
701
  // -----------------------------------
681
702
  Label slow, notin;
682
703
  Factory* factory = masm->isolate()->factory();
683
704
  Operand mapped_location =
684
 
      GenerateMappedArgumentsLookup(masm, edx, eax, ebx, ecx, &notin, &slow);
 
705
      GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
685
706
  __ mov(eax, mapped_location);
686
707
  __ Ret();
687
708
  __ bind(&notin);
688
709
  // The unmapped lookup expects that the parameter map is in ebx.
689
710
  Operand unmapped_location =
690
 
      GenerateUnmappedArgumentsLookup(masm, eax, ebx, ecx, &slow);
 
711
      GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
691
712
  __ cmp(unmapped_location, factory->the_hole_value());
692
713
  __ j(equal, &slow);
693
714
  __ mov(eax, unmapped_location);
710
731
  __ mov(mapped_location, eax);
711
732
  __ lea(ecx, mapped_location);
712
733
  __ mov(edx, eax);
713
 
  __ RecordWrite(ebx, ecx, edx);
 
734
  __ RecordWrite(ebx, ecx, edx, kDontSaveFPRegs);
714
735
  __ Ret();
715
736
  __ bind(&notin);
716
737
  // The unmapped lookup expects that the parameter map is in ebx.
719
740
  __ mov(unmapped_location, eax);
720
741
  __ lea(edi, unmapped_location);
721
742
  __ mov(edx, eax);
722
 
  __ RecordWrite(ebx, edi, edx);
 
743
  __ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
723
744
  __ Ret();
724
745
  __ bind(&slow);
725
746
  GenerateMiss(masm, false);
726
747
}
727
748
 
728
749
 
 
750
static void KeyedStoreGenerateGenericHelper(
 
751
    MacroAssembler* masm,
 
752
    Label* fast_object,
 
753
    Label* fast_double,
 
754
    Label* slow,
 
755
    KeyedStoreCheckMap check_map,
 
756
    KeyedStoreIncrementLength increment_length) {
 
757
  Label transition_smi_elements;
 
758
  Label finish_object_store, non_double_value, transition_double_elements;
 
759
  Label fast_double_without_map_check;
 
760
  // eax: value
 
761
  // ecx: key (a smi)
 
762
  // edx: receiver
 
763
  // ebx: FixedArray receiver->elements
 
764
  // edi: receiver map
 
765
  // Fast case: Do the store, could either Object or double.
 
766
  __ bind(fast_object);
 
767
  if (check_map == kCheckMap) {
 
768
    __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
 
769
    __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
 
770
    __ j(not_equal, fast_double);
 
771
  }
 
772
  // Smi stores don't require further checks.
 
773
  Label non_smi_value;
 
774
  __ JumpIfNotSmi(eax, &non_smi_value);
 
775
  if (increment_length == kIncrementLength) {
 
776
    // Add 1 to receiver->length.
 
777
    __ add(FieldOperand(edx, JSArray::kLengthOffset),
 
778
           Immediate(Smi::FromInt(1)));
 
779
  }
 
780
  // It's irrelevant whether array is smi-only or not when writing a smi.
 
781
  __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
 
782
  __ ret(0);
 
783
 
 
784
  __ bind(&non_smi_value);
 
785
  // Escape to elements kind transition case.
 
786
  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
 
787
  __ CheckFastObjectElements(edi, &transition_smi_elements);
 
788
 
 
789
  // Fast elements array, store the value to the elements backing store.
 
790
  __ bind(&finish_object_store);
 
791
  if (increment_length == kIncrementLength) {
 
792
    // Add 1 to receiver->length.
 
793
    __ add(FieldOperand(edx, JSArray::kLengthOffset),
 
794
           Immediate(Smi::FromInt(1)));
 
795
  }
 
796
  __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
 
797
  // Update write barrier for the elements array address.
 
798
  __ mov(edx, eax);  // Preserve the value which is returned.
 
799
  __ RecordWriteArray(
 
800
      ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
 
801
  __ ret(0);
 
802
 
 
803
  __ bind(fast_double);
 
804
  if (check_map == kCheckMap) {
 
805
    // Check for fast double array case. If this fails, call through to the
 
806
    // runtime.
 
807
    __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
 
808
    __ j(not_equal, slow);
 
809
    // If the value is a number, store it as a double in the FastDoubleElements
 
810
    // array.
 
811
  }
 
812
  __ bind(&fast_double_without_map_check);
 
813
  __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0,
 
814
                                 &transition_double_elements, false);
 
815
  if (increment_length == kIncrementLength) {
 
816
    // Add 1 to receiver->length.
 
817
    __ add(FieldOperand(edx, JSArray::kLengthOffset),
 
818
           Immediate(Smi::FromInt(1)));
 
819
  }
 
820
  __ ret(0);
 
821
 
 
822
  __ bind(&transition_smi_elements);
 
823
  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
 
824
 
 
825
  // Transition the array appropriately depending on the value type.
 
826
  __ CheckMap(eax,
 
827
              masm->isolate()->factory()->heap_number_map(),
 
828
              &non_double_value,
 
829
              DONT_DO_SMI_CHECK);
 
830
 
 
831
  // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
 
832
  // and complete the store.
 
833
  __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
 
834
                                         FAST_DOUBLE_ELEMENTS,
 
835
                                         ebx,
 
836
                                         edi,
 
837
                                         slow);
 
838
  ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow);
 
839
  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
 
840
  __ jmp(&fast_double_without_map_check);
 
841
 
 
842
  __ bind(&non_double_value);
 
843
  // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
 
844
  __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
 
845
                                         FAST_ELEMENTS,
 
846
                                         ebx,
 
847
                                         edi,
 
848
                                         slow);
 
849
  ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
 
850
  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
 
851
  __ jmp(&finish_object_store);
 
852
 
 
853
  __ bind(&transition_double_elements);
 
854
  // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
 
855
  // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
 
856
  // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
 
857
  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
 
858
  __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
 
859
                                         FAST_ELEMENTS,
 
860
                                         ebx,
 
861
                                         edi,
 
862
                                         slow);
 
863
  ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow);
 
864
  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
 
865
  __ jmp(&finish_object_store);
 
866
}
 
867
 
 
868
 
729
869
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
730
870
                                   StrictModeFlag strict_mode) {
731
871
  // ----------- S t a t e -------------
734
874
  //  -- edx    : receiver
735
875
  //  -- esp[0] : return address
736
876
  // -----------------------------------
737
 
  Label slow, fast, array, extra;
 
877
  Label slow, fast_object, fast_object_grow;
 
878
  Label fast_double, fast_double_grow;
 
879
  Label array, extra, check_if_double_array;
738
880
 
739
881
  // Check that the object isn't a smi.
740
882
  __ JumpIfSmi(edx, &slow);
750
892
  __ CmpInstanceType(edi, JS_ARRAY_TYPE);
751
893
  __ j(equal, &array);
752
894
  // Check that the object is some kind of JSObject.
753
 
  __ CmpInstanceType(edi, FIRST_JS_RECEIVER_TYPE);
 
895
  __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
754
896
  __ j(below, &slow);
755
 
  __ CmpInstanceType(edi, JS_PROXY_TYPE);
756
 
  __ j(equal, &slow);
757
 
  __ CmpInstanceType(edi, JS_FUNCTION_PROXY_TYPE);
758
 
  __ j(equal, &slow);
759
897
 
760
898
  // Object case: Check key against length in the elements array.
761
899
  // eax: value
762
900
  // edx: JSObject
763
901
  // ecx: key (a smi)
764
 
  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
765
 
  // Check that the object is in fast mode and writable.
766
 
  __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, DONT_DO_SMI_CHECK);
767
 
  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
768
 
  __ j(below, &fast);
 
902
  // edi: receiver map
 
903
  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
 
904
  // Check array bounds. Both the key and the length of FixedArray are smis.
 
905
  __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
 
906
  __ j(below, &fast_object);
769
907
 
770
908
  // Slow case: call runtime.
771
909
  __ bind(&slow);
778
916
  // eax: value
779
917
  // edx: receiver, a JSArray
780
918
  // ecx: key, a smi.
781
 
  // edi: receiver->elements, a FixedArray
 
919
  // ebx: receiver->elements, a FixedArray
 
920
  // edi: receiver map
782
921
  // flags: compare (ecx, edx.length())
783
922
  // do not leave holes in the array:
784
923
  __ j(not_equal, &slow);
785
 
  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
 
924
  __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
786
925
  __ j(above_equal, &slow);
787
 
  // Add 1 to receiver->length, and go to fast array write.
788
 
  __ add(FieldOperand(edx, JSArray::kLengthOffset),
789
 
         Immediate(Smi::FromInt(1)));
790
 
  __ jmp(&fast);
 
926
  __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
 
927
  __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
 
928
  __ j(not_equal, &check_if_double_array);
 
929
  __ jmp(&fast_object_grow);
 
930
 
 
931
  __ bind(&check_if_double_array);
 
932
  __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
 
933
  __ j(not_equal, &slow);
 
934
  __ jmp(&fast_double_grow);
791
935
 
792
936
  // Array case: Get the length and the elements array from the JS
793
937
  // array. Check that the array is in fast mode (and writable); if it
796
940
  // eax: value
797
941
  // edx: receiver, a JSArray
798
942
  // ecx: key, a smi.
799
 
  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
800
 
  __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, DONT_DO_SMI_CHECK);
 
943
  // edi: receiver map
 
944
  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
801
945
 
802
 
  // Check the key against the length in the array, compute the
803
 
  // address to store into and fall through to fast case.
 
946
  // Check the key against the length in the array and fall through to the
 
947
  // common store code.
804
948
  __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // Compare smis.
805
949
  __ j(above_equal, &extra);
806
950
 
807
 
  // Fast case: Do the store.
808
 
  __ bind(&fast);
809
 
  // eax: value
810
 
  // ecx: key (a smi)
811
 
  // edx: receiver
812
 
  // edi: FixedArray receiver->elements
813
 
  __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax);
814
 
  // Update write barrier for the elements array address.
815
 
  __ mov(edx, Operand(eax));
816
 
  __ RecordWrite(edi, 0, edx, ecx);
817
 
  __ ret(0);
 
951
  KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
 
952
                                  &slow, kCheckMap, kDontIncrementLength);
 
953
  KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
 
954
                                  &slow, kDontCheckMap, kIncrementLength);
818
955
}
819
956
 
820
957
 
821
958
// The generated code does not accept smi keys.
822
959
// The generated code falls through if both probes miss.
823
 
static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
824
 
                                          int argc,
825
 
                                          Code::Kind kind,
826
 
                                          Code::ExtraICState extra_ic_state) {
 
960
void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
 
961
                                               int argc,
 
962
                                               Code::Kind kind,
 
963
                                               Code::ExtraICState extra_state) {
827
964
  // ----------- S t a t e -------------
828
965
  //  -- ecx                 : name
829
966
  //  -- edx                 : receiver
833
970
  // Probe the stub cache.
834
971
  Code::Flags flags = Code::ComputeFlags(kind,
835
972
                                         MONOMORPHIC,
836
 
                                         extra_ic_state,
837
 
                                         NORMAL,
 
973
                                         extra_state,
 
974
                                         Code::NORMAL,
838
975
                                         argc);
839
 
  Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
840
 
                                                  eax);
 
976
  Isolate* isolate = masm->isolate();
 
977
  isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, eax);
841
978
 
842
979
  // If the stub cache probing failed, the receiver might be a value.
843
980
  // For value objects, we use the map of the prototype objects for
863
1000
 
864
1001
  // Check for boolean.
865
1002
  __ bind(&non_string);
866
 
  __ cmp(edx, FACTORY->true_value());
 
1003
  __ cmp(edx, isolate->factory()->true_value());
867
1004
  __ j(equal, &boolean);
868
 
  __ cmp(edx, FACTORY->false_value());
 
1005
  __ cmp(edx, isolate->factory()->false_value());
869
1006
  __ j(not_equal, &miss);
870
1007
  __ bind(&boolean);
871
1008
  StubCompiler::GenerateLoadGlobalFunctionPrototype(
873
1010
 
874
1011
  // Probe the stub cache for the value object.
875
1012
  __ bind(&probe);
876
 
  Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
877
 
                                                  no_reg);
 
1013
  isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
878
1014
  __ bind(&miss);
879
1015
}
880
1016
 
904
1040
                    NullCallWrapper(), CALL_AS_METHOD);
905
1041
}
906
1042
 
 
1043
 
907
1044
// The generated code falls through if the call should be handled by runtime.
908
 
static void GenerateCallNormal(MacroAssembler* masm, int argc) {
 
1045
void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
909
1046
  // ----------- S t a t e -------------
910
1047
  //  -- ecx                 : name
911
1048
  //  -- esp[0]              : return address
929
1066
}
930
1067
 
931
1068
 
932
 
static void GenerateCallMiss(MacroAssembler* masm,
933
 
                             int argc,
934
 
                             IC::UtilityId id,
935
 
                             Code::ExtraICState extra_ic_state) {
 
1069
void CallICBase::GenerateMiss(MacroAssembler* masm,
 
1070
                              int argc,
 
1071
                              IC::UtilityId id,
 
1072
                              Code::ExtraICState extra_state) {
936
1073
  // ----------- S t a t e -------------
937
1074
  //  -- ecx                 : name
938
1075
  //  -- esp[0]              : return address
951
1088
  // Get the receiver of the function from the stack; 1 ~ return address.
952
1089
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
953
1090
 
954
 
  // Enter an internal frame.
955
 
  __ EnterInternalFrame();
956
 
 
957
 
  // Push the receiver and the name of the function.
958
 
  __ push(edx);
959
 
  __ push(ecx);
960
 
 
961
 
  // Call the entry.
962
 
  CEntryStub stub(1);
963
 
  __ mov(eax, Immediate(2));
964
 
  __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate())));
965
 
  __ CallStub(&stub);
966
 
 
967
 
  // Move result to edi and exit the internal frame.
968
 
  __ mov(edi, eax);
969
 
  __ LeaveInternalFrame();
 
1091
  {
 
1092
    FrameScope scope(masm, StackFrame::INTERNAL);
 
1093
 
 
1094
    // Push the receiver and the name of the function.
 
1095
    __ push(edx);
 
1096
    __ push(ecx);
 
1097
 
 
1098
    // Call the entry.
 
1099
    CEntryStub stub(1);
 
1100
    __ mov(eax, Immediate(2));
 
1101
    __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate())));
 
1102
    __ CallStub(&stub);
 
1103
 
 
1104
    // Move result to edi and exit the internal frame.
 
1105
    __ mov(edi, eax);
 
1106
  }
970
1107
 
971
1108
  // Check if the receiver is a global object of some sort.
972
1109
  // This can happen only for regular CallIC but not KeyedCallIC.
989
1126
  }
990
1127
 
991
1128
  // Invoke the function.
992
 
  CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
 
1129
  CallKind call_kind = CallICBase::Contextual::decode(extra_state)
993
1130
      ? CALL_AS_FUNCTION
994
1131
      : CALL_AS_METHOD;
995
1132
  ParameterCount actual(argc);
1003
1140
 
1004
1141
void CallIC::GenerateMegamorphic(MacroAssembler* masm,
1005
1142
                                 int argc,
1006
 
                                 Code::ExtraICState extra_ic_state) {
 
1143
                                 Code::ExtraICState extra_state) {
1007
1144
  // ----------- S t a t e -------------
1008
1145
  //  -- ecx                 : name
1009
1146
  //  -- esp[0]              : return address
1014
1151
 
1015
1152
  // Get the receiver of the function from the stack; 1 ~ return address.
1016
1153
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1017
 
  GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
1018
 
 
1019
 
  GenerateMiss(masm, argc, extra_ic_state);
1020
 
}
1021
 
 
1022
 
 
1023
 
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
1024
 
  // ----------- S t a t e -------------
1025
 
  //  -- ecx                 : name
1026
 
  //  -- esp[0]              : return address
1027
 
  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1028
 
  //  -- ...
1029
 
  //  -- esp[(argc + 1) * 4] : receiver
1030
 
  // -----------------------------------
1031
 
 
1032
 
  GenerateCallNormal(masm, argc);
1033
 
  GenerateMiss(masm, argc, Code::kNoExtraICState);
1034
 
}
1035
 
 
1036
 
 
1037
 
void CallIC::GenerateMiss(MacroAssembler* masm,
1038
 
                          int argc,
1039
 
                          Code::ExtraICState extra_ic_state) {
1040
 
  // ----------- S t a t e -------------
1041
 
  //  -- ecx                 : name
1042
 
  //  -- esp[0]              : return address
1043
 
  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1044
 
  //  -- ...
1045
 
  //  -- esp[(argc + 1) * 4] : receiver
1046
 
  // -----------------------------------
1047
 
 
1048
 
  GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
 
1154
  CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC,
 
1155
                                            extra_state);
 
1156
 
 
1157
  GenerateMiss(masm, argc, extra_state);
1049
1158
}
1050
1159
 
1051
1160
 
1111
1220
  // This branch is taken when calling KeyedCallIC_Miss is neither required
1112
1221
  // nor beneficial.
1113
1222
  __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
1114
 
  __ EnterInternalFrame();
1115
 
  __ push(ecx);  // save the key
1116
 
  __ push(edx);  // pass the receiver
1117
 
  __ push(ecx);  // pass the key
1118
 
  __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1119
 
  __ pop(ecx);  // restore the key
1120
 
  __ LeaveInternalFrame();
 
1223
 
 
1224
  {
 
1225
    FrameScope scope(masm, StackFrame::INTERNAL);
 
1226
    __ push(ecx);  // save the key
 
1227
    __ push(edx);  // pass the receiver
 
1228
    __ push(ecx);  // pass the key
 
1229
    __ CallRuntime(Runtime::kKeyedGetProperty, 2);
 
1230
    __ pop(ecx);  // restore the key
 
1231
    // Leave the internal frame.
 
1232
  }
 
1233
 
1121
1234
  __ mov(edi, eax);
1122
1235
  __ jmp(&do_call);
1123
1236
 
1143
1256
 
1144
1257
  __ bind(&lookup_monomorphic_cache);
1145
1258
  __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
1146
 
  GenerateMonomorphicCacheProbe(masm,
1147
 
                                argc,
1148
 
                                Code::KEYED_CALL_IC,
1149
 
                                Code::kNoExtraICState);
 
1259
  CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC,
 
1260
                                            Code::kNoExtraICState);
1150
1261
  // Fall through on miss.
1151
1262
 
1152
1263
  __ bind(&slow_call);
1209
1320
  __ JumpIfSmi(ecx, &miss);
1210
1321
  Condition cond = masm->IsObjectStringType(ecx, eax, eax);
1211
1322
  __ j(NegateCondition(cond), &miss);
1212
 
  GenerateCallNormal(masm, argc);
 
1323
  CallICBase::GenerateNormal(masm, argc);
1213
1324
  __ bind(&miss);
1214
1325
  GenerateMiss(masm, argc);
1215
1326
}
1216
1327
 
1217
1328
 
1218
 
void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
1219
 
  // ----------- S t a t e -------------
1220
 
  //  -- ecx                 : name
1221
 
  //  -- esp[0]              : return address
1222
 
  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1223
 
  //  -- ...
1224
 
  //  -- esp[(argc + 1) * 4] : receiver
1225
 
  // -----------------------------------
1226
 
 
1227
 
  GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
1228
 
}
1229
 
 
1230
 
 
1231
1329
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1232
1330
  // ----------- S t a t e -------------
1233
 
  //  -- eax    : receiver
1234
1331
  //  -- ecx    : name
 
1332
  //  -- edx    : receiver
1235
1333
  //  -- esp[0] : return address
1236
1334
  // -----------------------------------
1237
1335
 
1238
1336
  // Probe the stub cache.
1239
1337
  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
1240
 
  Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, eax, ecx, ebx,
1241
 
                                                  edx);
 
1338
  Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
 
1339
                                                  eax);
1242
1340
 
1243
1341
  // Cache miss: Jump to runtime.
1244
1342
  GenerateMiss(masm);
1247
1345
 
1248
1346
void LoadIC::GenerateNormal(MacroAssembler* masm) {
1249
1347
  // ----------- S t a t e -------------
1250
 
  //  -- eax    : receiver
1251
1348
  //  -- ecx    : name
 
1349
  //  -- edx    : receiver
1252
1350
  //  -- esp[0] : return address
1253
1351
  // -----------------------------------
1254
1352
  Label miss;
1255
1353
 
1256
 
  GenerateStringDictionaryReceiverCheck(masm, eax, edx, ebx, &miss);
 
1354
  GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
1257
1355
 
1258
 
  // edx: elements
 
1356
  // eax: elements
1259
1357
  // Search the dictionary placing the result in eax.
1260
 
  GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax);
 
1358
  GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, eax);
1261
1359
  __ ret(0);
1262
1360
 
1263
1361
  // Cache miss: Jump to runtime.
1268
1366
 
1269
1367
void LoadIC::GenerateMiss(MacroAssembler* masm) {
1270
1368
  // ----------- S t a t e -------------
1271
 
  //  -- eax    : receiver
1272
1369
  //  -- ecx    : name
 
1370
  //  -- edx    : receiver
1273
1371
  //  -- esp[0] : return address
1274
1372
  // -----------------------------------
1275
1373
 
1276
1374
  __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
1277
1375
 
1278
1376
  __ pop(ebx);
1279
 
  __ push(eax);  // receiver
 
1377
  __ push(edx);  // receiver
1280
1378
  __ push(ecx);  // name
1281
1379
  __ push(ebx);  // return address
1282
1380
 
1289
1387
 
1290
1388
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
1291
1389
  // ----------- S t a t e -------------
1292
 
  //  -- eax    : key
 
1390
  //  -- ecx    : key
1293
1391
  //  -- edx    : receiver
1294
1392
  //  -- esp[0] : return address
1295
1393
  // -----------------------------------
1298
1396
 
1299
1397
  __ pop(ebx);
1300
1398
  __ push(edx);  // receiver
1301
 
  __ push(eax);  // name
 
1399
  __ push(ecx);  // name
1302
1400
  __ push(ebx);  // return address
1303
1401
 
1304
1402
  // Perform tail call to the entry.
1312
1410
 
1313
1411
void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1314
1412
  // ----------- S t a t e -------------
1315
 
  //  -- eax    : key
 
1413
  //  -- ecx    : key
1316
1414
  //  -- edx    : receiver
1317
1415
  //  -- esp[0] : return address
1318
1416
  // -----------------------------------
1319
1417
 
1320
1418
  __ pop(ebx);
1321
1419
  __ push(edx);  // receiver
1322
 
  __ push(eax);  // name
 
1420
  __ push(ecx);  // name
1323
1421
  __ push(ebx);  // return address
1324
1422
 
1325
1423
  // Perform tail call to the entry.
1375
1473
  //  -- esp[0] : return address
1376
1474
  // -----------------------------------
1377
1475
  //
1378
 
  // This accepts as a receiver anything JSObject::SetElementsLength accepts
 
1476
  // This accepts as a receiver anything JSArray::SetElementsLength accepts
1379
1477
  // (currently anything except for external arrays which means anything with
1380
 
  // elements of FixedArray type.), but currently is restricted to JSArray.
1381
 
  // Value must be a number, but only smis are accepted as the most common case.
 
1478
  // elements of FixedArray type).  Value must be a number, but only smis are
 
1479
  // accepted as the most common case.
1382
1480
 
1383
1481
  Label miss;
1384
1482
 
1400
1498
  __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
1401
1499
  __ j(not_equal, &miss);
1402
1500
 
 
1501
  // Check that the array has fast properties, otherwise the length
 
1502
  // property might have been redefined.
 
1503
  __ mov(scratch, FieldOperand(receiver, JSArray::kPropertiesOffset));
 
1504
  __ CompareRoot(FieldOperand(scratch, FixedArray::kMapOffset),
 
1505
                 Heap::kHashTableMapRootIndex);
 
1506
  __ j(equal, &miss);
 
1507
 
1403
1508
  // Check that value is a smi.
1404
1509
  __ JumpIfNotSmi(value, &miss);
1405
1510
 
1536
1641
}
1537
1642
 
1538
1643
 
 
1644
void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
 
1645
  // ----------- S t a t e -------------
 
1646
  //  -- ebx    : target map
 
1647
  //  -- edx    : receiver
 
1648
  //  -- esp[0] : return address
 
1649
  // -----------------------------------
 
1650
  // Must return the modified receiver in eax.
 
1651
  if (!FLAG_trace_elements_transitions) {
 
1652
    Label fail;
 
1653
    ElementsTransitionGenerator::GenerateSmiToDouble(masm, &fail);
 
1654
    __ mov(eax, edx);
 
1655
    __ Ret();
 
1656
    __ bind(&fail);
 
1657
  }
 
1658
 
 
1659
  __ pop(ebx);
 
1660
  __ push(edx);
 
1661
  __ push(ebx);  // return address
 
1662
  // Leaving the code managed by the register allocator and return to the
 
1663
  // convention of using esi as context register.
 
1664
  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
 
1665
  __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
 
1666
}
 
1667
 
 
1668
 
 
1669
void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
 
1670
    MacroAssembler* masm) {
 
1671
  // ----------- S t a t e -------------
 
1672
  //  -- ebx    : target map
 
1673
  //  -- edx    : receiver
 
1674
  //  -- esp[0] : return address
 
1675
  // -----------------------------------
 
1676
  // Must return the modified receiver in eax.
 
1677
  if (!FLAG_trace_elements_transitions) {
 
1678
    Label fail;
 
1679
    ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
 
1680
    __ mov(eax, edx);
 
1681
    __ Ret();
 
1682
    __ bind(&fail);
 
1683
  }
 
1684
 
 
1685
  __ pop(ebx);
 
1686
  __ push(edx);
 
1687
  __ push(ebx);  // return address
 
1688
  // Leaving the code managed by the register allocator and return to the
 
1689
  // convention of using esi as context register.
 
1690
  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
 
1691
  __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
 
1692
}
 
1693
 
 
1694
 
1539
1695
#undef __
1540
1696
 
1541
1697
 
1547
1703
    case Token::LT:
1548
1704
      return less;
1549
1705
    case Token::GT:
1550
 
      // Reverse left and right operands to obtain ECMA-262 conversion order.
1551
 
      return less;
 
1706
      return greater;
1552
1707
    case Token::LTE:
1553
 
      // Reverse left and right operands to obtain ECMA-262 conversion order.
1554
 
      return greater_equal;
 
1708
      return less_equal;
1555
1709
    case Token::GTE:
1556
1710
      return greater_equal;
1557
1711
    default:
1583
1737
    rewritten = stub.GetCode();
1584
1738
  } else {
1585
1739
    ICCompareStub stub(op_, state);
 
1740
    if (state == KNOWN_OBJECTS) {
 
1741
      stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
 
1742
    }
1586
1743
    rewritten = stub.GetCode();
1587
1744
  }
1588
1745
  set_target(*rewritten);
1598
1755
 
1599
1756
  // Activate inlined smi code.
1600
1757
  if (previous_state == UNINITIALIZED) {
1601
 
    PatchInlinedSmiCode(address());
 
1758
    PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
1602
1759
  }
1603
1760
}
1604
1761
 
1605
1762
 
1606
 
void PatchInlinedSmiCode(Address address) {
 
1763
void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
1607
1764
  // The address of the instruction following the call.
1608
1765
  Address test_instruction_address =
1609
1766
      address + Assembler::kCallTargetAddressOffset;
1624
1781
           address, test_instruction_address, delta);
1625
1782
  }
1626
1783
 
1627
 
  // Patch with a short conditional jump. There must be a
1628
 
  // short jump-if-carry/not-carry at this position.
 
1784
  // Patch with a short conditional jump. Enabling means switching from a short
 
1785
  // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the
 
1786
  // reverse operation of that.
1629
1787
  Address jmp_address = test_instruction_address - delta;
1630
 
  ASSERT(*jmp_address == Assembler::kJncShortOpcode ||
1631
 
         *jmp_address == Assembler::kJcShortOpcode);
1632
 
  Condition cc = *jmp_address == Assembler::kJncShortOpcode
1633
 
      ? not_zero
1634
 
      : zero;
 
1788
  ASSERT((check == ENABLE_INLINED_SMI_CHECK)
 
1789
         ? (*jmp_address == Assembler::kJncShortOpcode ||
 
1790
            *jmp_address == Assembler::kJcShortOpcode)
 
1791
         : (*jmp_address == Assembler::kJnzShortOpcode ||
 
1792
            *jmp_address == Assembler::kJzShortOpcode));
 
1793
  Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
 
1794
      ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
 
1795
      : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
1635
1796
  *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
1636
1797
}
1637
1798