| Index: src/ia32/stub-cache-ia32.cc
|
| diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
|
| index 3379ff00fdd5b4db01865c5472b7b133a3f78ee7..efaefabbdfb1934114359d512b860af926c20a3e 100644
|
| --- a/src/ia32/stub-cache-ia32.cc
|
| +++ b/src/ia32/stub-cache-ia32.cc
|
| @@ -713,6 +713,14 @@ void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
|
| }
|
|
|
|
|
| +void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
|
| + Code* code = masm->isolate()->builtins()->builtin(
|
| + Builtins::kKeyedLoadIC_MissForceGeneric);
|
| + Handle<Code> ic(code);
|
| + __ jmp(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,
|
| @@ -2654,60 +2662,58 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
|
| }
|
|
|
|
|
| -MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
|
| - JSObject* receiver) {
|
| +MaybeObject* KeyedStoreStubCompiler::CompileStoreFastElement(
|
| + Map* receiver_map) {
|
| // ----------- S t a t e -------------
|
| // -- eax : value
|
| // -- ecx : key
|
| // -- edx : receiver
|
| // -- esp[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(edx,
|
| + Handle<Map>(receiver_map),
|
| + Handle<Code>(stub),
|
| + DO_SMI_CHECK);
|
|
|
| - // Check that the receiver isn't a smi.
|
| - __ test(edx, Immediate(kSmiTagMask));
|
| - __ j(zero, &miss);
|
| + Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
|
| + __ jmp(ic, RelocInfo::CODE_TARGET);
|
|
|
| - // Check that the map matches.
|
| - __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
|
| - Immediate(Handle<Map>(receiver->map())));
|
| - __ j(not_equal, &miss);
|
| + // Return the generated code.
|
| + return GetCode(NORMAL, NULL);
|
| +}
|
|
|
| - // Check that the key is a smi.
|
| - __ test(ecx, Immediate(kSmiTagMask));
|
| - __ j(not_zero, &miss);
|
|
|
| - // Get the elements array and make sure it is a fast element array, not 'cow'.
|
| - __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
|
| - __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
|
| - Immediate(factory()->fixed_array_map()));
|
| - __ j(not_equal, &miss);
|
| +MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
|
| + MapList* receiver_maps,
|
| + CodeList* handler_ics) {
|
| + // ----------- S t a t e -------------
|
| + // -- eax : value
|
| + // -- ecx : key
|
| + // -- edx : receiver
|
| + // -- esp[0] : return address
|
| + // -----------------------------------
|
| + Label miss;
|
| + __ JumpIfSmi(edx, &miss);
|
|
|
| - // Check that the key is within bounds.
|
| - if (receiver->IsJSArray()) {
|
| - __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
|
| - __ j(above_equal, &miss);
|
| - } else {
|
| - __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // Compare smis.
|
| - __ j(above_equal, &miss);
|
| + Register map_reg = ebx;
|
| + __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
|
| + int receiver_count = receiver_maps->length();
|
| + for (int current = 0; current < receiver_count; ++current) {
|
| + Handle<Map> map(receiver_maps->at(current));
|
| + __ cmp(map_reg, map);
|
| + __ j(equal, Handle<Code>(handler_ics->at(current)));
|
| }
|
| -
|
| - // Do the store and update the write barrier. Make sure to preserve
|
| - // the value in register eax.
|
| - __ mov(edx, Operand(eax));
|
| - __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax);
|
| - __ RecordWrite(edi, 0, edx, ecx);
|
| -
|
| - // Done.
|
| - __ ret(0);
|
| -
|
| - // Handle store cache miss.
|
| __ bind(&miss);
|
| - Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
|
| - __ jmp(ic, RelocInfo::CODE_TARGET);
|
| + Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
|
| + __ jmp(miss_ic, RelocInfo::CODE_TARGET);
|
|
|
| // Return the generated code.
|
| - return GetCode(NORMAL, NULL);
|
| + return GetCode(NORMAL, NULL, MEGAMORPHIC);
|
| }
|
|
|
|
|
| @@ -3120,48 +3126,52 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
|
| }
|
|
|
|
|
| -MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
|
| +MaybeObject* KeyedLoadStubCompiler::CompileLoadFastElement(Map* receiver_map) {
|
| // ----------- S t a t e -------------
|
| // -- eax : key
|
| // -- edx : receiver
|
| // -- esp[0] : return address
|
| // -----------------------------------
|
| - Label miss;
|
| -
|
| - // Check that the receiver isn't a smi.
|
| - __ test(edx, Immediate(kSmiTagMask));
|
| - __ j(zero, &miss);
|
| + MaybeObject* maybe_stub = KeyedLoadFastElementStub().TryGetCode();
|
| + Code* stub;
|
| + if (!maybe_stub->To(&stub)) return maybe_stub;
|
| + __ DispatchMap(edx,
|
| + Handle<Map>(receiver_map),
|
| + Handle<Code>(stub),
|
| + DO_SMI_CHECK);
|
|
|
| - // Check that the map matches.
|
| - __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
|
| - Immediate(Handle<Map>(receiver->map())));
|
| - __ j(not_equal, &miss);
|
| + GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
|
|
|
| - // Check that the key is a smi.
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(not_zero, &miss);
|
| + // Return the generated code.
|
| + return GetCode(NORMAL, NULL);
|
| +}
|
|
|
| - // Get the elements array.
|
| - __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
|
| - __ AssertFastElements(ecx);
|
|
|
| - // Check that the key is within bounds.
|
| - __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
|
| - __ j(above_equal, &miss);
|
| +MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
|
| + MapList* receiver_maps,
|
| + CodeList* handler_ics) {
|
| + // ----------- S t a t e -------------
|
| + // -- eax : key
|
| + // -- edx : receiver
|
| + // -- esp[0] : return address
|
| + // -----------------------------------
|
| + Label miss;
|
| + __ JumpIfSmi(edx, &miss);
|
|
|
| - // Load the result and make sure it's not the hole.
|
| - __ mov(ebx, Operand(ecx, eax, times_2,
|
| - FixedArray::kHeaderSize - kHeapObjectTag));
|
| - __ cmp(ebx, factory()->the_hole_value());
|
| - __ j(equal, &miss);
|
| - __ mov(eax, ebx);
|
| - __ ret(0);
|
| + Register map_reg = ebx;
|
| + __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
|
| + int receiver_count = receiver_maps->length();
|
| + for (int current = 0; current < receiver_count; ++current) {
|
| + Handle<Map> map(receiver_maps->at(current));
|
| + __ cmp(map_reg, map);
|
| + __ j(equal, Handle<Code>(handler_ics->at(current)));
|
| + }
|
|
|
| __ bind(&miss);
|
| GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
|
|
|
| // Return the generated code.
|
| - return GetCode(NORMAL, NULL);
|
| + return GetCode(NORMAL, NULL, MEGAMORPHIC);
|
| }
|
|
|
|
|
| @@ -3304,36 +3314,82 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
|
| }
|
|
|
|
|
| -MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
|
| - JSObject*receiver, ExternalArrayType array_type, Code::Flags flags) {
|
| +MaybeObject* ExternalArrayLoadStubCompiler::CompileLoad(
|
| + JSObject*receiver, ExternalArrayType array_type) {
|
| // ----------- S t a t e -------------
|
| // -- eax : key
|
| // -- edx : receiver
|
| // -- esp[0] : return address
|
| // -----------------------------------
|
| - Label slow, failed_allocation;
|
| + MaybeObject* maybe_stub =
|
| + KeyedLoadExternalArrayStub(array_type).TryGetCode();
|
| + Code* stub;
|
| + if (!maybe_stub->To(&stub)) return maybe_stub;
|
| + __ DispatchMap(edx,
|
| + Handle<Map>(receiver->map()),
|
| + Handle<Code>(stub),
|
| + DO_SMI_CHECK);
|
| +
|
| + Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
|
| + __ jmp(ic, RelocInfo::CODE_TARGET);
|
| +
|
| + // Return the generated code.
|
| + return GetCode();
|
| +}
|
|
|
| - // Check that the object isn't a smi.
|
| - __ test(edx, Immediate(kSmiTagMask));
|
| - __ j(zero, &slow);
|
| +
|
| +MaybeObject* ExternalArrayStoreStubCompiler::CompileStore(
|
| + JSObject* receiver, ExternalArrayType array_type) {
|
| + // ----------- S t a t e -------------
|
| + // -- eax : value
|
| + // -- ecx : key
|
| + // -- edx : receiver
|
| + // -- esp[0] : return address
|
| + // -----------------------------------
|
| + MaybeObject* maybe_stub =
|
| + KeyedStoreExternalArrayStub(array_type).TryGetCode();
|
| + Code* stub;
|
| + if (!maybe_stub->To(&stub)) return maybe_stub;
|
| + __ DispatchMap(edx,
|
| + 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 -------------
|
| + // -- eax : key
|
| + // -- edx : receiver
|
| + // -- esp[0] : return address
|
| + // -----------------------------------
|
| + Label miss_force_generic, failed_allocation, 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 key is a smi.
|
| __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(not_zero, &slow);
|
| -
|
| - // Check that the map matches.
|
| - __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, DO_SMI_CHECK);
|
| - __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
|
| + __ j(not_zero, &miss_force_generic);
|
|
|
| - // eax: key, known to be a smi.
|
| - // edx: receiver, known to be a JSObject.
|
| - // ebx: elements object, known to be an external array.
|
| // Check that the index is in range.
|
| __ mov(ecx, eax);
|
| __ SmiUntag(ecx); // Untag the index.
|
| + __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
|
| __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
|
| // Unsigned comparison catches both negative and too-large values.
|
| - __ j(above_equal, &slow);
|
| + __ j(above_equal, &miss_force_generic);
|
| __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
|
| // ebx: base pointer of external storage
|
| switch (array_type) {
|
| @@ -3440,47 +3496,48 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
|
|
|
| // 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 -------------
|
| // -- eax : key
|
| // -- edx : receiver
|
| // -- esp[0] : return address
|
| // -----------------------------------
|
|
|
| - __ pop(ebx);
|
| - __ push(edx); // receiver
|
| - __ push(eax); // name
|
| - __ push(ebx); // 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);
|
| + // ----------- S t a t e -------------
|
| + // -- eax : key
|
| + // -- edx : receiver
|
| + // -- esp[0] : return address
|
| + // -----------------------------------
|
|
|
| - // Return the generated code.
|
| - return GetCode(flags);
|
| + // Miss case: Jump to runtime.
|
| + __ bind(&miss_force_generic);
|
| + 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 -------------
|
| - // -- eax : value
|
| - // -- ecx : key
|
| + // -- eax : key
|
| // -- edx : receiver
|
| // -- esp[0] : return address
|
| // -----------------------------------
|
| - Label slow, check_heap_number;
|
| -
|
| - // Check that the object isn't a smi.
|
| - __ test(edx, Immediate(kSmiTagMask));
|
| - __ j(zero, &slow);
|
| + Label miss_force_generic, slow, check_heap_number;
|
|
|
| - // Check that the map matches.
|
| - __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, DO_SMI_CHECK);
|
| + // 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.
|
| __ test(ecx, Immediate(kSmiTagMask));
|
| - __ j(not_zero, &slow);
|
| + __ j(not_zero, &miss_force_generic);
|
|
|
| // Check that the index is in range.
|
| __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
|
| @@ -3559,7 +3616,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
|
| // edi: elements array
|
| // ebx: untagged index
|
| __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
|
| - Immediate(factory()->heap_number_map()));
|
| + Immediate(masm->isolate()->factory()->heap_number_map()));
|
| __ j(not_equal, &slow);
|
|
|
| // The WebGL specification leaves the behavior of storing NaN and
|
| @@ -3654,6 +3711,9 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
|
|
|
| // Slow case: call runtime.
|
| __ bind(&slow);
|
| + Counters* counters = masm->isolate()->counters();
|
| + __ IncrementCounter(counters->keyed_store_external_array_slow(), 1);
|
| +
|
| // ----------- S t a t e -------------
|
| // -- eax : value
|
| // -- ecx : key
|
| @@ -3661,19 +3721,109 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
|
| // -- esp[0] : return address
|
| // -----------------------------------
|
|
|
| - __ pop(ebx);
|
| - __ push(edx);
|
| - __ push(ecx);
|
| - __ push(eax);
|
| - __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
|
| - __ push(Immediate(Smi::FromInt(
|
| - Code::ExtractExtraICStateFromFlags(flags) & kStrictMode)));
|
| - __ push(ebx); // return address
|
| + Handle<Code> ic = masm->isolate()->builtins()->KeyedStoreIC_Slow();
|
| + __ jmp(ic, RelocInfo::CODE_TARGET);
|
| +
|
| + // ----------- S t a t e -------------
|
| + // -- eax : value
|
| + // -- ecx : key
|
| + // -- edx : receiver
|
| + // -- esp[0] : return address
|
| + // -----------------------------------
|
| +
|
| + __ bind(&miss_force_generic);
|
| + Handle<Code> miss_ic =
|
| + masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
|
| + __ jmp(miss_ic, RelocInfo::CODE_TARGET);
|
| +}
|
| +
|
| +
|
| +
|
|
|
| - // Do tail-call to runtime routine.
|
| - __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
|
| +void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
|
| + // ----------- S t a t e -------------
|
| + // -- eax : key
|
| + // -- edx : receiver
|
| + // -- esp[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.
|
| + __ test(eax, Immediate(kSmiTagMask));
|
| + __ j(not_zero, &miss_force_generic);
|
| +
|
| + // Get the elements array.
|
| + __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
|
| + __ AssertFastElements(ecx);
|
| +
|
| + // Check that the key is within bounds.
|
| + __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
|
| + __ j(above_equal, &miss_force_generic);
|
| +
|
| + // Load the result and make sure it's not the hole.
|
| + __ mov(ebx, Operand(ecx, eax, times_2,
|
| + FixedArray::kHeaderSize - kHeapObjectTag));
|
| + __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
|
| + __ j(equal, &miss_force_generic);
|
| + __ mov(eax, ebx);
|
| + __ ret(0);
|
| +
|
| + __ bind(&miss_force_generic);
|
| + Handle<Code> miss_ic =
|
| + masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
|
| + __ jmp(miss_ic, RelocInfo::CODE_TARGET);
|
| +}
|
| +
|
| +
|
| +void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
|
| + bool is_js_array) {
|
| + // ----------- S t a t e -------------
|
| + // -- eax : key
|
| + // -- edx : receiver
|
| + // -- esp[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.
|
| + __ test(ecx, Immediate(kSmiTagMask));
|
| + __ j(not_zero, &miss_force_generic);
|
| +
|
| + // Get the elements array and make sure it is a fast element array, not 'cow'.
|
| + __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
|
| + __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
|
| + Immediate(masm->isolate()->factory()->fixed_array_map()));
|
| + __ j(not_equal, &miss_force_generic);
|
| +
|
| + if (is_js_array) {
|
| + // Check that the key is within bounds.
|
| + __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
|
| + __ j(above_equal, &miss_force_generic);
|
| + } else {
|
| + // Check that the key is within bounds.
|
| + __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
|
| + __ j(above_equal, &miss_force_generic);
|
| + }
|
| +
|
| + // Do the store and update the write barrier. Make sure to preserve
|
| + // the value in register eax.
|
| + __ mov(edx, Operand(eax));
|
| + __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax);
|
| + __ RecordWrite(edi, 0, edx, ecx);
|
| +
|
| + // Done.
|
| + __ ret(0);
|
|
|
| - return GetCode(flags);
|
| + // Handle store cache miss, replacing the ic with the generic stub.
|
| + __ bind(&miss_force_generic);
|
| + Handle<Code> ic_force_generic =
|
| + masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
|
| + __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
|
| }
|
|
|
|
|
|
|