| Index: src/x64/stub-cache-x64.cc
|
| ===================================================================
|
| --- src/x64/stub-cache-x64.cc (revision 7948)
|
| +++ src/x64/stub-cache-x64.cc (working copy)
|
| @@ -82,18 +82,18 @@
|
| // must always call a backup property check that is complete.
|
| // This function is safe to call if the receiver has fast properties.
|
| // Name must be a symbol and receiver must be a heap object.
|
| -static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
|
| - Label* miss_label,
|
| - Register receiver,
|
| - String* name,
|
| - Register r0,
|
| - Register r1) {
|
| +MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup(
|
| + MacroAssembler* masm,
|
| + Label* miss_label,
|
| + Register receiver,
|
| + String* name,
|
| + Register r0,
|
| + Register r1) {
|
| ASSERT(name->IsSymbol());
|
| Counters* counters = masm->isolate()->counters();
|
| __ IncrementCounter(counters->negative_lookups(), 1);
|
| __ IncrementCounter(counters->negative_lookups_miss(), 1);
|
|
|
| - Label done;
|
| __ movq(r0, FieldOperand(receiver, HeapObject::kMapOffset));
|
|
|
| const int kInterceptorOrAccessCheckNeededMask =
|
| @@ -117,64 +117,20 @@
|
| Heap::kHashTableMapRootIndex);
|
| __ j(not_equal, miss_label);
|
|
|
| - // Compute the capacity mask.
|
| - const int kCapacityOffset =
|
| - StringDictionary::kHeaderSize +
|
| - StringDictionary::kCapacityIndex * kPointerSize;
|
| + Label done;
|
| + MaybeObject* result = StringDictionaryLookupStub::GenerateNegativeLookup(
|
| + masm,
|
| + miss_label,
|
| + &done,
|
| + properties,
|
| + name,
|
| + r1);
|
| + if (result->IsFailure()) return result;
|
|
|
| - // Generate an unrolled loop that performs a few probes before
|
| - // giving up.
|
| - static const int kProbes = 4;
|
| - const int kElementsStartOffset =
|
| - StringDictionary::kHeaderSize +
|
| - StringDictionary::kElementsStartIndex * kPointerSize;
|
| -
|
| - // If names of slots in range from 1 to kProbes - 1 for the hash value are
|
| - // not equal to the name and kProbes-th slot is not used (its name is the
|
| - // undefined value), it guarantees the hash table doesn't contain the
|
| - // property. It's true even if some slots represent deleted properties
|
| - // (their names are the null value).
|
| - for (int i = 0; i < kProbes; i++) {
|
| - // r0 points to properties hash.
|
| - // Compute the masked index: (hash + i + i * i) & mask.
|
| - Register index = r1;
|
| - // Capacity is smi 2^n.
|
| - __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset));
|
| - __ decl(index);
|
| - __ and_(index,
|
| - Immediate(name->Hash() + StringDictionary::GetProbeOffset(i)));
|
| -
|
| - // Scale the index by multiplying by the entry size.
|
| - ASSERT(StringDictionary::kEntrySize == 3);
|
| - __ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
|
| -
|
| - Register entity_name = r1;
|
| - // Having undefined at this place means the name is not contained.
|
| - ASSERT_EQ(kSmiTagSize, 1);
|
| - __ movq(entity_name, Operand(properties, index, times_pointer_size,
|
| - kElementsStartOffset - kHeapObjectTag));
|
| - __ Cmp(entity_name, masm->isolate()->factory()->undefined_value());
|
| - // __ jmp(miss_label);
|
| - if (i != kProbes - 1) {
|
| - __ j(equal, &done);
|
| -
|
| - // Stop if found the property.
|
| - __ Cmp(entity_name, Handle<String>(name));
|
| - __ j(equal, miss_label);
|
| -
|
| - // Check if the entry name is not a symbol.
|
| - __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
|
| - __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
|
| - Immediate(kIsSymbolMask));
|
| - __ j(zero, miss_label);
|
| - } else {
|
| - // Give up probing if still not found the undefined value.
|
| - __ j(not_equal, miss_label);
|
| - }
|
| - }
|
| -
|
| __ bind(&done);
|
| __ DecrementCounter(counters->negative_lookups_miss(), 1);
|
| +
|
| + return result;
|
| }
|
|
|
|
|
| @@ -747,6 +703,14 @@
|
| }
|
|
|
|
|
| +void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
|
| + Code* code = masm->isolate()->builtins()->builtin(
|
| + Builtins::kKeyedLoadIC_MissForceGeneric);
|
| + Handle<Code> ic(code);
|
| + __ Jump(ic, RelocInfo::CODE_TARGET);
|
| +}
|
| +
|
| +
|
| // Both name_reg and receiver_reg are preserved on jumps to miss_label,
|
| // but may be destroyed if store is successful.
|
| void StubCompiler::GenerateStoreField(MacroAssembler* masm,
|
| @@ -907,12 +871,17 @@
|
| ASSERT(current->property_dictionary()->FindEntry(name) ==
|
| StringDictionary::kNotFound);
|
|
|
| - GenerateDictionaryNegativeLookup(masm(),
|
| - miss,
|
| - reg,
|
| - name,
|
| - scratch1,
|
| - scratch2);
|
| + MaybeObject* negative_lookup = GenerateDictionaryNegativeLookup(masm(),
|
| + miss,
|
| + reg,
|
| + name,
|
| + scratch1,
|
| + scratch2);
|
| + if (negative_lookup->IsFailure()) {
|
| + set_failure(Failure::cast(negative_lookup));
|
| + return reg;
|
| + }
|
| +
|
| __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
|
| reg = holder_reg; // from now the object is in holder_reg
|
| __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
|
| @@ -1944,7 +1913,7 @@
|
|
|
| // Check if the argument is a heap number and load its value.
|
| __ bind(¬_smi);
|
| - __ CheckMap(rax, factory()->heap_number_map(), &slow, true);
|
| + __ CheckMap(rax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
|
| __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
|
|
|
| // Check the sign of the argument. If the argument is positive,
|
| @@ -1993,6 +1962,7 @@
|
| // repatch it to global receiver.
|
| if (object->IsGlobalObject()) return heap()->undefined_value();
|
| if (cell != NULL) return heap()->undefined_value();
|
| + if (!object->IsJSObject()) return heap()->undefined_value();
|
| int depth = optimization.GetPrototypeDepthOfExpectedType(
|
| JSObject::cast(object), holder);
|
| if (depth == kInvalidProtoDepth) return heap()->undefined_value();
|
| @@ -2523,60 +2493,62 @@
|
| }
|
|
|
|
|
| -MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
|
| - JSObject* receiver) {
|
| +MaybeObject* KeyedStoreStubCompiler::CompileStoreFastElement(
|
| + Map* receiver_map) {
|
| // ----------- S t a t e -------------
|
| // -- rax : value
|
| // -- rcx : key
|
| // -- rdx : receiver
|
| // -- rsp[0] : return address
|
| // -----------------------------------
|
| - Label miss;
|
| + bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
|
| + MaybeObject* maybe_stub =
|
| + KeyedStoreFastElementStub(is_js_array).TryGetCode();
|
| + Code* stub;
|
| + if (!maybe_stub->To(&stub)) return maybe_stub;
|
| + __ DispatchMap(rdx,
|
| + Handle<Map>(receiver_map),
|
| + Handle<Code>(stub),
|
| + DO_SMI_CHECK);
|
|
|
| - // Check that the receiver isn't a smi.
|
| - __ JumpIfSmi(rdx, &miss);
|
| + Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
|
| + __ jmp(ic, RelocInfo::CODE_TARGET);
|
|
|
| - // Check that the map matches.
|
| - __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
|
| - Handle<Map>(receiver->map()));
|
| - __ j(not_equal, &miss);
|
| + // Return the generated code.
|
| + return GetCode(NORMAL, NULL);
|
| +}
|
|
|
| - // Check that the key is a smi.
|
| - __ JumpIfNotSmi(rcx, &miss);
|
|
|
| - // Get the elements array and make sure it is a fast element array, not 'cow'.
|
| - __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
|
| - __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
|
| - factory()->fixed_array_map());
|
| - __ j(not_equal, &miss);
|
| +MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
|
| + MapList* receiver_maps,
|
| + CodeList* handler_ics) {
|
| + // ----------- S t a t e -------------
|
| + // -- rax : value
|
| + // -- rcx : key
|
| + // -- rdx : receiver
|
| + // -- rsp[0] : return address
|
| + // -----------------------------------
|
| + Label miss;
|
| + __ JumpIfSmi(rdx, &miss);
|
|
|
| - // Check that the key is within bounds.
|
| - if (receiver->IsJSArray()) {
|
| - __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
|
| - __ j(above_equal, &miss);
|
| - } else {
|
| - __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
|
| - __ j(above_equal, &miss);
|
| + Register map_reg = rbx;
|
| + __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset));
|
| + int receiver_count = receiver_maps->length();
|
| + for (int current = 0; current < receiver_count; ++current) {
|
| + // Check map and tail call if there's a match
|
| + Handle<Map> map(receiver_maps->at(current));
|
| + __ Cmp(map_reg, map);
|
| + __ j(equal,
|
| + Handle<Code>(handler_ics->at(current)),
|
| + RelocInfo::CODE_TARGET);
|
| }
|
|
|
| - // Do the store and update the write barrier. Make sure to preserve
|
| - // the value in register eax.
|
| - __ movq(rdx, rax);
|
| - __ SmiToInteger32(rcx, rcx);
|
| - __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
|
| - rax);
|
| - __ RecordWrite(rdi, 0, rdx, rcx, kDontSaveFPRegs);
|
| -
|
| - // Done.
|
| - __ ret(0);
|
| -
|
| - // Handle store cache miss.
|
| __ bind(&miss);
|
| Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
|
| __ jmp(ic, RelocInfo::CODE_TARGET);
|
|
|
| // Return the generated code.
|
| - return GetCode(NORMAL, NULL);
|
| + return GetCode(NORMAL, NULL, MEGAMORPHIC);
|
| }
|
|
|
|
|
| @@ -2590,7 +2562,7 @@
|
| // -----------------------------------
|
| Label miss;
|
|
|
| - // Chech that receiver is not a smi.
|
| + // Check that receiver is not a smi.
|
| __ JumpIfSmi(rax, &miss);
|
|
|
| // Check the maps of the full prototype chain. Also check that
|
| @@ -2981,49 +2953,56 @@
|
| }
|
|
|
|
|
| -MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
|
| +MaybeObject* KeyedLoadStubCompiler::CompileLoadFastElement(Map* receiver_map) {
|
| // ----------- S t a t e -------------
|
| // -- rax : key
|
| // -- rdx : receiver
|
| // -- rsp[0] : return address
|
| // -----------------------------------
|
| - Label miss;
|
| + MaybeObject* maybe_stub = KeyedLoadFastElementStub().TryGetCode();
|
| + Code* stub;
|
| + if (!maybe_stub->To(&stub)) return maybe_stub;
|
| + __ DispatchMap(rdx,
|
| + Handle<Map>(receiver_map),
|
| + Handle<Code>(stub),
|
| + DO_SMI_CHECK);
|
|
|
| - // Check that the receiver isn't a smi.
|
| - __ JumpIfSmi(rdx, &miss);
|
| + Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
|
| + __ jmp(ic, RelocInfo::CODE_TARGET);
|
|
|
| - // Check that the map matches.
|
| - __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
|
| - Handle<Map>(receiver->map()));
|
| - __ j(not_equal, &miss);
|
| + // Return the generated code.
|
| + return GetCode(NORMAL, NULL);
|
| +}
|
|
|
| - // Check that the key is a smi.
|
| - __ JumpIfNotSmi(rax, &miss);
|
|
|
| - // Get the elements array.
|
| - __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| - __ AssertFastElements(rcx);
|
| +MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
|
| + MapList* receiver_maps,
|
| + CodeList* handler_ics) {
|
| + // ----------- S t a t e -------------
|
| + // -- rax : key
|
| + // -- rdx : receiver
|
| + // -- rsp[0] : return address
|
| + // -----------------------------------
|
| + Label miss;
|
| + __ JumpIfSmi(rdx, &miss);
|
|
|
| - // Check that the key is within bounds.
|
| - __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
|
| - __ j(above_equal, &miss);
|
| + Register map_reg = rbx;
|
| + __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset));
|
| + int receiver_count = receiver_maps->length();
|
| + for (int current = 0; current < receiver_count; ++current) {
|
| + // Check map and tail call if there's a match
|
| + Handle<Map> map(receiver_maps->at(current));
|
| + __ Cmp(map_reg, map);
|
| + __ j(equal,
|
| + Handle<Code>(handler_ics->at(current)),
|
| + RelocInfo::CODE_TARGET);
|
| + }
|
|
|
| - // Load the result and make sure it's not the hole.
|
| - SmiIndex index = masm()->SmiToIndex(rbx, rax, kPointerSizeLog2);
|
| - __ movq(rbx, FieldOperand(rcx,
|
| - index.reg,
|
| - index.scale,
|
| - FixedArray::kHeaderSize));
|
| - __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
|
| - __ j(equal, &miss);
|
| - __ movq(rax, rbx);
|
| - __ ret(0);
|
| -
|
| - __ bind(&miss);
|
| + __ bind(&miss);
|
| GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
|
|
|
| // Return the generated code.
|
| - return GetCode(NORMAL, NULL);
|
| + return GetCode(NORMAL, NULL, MEGAMORPHIC);
|
| }
|
|
|
|
|
| @@ -3160,30 +3139,79 @@
|
| }
|
|
|
|
|
| -MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
|
| - JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
|
| +MaybeObject* ExternalArrayLoadStubCompiler::CompileLoad(
|
| + JSObject*receiver, ExternalArrayType array_type) {
|
| // ----------- S t a t e -------------
|
| // -- rax : key
|
| // -- rdx : receiver
|
| // -- rsp[0] : return address
|
| // -----------------------------------
|
| - Label slow;
|
| + MaybeObject* maybe_stub =
|
| + KeyedLoadExternalArrayStub(array_type).TryGetCode();
|
| + Code* stub;
|
| + if (!maybe_stub->To(&stub)) return maybe_stub;
|
| + __ DispatchMap(rdx,
|
| + Handle<Map>(receiver->map()),
|
| + Handle<Code>(stub),
|
| + DO_SMI_CHECK);
|
|
|
| - // Check that the object isn't a smi.
|
| - __ JumpIfSmi(rdx, &slow);
|
| + Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
|
| + __ jmp(ic, RelocInfo::CODE_TARGET);
|
|
|
| + // Return the generated code.
|
| + return GetCode();
|
| +}
|
| +
|
| +MaybeObject* ExternalArrayStoreStubCompiler::CompileStore(
|
| + JSObject* receiver, ExternalArrayType array_type) {
|
| + // ----------- S t a t e -------------
|
| + // -- rax : value
|
| + // -- rcx : key
|
| + // -- rdx : receiver
|
| + // -- rsp[0] : return address
|
| + // -----------------------------------
|
| + MaybeObject* maybe_stub =
|
| + KeyedStoreExternalArrayStub(array_type).TryGetCode();
|
| + Code* stub;
|
| + if (!maybe_stub->To(&stub)) return maybe_stub;
|
| + __ DispatchMap(rdx,
|
| + Handle<Map>(receiver->map()),
|
| + Handle<Code>(stub),
|
| + DO_SMI_CHECK);
|
| +
|
| + Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
|
| + __ jmp(ic, RelocInfo::CODE_TARGET);
|
| +
|
| + return GetCode();
|
| +}
|
| +
|
| +
|
| +#undef __
|
| +#define __ ACCESS_MASM(masm)
|
| +
|
| +
|
| +void KeyedLoadStubCompiler::GenerateLoadExternalArray(
|
| + MacroAssembler* masm,
|
| + ExternalArrayType array_type) {
|
| + // ----------- S t a t e -------------
|
| + // -- rax : key
|
| + // -- rdx : receiver
|
| + // -- rsp[0] : return address
|
| + // -----------------------------------
|
| + Label slow, miss_force_generic;
|
| +
|
| + // This stub is meant to be tail-jumped to, the receiver must already
|
| + // have been verified by the caller to not be a smi.
|
| +
|
| // Check that the key is a smi.
|
| - __ JumpIfNotSmi(rax, &slow);
|
| + __ JumpIfNotSmi(rax, &miss_force_generic);
|
|
|
| - // Check that the map matches.
|
| - __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false);
|
| + // Check that the index is in range.
|
| __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| -
|
| - // Check that the index is in range.
|
| __ SmiToInteger32(rcx, rax);
|
| __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
|
| // Unsigned comparison catches both negative and too-large values.
|
| - __ j(above_equal, &slow);
|
| + __ j(above_equal, &miss_force_generic);
|
|
|
| // rax: index (as a smi)
|
| // rdx: receiver (JSObject)
|
| @@ -3234,9 +3262,9 @@
|
| // For the UnsignedInt array type, we need to see whether
|
| // the value can be represented in a Smi. If not, we need to convert
|
| // it to a HeapNumber.
|
| - NearLabel box_int;
|
| + Label box_int;
|
|
|
| - __ JumpIfUIntNotValidSmiValue(rcx, &box_int);
|
| + __ JumpIfUIntNotValidSmiValue(rcx, &box_int, Label::kNear);
|
|
|
| __ Integer32ToSmi(rax, rcx);
|
| __ ret(0);
|
| @@ -3270,7 +3298,7 @@
|
|
|
| // Slow case: Jump to runtime.
|
| __ bind(&slow);
|
| - Counters* counters = isolate()->counters();
|
| + Counters* counters = masm->isolate()->counters();
|
| __ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
|
|
|
| // ----------- S t a t e -------------
|
| @@ -3279,44 +3307,46 @@
|
| // -- rsp[0] : return address
|
| // -----------------------------------
|
|
|
| - __ pop(rbx);
|
| - __ push(rdx); // receiver
|
| - __ push(rax); // name
|
| - __ push(rbx); // return address
|
| + Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Slow();
|
| + __ jmp(ic, RelocInfo::CODE_TARGET);
|
|
|
| - // Perform tail call to the entry.
|
| - __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
|
| + // Miss case: Jump to runtime.
|
| + __ bind(&miss_force_generic);
|
|
|
| - // Return the generated code.
|
| - return GetCode(flags);
|
| + // ----------- S t a t e -------------
|
| + // -- rax : key
|
| + // -- rdx : receiver
|
| + // -- rsp[0] : return address
|
| + // -----------------------------------
|
| + Handle<Code> miss_ic =
|
| + masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
|
| + __ jmp(miss_ic, RelocInfo::CODE_TARGET);
|
| }
|
|
|
|
|
| -MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
|
| - JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
|
| +void KeyedStoreStubCompiler::GenerateStoreExternalArray(
|
| + MacroAssembler* masm,
|
| + ExternalArrayType array_type) {
|
| // ----------- S t a t e -------------
|
| // -- rax : value
|
| // -- rcx : key
|
| // -- rdx : receiver
|
| // -- rsp[0] : return address
|
| // -----------------------------------
|
| - Label slow;
|
| + Label slow, miss_force_generic;
|
|
|
| - // Check that the object isn't a smi.
|
| - __ JumpIfSmi(rdx, &slow);
|
| + // This stub is meant to be tail-jumped to, the receiver must already
|
| + // have been verified by the caller to not be a smi.
|
|
|
| - // Check that the map matches.
|
| - __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false);
|
| - __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| -
|
| // Check that the key is a smi.
|
| - __ JumpIfNotSmi(rcx, &slow);
|
| + __ JumpIfNotSmi(rcx, &miss_force_generic);
|
|
|
| // Check that the index is in range.
|
| + __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| __ SmiToInteger32(rdi, rcx); // Untag the index.
|
| __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset));
|
| // Unsigned comparison catches both negative and too-large values.
|
| - __ j(above_equal, &slow);
|
| + __ j(above_equal, &miss_force_generic);
|
|
|
| // Handle both smis and HeapNumbers in the fast path. Go to the
|
| // runtime for all other kinds of values.
|
| @@ -3325,12 +3355,12 @@
|
| // rdx: receiver (a JSObject)
|
| // rbx: elements array
|
| // rdi: untagged key
|
| - NearLabel check_heap_number;
|
| + Label check_heap_number;
|
| if (array_type == kExternalPixelArray) {
|
| // Float to pixel conversion is only implemented in the runtime for now.
|
| __ JumpIfNotSmi(rax, &slow);
|
| } else {
|
| - __ JumpIfNotSmi(rax, &check_heap_number);
|
| + __ JumpIfNotSmi(rax, &check_heap_number, Label::kNear);
|
| }
|
| // No more branches to slow case on this path. Key and receiver not needed.
|
| __ SmiToInteger32(rdx, rax);
|
| @@ -3339,9 +3369,9 @@
|
| switch (array_type) {
|
| case kExternalPixelArray:
|
| { // Clamp the value to [0..255].
|
| - NearLabel done;
|
| + Label done;
|
| __ testl(rdx, Immediate(0xFFFFFF00));
|
| - __ j(zero, &done);
|
| + __ j(zero, &done, Label::kNear);
|
| __ setcc(negative, rdx); // 1 if negative, 0 if positive.
|
| __ decb(rdx); // 0 if negative, 255 if positive.
|
| __ bind(&done);
|
| @@ -3450,21 +3480,117 @@
|
| // -- rsp[0] : return address
|
| // -----------------------------------
|
|
|
| - __ pop(rbx);
|
| - __ push(rdx); // receiver
|
| - __ push(rcx); // key
|
| - __ push(rax); // value
|
| - __ Push(Smi::FromInt(NONE)); // PropertyAttributes
|
| - __ Push(Smi::FromInt(
|
| - Code::ExtractExtraICStateFromFlags(flags) & kStrictMode));
|
| - __ push(rbx); // return address
|
| + Handle<Code> ic = masm->isolate()->builtins()->KeyedStoreIC_Slow();
|
| + __ jmp(ic, RelocInfo::CODE_TARGET);
|
|
|
| - // Do tail-call to runtime routine.
|
| - __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
|
| + // Miss case: call runtime.
|
| + __ bind(&miss_force_generic);
|
|
|
| - return GetCode(flags);
|
| + // ----------- S t a t e -------------
|
| + // -- rax : value
|
| + // -- rcx : key
|
| + // -- rdx : receiver
|
| + // -- rsp[0] : return address
|
| + // -----------------------------------
|
| +
|
| + Handle<Code> miss_ic =
|
| + masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
|
| + __ jmp(miss_ic, RelocInfo::CODE_TARGET);
|
| }
|
|
|
| +
|
| +void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
|
| + // ----------- S t a t e -------------
|
| + // -- rax : key
|
| + // -- rdx : receiver
|
| + // -- rsp[0] : return address
|
| + // -----------------------------------
|
| + Label miss_force_generic;
|
| +
|
| + // This stub is meant to be tail-jumped to, the receiver must already
|
| + // have been verified by the caller to not be a smi.
|
| +
|
| + // Check that the key is a smi.
|
| + __ JumpIfNotSmi(rax, &miss_force_generic);
|
| +
|
| + // Get the elements array.
|
| + __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| + __ AssertFastElements(rcx);
|
| +
|
| + // Check that the key is within bounds.
|
| + __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
|
| + __ j(above_equal, &miss_force_generic);
|
| +
|
| + // Load the result and make sure it's not the hole.
|
| + SmiIndex index = masm->SmiToIndex(rbx, rax, kPointerSizeLog2);
|
| + __ movq(rbx, FieldOperand(rcx,
|
| + index.reg,
|
| + index.scale,
|
| + FixedArray::kHeaderSize));
|
| + __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
|
| + __ j(equal, &miss_force_generic);
|
| + __ movq(rax, rbx);
|
| + __ ret(0);
|
| +
|
| + __ bind(&miss_force_generic);
|
| + Code* code = masm->isolate()->builtins()->builtin(
|
| + Builtins::kKeyedLoadIC_MissForceGeneric);
|
| + Handle<Code> ic(code);
|
| + __ jmp(ic, RelocInfo::CODE_TARGET);
|
| +}
|
| +
|
| +
|
| +void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
|
| + bool is_js_array) {
|
| + // ----------- S t a t e -------------
|
| + // -- rax : value
|
| + // -- rcx : key
|
| + // -- rdx : receiver
|
| + // -- rsp[0] : return address
|
| + // -----------------------------------
|
| + Label miss_force_generic;
|
| +
|
| + // This stub is meant to be tail-jumped to, the receiver must already
|
| + // have been verified by the caller to not be a smi.
|
| +
|
| + // Check that the key is a smi.
|
| + __ JumpIfNotSmi(rcx, &miss_force_generic);
|
| +
|
| + // Get the elements array and make sure it is a fast element array, not 'cow'.
|
| + __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
|
| + __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset),
|
| + Heap::kFixedArrayMapRootIndex);
|
| + __ j(not_equal, &miss_force_generic);
|
| +
|
| + // Check that the key is within bounds.
|
| + if (is_js_array) {
|
| + __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
|
| + __ j(above_equal, &miss_force_generic);
|
| + } else {
|
| + __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
|
| + __ j(above_equal, &miss_force_generic);
|
| + }
|
| +
|
| + // Do the store and update the write barrier.
|
| + __ SmiToInteger32(rcx, rcx);
|
| + __ lea(rcx,
|
| + FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize));
|
| + __ movq(Operand(rcx, 0), rax);
|
| + // Make sure to preserve the value in register rax.
|
| + __ movq(rdx, rax);
|
| + __ RecordWrite(rdi, rcx, rdx, kDontSaveFPRegs);
|
| +
|
| + // Done.
|
| + __ ret(0);
|
| +
|
| + // Handle store cache miss.
|
| + __ bind(&miss_force_generic);
|
| + Handle<Code> ic_force_generic =
|
| + masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
|
| + __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
|
| +}
|
| +
|
| +
|
| #undef __
|
|
|
| } } // namespace v8::internal
|
|
|