Better support for 'polymorphic' JS and external arrays

Allow  keyed store/load stubs to switch between external array and fast JS arrays without forcing a state transition to the generic stub.

There CL consists of two pieces of functionality. First, code stubs for fast element arrays don't immediately transition to the MEGAMORPHIC state when there's a map mismatch. Second, two ICs are cached per map for fast elements, the MONOMORPHIC version, and a new MEGAMORPHIC version that handles two or more different maps. Currently, the only array types supported by the MEGAMORPHIC stub are fast elements for objects and JSArrays.

BUG=
TEST=

Review URL: http://codereview.chromium.org/6894003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7917 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
danno@chromium.org 2011-05-17 17:29:13 +00:00
parent 46aeea9d3a
commit 5a9b2b3c5f
34 changed files with 2015 additions and 867 deletions

View File

@ -1,4 +1,4 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:

View File

@ -868,10 +868,7 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
}
Object* KeyedLoadIC_Miss(Arguments args);
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ---------- S t a t e --------------
// -- lr : return address
// -- r0 : key
@ -883,8 +880,11 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
__ Push(r1, r0);
ExternalReference ref =
ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
// Perform tail call to the entry.
ExternalReference ref = force_generic
? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
: ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
__ TailCallExternalReference(ref, 2, 1);
}
@ -1075,7 +1075,7 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
char_at_generator.GenerateSlow(masm, call_helper);
__ bind(&miss);
GenerateMiss(masm);
GenerateMiss(masm, false);
}
@ -1115,11 +1115,11 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1);
__ bind(&slow);
GenerateMiss(masm);
GenerateMiss(masm, false);
}
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ---------- S t a t e --------------
// -- r0 : value
// -- r1 : key
@ -1130,8 +1130,29 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
// Push receiver, key and value for runtime call.
__ Push(r2, r1, r0);
ExternalReference ref = force_generic
? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
masm->isolate())
: ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}
void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
// ---------- S t a t e --------------
// -- r0 : value
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
// -----------------------------------
// Push receiver, key and value for runtime call.
__ Push(r2, r1, r0);
// The slow case calls into the runtime to complete the store without causing
// an IC miss that would otherwise cause a transition to the generic stub.
ExternalReference ref =
ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}

View File

@ -1681,6 +1681,23 @@ void MacroAssembler::CheckMap(Register obj,
}
void MacroAssembler::DispatchMap(Register obj,
Register scratch,
Handle<Map> map,
Handle<Code> success,
SmiCheckType smi_check_type) {
Label fail;
if (smi_check_type == DO_SMI_CHECK) {
JumpIfSmi(obj, &fail);
}
ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
mov(ip, Operand(map));
cmp(scratch, ip);
Jump(success, RelocInfo::CODE_TARGET, eq);
bind(&fail);
}
void MacroAssembler::TryGetFunctionPrototype(Register function,
Register result,
Register scratch,

View File

@ -578,6 +578,7 @@ class MacroAssembler: public Assembler {
Label* fail,
SmiCheckType smi_check_type);
void CheckMap(Register obj,
Register scratch,
Heap::RootListIndex index,
@ -585,6 +586,16 @@ class MacroAssembler: public Assembler {
SmiCheckType smi_check_type);
// Check if the map of an object is equal to a specified map and branch to a
// specified target if equal. Skip the smi check if not required (object is
// known to be a heap object)
void DispatchMap(Register obj,
Register scratch,
Handle<Map> map,
Handle<Code> success,
SmiCheckType smi_check_type);
// Compare the object in a register to a value from the root list.
// Uses the ip register as scratch.
void CompareRoot(Register obj, Heap::RootListIndex index);

View File

@ -3091,52 +3091,56 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
}
MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
MaybeObject* KeyedLoadStubCompiler::CompileLoadFastElement(Map* receiver_map) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
MaybeObject* maybe_stub = KeyedLoadFastElementStub().TryGetCode();
Code* stub;
if (!maybe_stub->To(&stub)) return maybe_stub;
__ DispatchMap(r1,
r2,
Handle<Map>(receiver_map),
Handle<Code>(stub),
DO_SMI_CHECK);
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode(NORMAL, NULL);
}
MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
MapList* receiver_maps,
CodeList* handler_ics) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
Label miss;
__ JumpIfSmi(r1, &miss);
// Check that the receiver isn't a smi.
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &miss);
// Check that the map matches.
int receiver_count = receiver_maps->length();
__ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
__ cmp(r2, Operand(Handle<Map>(receiver->map())));
__ b(ne, &miss);
// Check that the key is a smi.
__ tst(r0, Operand(kSmiTagMask));
__ b(ne, &miss);
// Get the elements array.
__ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
__ AssertFastElements(r2);
// Check that the key is within bounds.
__ ldr(r3, FieldMemOperand(r2, FixedArray::kLengthOffset));
__ cmp(r0, Operand(r3));
__ b(hs, &miss);
// Load the result and make sure it's not the hole.
__ add(r3, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ ldr(r4,
MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ cmp(r4, ip);
__ b(eq, &miss);
__ mov(r0, r4);
__ Ret();
for (int current = 0; current < receiver_count; ++current) {
Handle<Map> map(receiver_maps->at(current));
Handle<Code> code(handler_ics->at(current));
__ mov(ip, Operand(map));
__ cmp(r2, ip);
__ Jump(code, RelocInfo::CODE_TARGET, eq);
}
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
__ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
// Return the generated code.
return GetCode(NORMAL, NULL);
return GetCode(NORMAL, NULL, MEGAMORPHIC);
}
@ -3178,69 +3182,27 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
}
MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
JSObject* receiver) {
MaybeObject* KeyedStoreStubCompiler::CompileStoreFastElement(
Map* receiver_map) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
// -- r3 : scratch
// -- r4 : scratch (elements)
// -----------------------------------
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(r2,
r3,
Handle<Map>(receiver_map),
Handle<Code>(stub),
DO_SMI_CHECK);
Register value_reg = r0;
Register key_reg = r1;
Register receiver_reg = r2;
Register scratch = r3;
Register elements_reg = r4;
// Check that the receiver isn't a smi.
__ tst(receiver_reg, Operand(kSmiTagMask));
__ b(eq, &miss);
// Check that the map matches.
__ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
__ cmp(scratch, Operand(Handle<Map>(receiver->map())));
__ b(ne, &miss);
// Check that the key is a smi.
__ tst(key_reg, Operand(kSmiTagMask));
__ b(ne, &miss);
// Get the elements array and make sure it is a fast element array, not 'cow'.
__ ldr(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
__ ldr(scratch, FieldMemOperand(elements_reg, HeapObject::kMapOffset));
__ cmp(scratch, Operand(Handle<Map>(factory()->fixed_array_map())));
__ b(ne, &miss);
// Check that the key is within bounds.
if (receiver->IsJSArray()) {
__ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
} else {
__ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
}
// Compare smis.
__ cmp(key_reg, scratch);
__ b(hs, &miss);
__ add(scratch,
elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ str(value_reg,
MemOperand(scratch, key_reg, LSL, kPointerSizeLog2 - kSmiTagSize));
__ RecordWrite(scratch,
Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize),
receiver_reg , elements_reg);
// value_reg (r0) is preserved.
// Done.
__ Ret();
__ bind(&miss);
Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@ -3248,6 +3210,38 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
}
MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
MapList* receiver_maps,
CodeList* handler_ics) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
// -- r3 : scratch
// -----------------------------------
Label miss;
__ JumpIfSmi(r2, &miss);
int receiver_count = receiver_maps->length();
__ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
for (int current = 0; current < receiver_count; ++current) {
Handle<Map> map(receiver_maps->at(current));
Handle<Code> code(handler_ics->at(current));
__ mov(ip, Operand(map));
__ cmp(r3, ip);
__ Jump(code, RelocInfo::CODE_TARGET, eq);
}
__ bind(&miss);
Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
// Return the generated code.
return GetCode(NORMAL, NULL, MEGAMORPHIC);
}
MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
// ----------- S t a t e -------------
// -- r0 : argc
@ -3392,6 +3386,60 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
}
MaybeObject* ExternalArrayLoadStubCompiler::CompileLoad(
JSObject*receiver, ExternalArrayType array_type) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
MaybeObject* maybe_stub =
KeyedLoadExternalArrayStub(array_type).TryGetCode();
Code* stub;
if (!maybe_stub->To(&stub)) return maybe_stub;
__ DispatchMap(r1,
r2,
Handle<Map>(receiver->map()),
Handle<Code>(stub),
DO_SMI_CHECK);
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode();
}
MaybeObject* ExternalArrayStoreStubCompiler::CompileStore(
JSObject* receiver, ExternalArrayType array_type) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : name
// -- r2 : receiver
// -- lr : return address
// -----------------------------------
MaybeObject* maybe_stub =
KeyedStoreExternalArrayStub(array_type).TryGetCode();
Code* stub;
if (!maybe_stub->To(&stub)) return maybe_stub;
__ DispatchMap(r2,
r3,
Handle<Map>(receiver->map()),
Handle<Code>(stub),
DONT_DO_SMI_CHECK);
Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
return GetCode();
}
#undef __
#define __ ACCESS_MASM(masm)
static bool IsElementTypeSigned(ExternalArrayType array_type) {
switch (array_type) {
case kExternalByteArray:
@ -3411,30 +3459,24 @@ static bool IsElementTypeSigned(ExternalArrayType array_type) {
}
MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
JSObject* receiver_object,
ExternalArrayType array_type,
Code::Flags flags) {
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
ExternalArrayType array_type) {
// ---------- S t a t e --------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
Label slow, failed_allocation;
Label miss_force_generic, slow, failed_allocation;
Register key = r0;
Register receiver = r1;
// Check that the object isn't a smi
__ JumpIfSmi(receiver, &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.
__ JumpIfNotSmi(key, &slow);
// Make sure that we've got the right map.
__ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ cmp(r2, Operand(Handle<Map>(receiver_object->map())));
__ b(ne, &slow);
__ JumpIfNotSmi(key, &miss_force_generic);
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// r3: elements array
@ -3443,7 +3485,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
__ cmp(ip, Operand(key, ASR, kSmiTagSize));
// Unsigned comparison catches both negative and too-large values.
__ b(lo, &slow);
__ b(lo, &miss_force_generic);
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage
@ -3535,8 +3577,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
__ Ret();
} else {
WriteInt32ToHeapNumberStub stub(value, r0, r3);
MaybeObject* stub_code = masm()->TryTailCallStub(&stub);
if (stub_code->IsFailure()) return stub_code;
__ TailCallStub(&stub);
}
} else if (array_type == kExternalUnsignedIntArray) {
// The test is different for unsigned int values. Since we need
@ -3581,12 +3622,12 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
__ bind(&box_int_0);
// Integer does not have leading zeros.
GenerateUInt2Double(masm(), hiword, loword, r4, 0);
GenerateUInt2Double(masm, hiword, loword, r4, 0);
__ b(&done);
__ bind(&box_int_1);
// Integer has one leading zero.
GenerateUInt2Double(masm(), hiword, loword, r4, 1);
GenerateUInt2Double(masm, hiword, loword, r4, 1);
__ bind(&done);
@ -3708,7 +3749,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
// Slow case, key and receiver still in r0 and r1.
__ bind(&slow);
__ IncrementCounter(
masm()->isolate()->counters()->keyed_load_external_array_slow(),
masm->isolate()->counters()->keyed_load_external_array_slow(),
1, r2, r3);
// ---------- S t a t e --------------
@ -3721,21 +3762,23 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
__ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
return GetCode(flags);
__ bind(&miss_force_generic);
Code* stub = masm->isolate()->builtins()->builtin(
Builtins::kKeyedLoadIC_MissForceGeneric);
__ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
}
MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
JSObject* receiver_object,
ExternalArrayType array_type,
Code::Flags flags) {
void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
ExternalArrayType array_type) {
// ---------- S t a t e --------------
// -- r0 : value
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
// -----------------------------------
Label slow, check_heap_number;
Label slow, check_heap_number, miss_force_generic;
// Register usage.
Register value = r0;
@ -3743,25 +3786,20 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
Register receiver = r2;
// r3 mostly holds the elements array or the destination external array.
// Check that the object isn't a smi.
__ JumpIfSmi(receiver, &slow);
// Make sure that we've got the right map.
__ ldr(r3, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ cmp(r3, Operand(Handle<Map>(receiver_object->map())));
__ b(ne, &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.
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// Check that the key is a smi.
__ JumpIfNotSmi(key, &slow);
__ JumpIfNotSmi(key, &miss_force_generic);
// Check that the index is in range
__ SmiUntag(r4, key);
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
__ cmp(r4, ip);
// Unsigned comparison catches both negative and too-large values.
__ b(hs, &slow);
__ b(hs, &miss_force_generic);
// Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values.
@ -3799,7 +3837,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
break;
case kExternalFloatArray:
// Perform int-to-float conversion and store to memory.
StoreIntAsFloat(masm(), r3, r4, r5, r6, r7, r9);
StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
break;
case kExternalDoubleArray:
__ add(r3, r3, Operand(r4, LSL, 3));
@ -3811,7 +3849,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
destination = FloatingPointHelper::kCoreRegisters;
}
FloatingPointHelper::ConvertIntToDouble(
masm(), r5, destination,
masm, r5, destination,
d0, r6, r7, // These are: double_dst, dst1, dst2.
r4, s2); // These are: scratch2, single_scratch.
if (destination == FloatingPointHelper::kVFPRegisters) {
@ -4038,28 +4076,137 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
}
}
// Slow case: call runtime.
// Slow case, key and receiver still in r0 and r1.
__ bind(&slow);
__ IncrementCounter(
masm->isolate()->counters()->keyed_load_external_array_slow(),
1, r2, r3);
// Entry registers are intact.
// ---------- S t a t e --------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
Handle<Code> slow_ic =
masm->isolate()->builtins()->KeyedStoreIC_Slow();
__ Jump(slow_ic, RelocInfo::CODE_TARGET);
// Miss case, call the runtime.
__ bind(&miss_force_generic);
// ---------- S t a t e --------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
Handle<Code> miss_ic =
masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
__ Jump(miss_ic, RelocInfo::CODE_TARGET);
}
void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
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(r0, &miss_force_generic);
// Get the elements array.
__ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
__ AssertFastElements(r2);
// Check that the key is within bounds.
__ ldr(r3, FieldMemOperand(r2, FixedArray::kLengthOffset));
__ cmp(r0, Operand(r3));
__ b(hs, &miss_force_generic);
// Load the result and make sure it's not the hole.
__ add(r3, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ ldr(r4,
MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ cmp(r4, ip);
__ b(eq, &miss_force_generic);
__ mov(r0, r4);
__ Ret();
__ bind(&miss_force_generic);
Code* stub = masm->isolate()->builtins()->builtin(
Builtins::kKeyedLoadIC_MissForceGeneric);
__ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
}
void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
bool is_js_array) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
// -- r3 : scratch
// -- r4 : scratch (elements)
// -----------------------------------
Label miss_force_generic;
// Push receiver, key and value for runtime call.
__ Push(r2, r1, r0);
Register value_reg = r0;
Register key_reg = r1;
Register receiver_reg = r2;
Register scratch = r3;
Register elements_reg = r4;
__ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
__ mov(r0, Operand(Smi::FromInt(
Code::ExtractExtraICStateFromFlags(flags) & kStrictMode)));
__ Push(r1, r0);
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
__ TailCallRuntime(Runtime::kSetProperty, 5, 1);
// Check that the key is a smi.
__ JumpIfNotSmi(r0, &miss_force_generic);
return GetCode(flags);
// Get the elements array and make sure it is a fast element array, not 'cow'.
__ ldr(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
__ CheckMap(elements_reg,
scratch,
Heap::kFixedArrayMapRootIndex,
&miss_force_generic,
DONT_DO_SMI_CHECK);
// Check that the key is within bounds.
if (is_js_array) {
__ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
} else {
__ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
}
// Compare smis.
__ cmp(key_reg, scratch);
__ b(hs, &miss_force_generic);
__ add(scratch,
elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ str(value_reg,
MemOperand(scratch, key_reg, LSL, kPointerSizeLog2 - kSmiTagSize));
__ RecordWrite(scratch,
Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize),
receiver_reg , elements_reg);
// value_reg (r0) is preserved.
// Done.
__ Ret();
__ bind(&miss_force_generic);
Handle<Code> ic =
masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
__ Jump(ic, RelocInfo::CODE_TARGET);
}

View File

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -1341,8 +1341,18 @@ static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
}
static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
KeyedLoadIC::GenerateRuntimeGetProperty(masm);
}
static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
KeyedLoadIC::GenerateMiss(masm);
KeyedLoadIC::GenerateMiss(masm, false);
}
static void Generate_KeyedLoadIC_MissForceGeneric(MacroAssembler* masm) {
KeyedLoadIC::GenerateMiss(masm, true);
}
@ -1431,7 +1441,17 @@ static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) {
static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
KeyedStoreIC::GenerateMiss(masm);
KeyedStoreIC::GenerateMiss(masm, false);
}
static void Generate_KeyedStoreIC_MissForceGeneric(MacroAssembler* masm) {
KeyedStoreIC::GenerateMiss(masm, true);
}
static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
KeyedStoreIC::GenerateSlow(masm);
}

View File

@ -1,4 +1,4 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -97,11 +97,18 @@ enum BuiltinExtraArguments {
Code::kNoExtraICState) \
V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(KeyedLoadIC_MissForceGeneric, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(KeyedLoadIC_Slow, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(StoreIC_Miss, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
\
V(KeyedStoreIC_MissForceGeneric, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(KeyedStoreIC_Slow, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED, \
Code::kNoExtraICState) \
V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC, \

View File

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -29,6 +29,7 @@
#include "bootstrapper.h"
#include "code-stubs.h"
#include "stub-cache.h"
#include "factory.h"
#include "gdb-jit.h"
#include "macro-assembler.h"
@ -243,4 +244,24 @@ const char* InstanceofStub::GetName() {
}
void KeyedLoadFastElementStub::Generate(MacroAssembler* masm) {
KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
}
void KeyedStoreFastElementStub::Generate(MacroAssembler* masm) {
KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_);
}
void KeyedLoadExternalArrayStub::Generate(MacroAssembler* masm) {
KeyedLoadStubCompiler::GenerateLoadExternalArray(masm, array_type_);
}
void KeyedStoreExternalArrayStub::Generate(MacroAssembler* masm) {
KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, array_type_);
}
} } // namespace v8::internal

View File

@ -66,6 +66,10 @@ namespace internal {
V(NumberToString) \
V(CEntry) \
V(JSEntry) \
V(KeyedLoadFastElement) \
V(KeyedStoreFastElement) \
V(KeyedLoadExternalArray) \
V(KeyedStoreExternalArray) \
V(DebuggerStatement) \
V(StringDictionaryNegativeLookup)
@ -922,6 +926,86 @@ class AllowStubCallsScope {
DISALLOW_COPY_AND_ASSIGN(AllowStubCallsScope);
};
#ifdef DEBUG
#define DECLARE_ARRAY_STUB_PRINT(name) void Print() { PrintF(#name); }
#else
#define DECLARE_ARRAY_STUB_PRINT(name)
#endif
class KeyedLoadFastElementStub : public CodeStub {
public:
explicit KeyedLoadFastElementStub() {
}
Major MajorKey() { return KeyedLoadFastElement; }
int MinorKey() { return 0; }
void Generate(MacroAssembler* masm);
const char* GetName() { return "KeyedLoadFastElementStub"; }
DECLARE_ARRAY_STUB_PRINT(KeyedLoadFastElementStub)
};
class KeyedStoreFastElementStub : public CodeStub {
public:
explicit KeyedStoreFastElementStub(bool is_js_array)
: is_js_array_(is_js_array) { }
Major MajorKey() { return KeyedStoreFastElement; }
int MinorKey() { return is_js_array_ ? 1 : 0; }
void Generate(MacroAssembler* masm);
const char* GetName() { return "KeyedStoreFastElementStub"; }
DECLARE_ARRAY_STUB_PRINT(KeyedStoreFastElementStub)
private:
bool is_js_array_;
};
class KeyedLoadExternalArrayStub : public CodeStub {
public:
explicit KeyedLoadExternalArrayStub(ExternalArrayType array_type)
: array_type_(array_type) { }
Major MajorKey() { return KeyedLoadExternalArray; }
int MinorKey() { return array_type_; }
void Generate(MacroAssembler* masm);
const char* GetName() { return "KeyedLoadExternalArrayStub"; }
DECLARE_ARRAY_STUB_PRINT(KeyedLoadExternalArrayStub)
protected:
ExternalArrayType array_type_;
};
class KeyedStoreExternalArrayStub : public CodeStub {
public:
explicit KeyedStoreExternalArrayStub(ExternalArrayType array_type)
: array_type_(array_type) { }
Major MajorKey() { return KeyedStoreExternalArray; }
int MinorKey() { return array_type_; }
void Generate(MacroAssembler* masm);
const char* GetName() { return "KeyedStoreExternalArrayStub"; }
DECLARE_ARRAY_STUB_PRINT(KeyedStoreExternalArrayStub)
protected:
ExternalArrayType array_type_;
};
} } // namespace v8::internal
#endif // V8_CODE_STUBS_H_

View File

@ -287,10 +287,9 @@ DEFINE_bool(native_code_counters, false,
DEFINE_bool(always_compact, false, "Perform compaction on every full GC")
DEFINE_bool(never_compact, false,
"Never perform compaction on full GC - testing only")
DEFINE_bool(cleanup_ics_at_gc, true,
"Flush inline caches prior to mark compact collection.")
DEFINE_bool(cleanup_caches_in_maps_at_gc, true,
"Flush code caches in maps during mark compact cycle.")
DEFINE_bool(cleanup_code_caches_at_gc, true,
"Flush inline caches prior to mark compact collection and "
"flush code caches in maps during mark compact cycle.")
DEFINE_int(random_seed, 0,
"Default seed for initializing random generator "
"(0, the default, means to use system random).")

View File

@ -1,4 +1,4 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -178,8 +178,14 @@ inline Heap* _inline_get_heap_();
V(value_of_symbol, "valueOf") \
V(InitializeVarGlobal_symbol, "InitializeVarGlobal") \
V(InitializeConstGlobal_symbol, "InitializeConstGlobal") \
V(KeyedLoadSpecialized_symbol, "KeyedLoadSpecialized") \
V(KeyedStoreSpecialized_symbol, "KeyedStoreSpecialized") \
V(KeyedLoadSpecializedMonomorphic_symbol, \
"KeyedLoadSpecializedMonomorphic") \
V(KeyedLoadSpecializedPolymorphic_symbol, \
"KeyedLoadSpecializedPolymorphic") \
V(KeyedStoreSpecializedMonomorphic_symbol, \
"KeyedStoreSpecializedMonomorphic") \
V(KeyedStoreSpecializedPolymorphic_symbol, \
"KeyedStoreSpecializedPolymorphic") \
V(stack_overflow_symbol, "kStackOverflowBoilerplate") \
V(illegal_access_symbol, "illegal access") \
V(out_of_memory_symbol, "out-of-memory") \
@ -207,32 +213,7 @@ inline Heap* _inline_get_heap_();
V(global_eval_symbol, "GlobalEval") \
V(identity_hash_symbol, "v8::IdentityHash") \
V(closure_symbol, "(closure)") \
V(use_strict, "use strict") \
V(KeyedLoadExternalByteArray_symbol, "KeyedLoadExternalByteArray") \
V(KeyedLoadExternalUnsignedByteArray_symbol, \
"KeyedLoadExternalUnsignedByteArray") \
V(KeyedLoadExternalShortArray_symbol, \
"KeyedLoadExternalShortArray") \
V(KeyedLoadExternalUnsignedShortArray_symbol, \
"KeyedLoadExternalUnsignedShortArray") \
V(KeyedLoadExternalIntArray_symbol, "KeyedLoadExternalIntArray") \
V(KeyedLoadExternalUnsignedIntArray_symbol, \
"KeyedLoadExternalUnsignedIntArray") \
V(KeyedLoadExternalFloatArray_symbol, "KeyedLoadExternalFloatArray") \
V(KeyedLoadExternalDoubleArray_symbol, "KeyedLoadExternalDoubleArray") \
V(KeyedLoadExternalPixelArray_symbol, "KeyedLoadExternalPixelArray") \
V(KeyedStoreExternalByteArray_symbol, "KeyedStoreExternalByteArray") \
V(KeyedStoreExternalUnsignedByteArray_symbol, \
"KeyedStoreExternalUnsignedByteArray") \
V(KeyedStoreExternalShortArray_symbol, "KeyedStoreExternalShortArray") \
V(KeyedStoreExternalUnsignedShortArray_symbol, \
"KeyedStoreExternalUnsignedShortArray") \
V(KeyedStoreExternalIntArray_symbol, "KeyedStoreExternalIntArray") \
V(KeyedStoreExternalUnsignedIntArray_symbol, \
"KeyedStoreExternalUnsignedIntArray") \
V(KeyedStoreExternalFloatArray_symbol, "KeyedStoreExternalFloatArray") \
V(KeyedStoreExternalDoubleArray_symbol, "KeyedStoreExternalDoubleArray") \
V(KeyedStoreExternalPixelArray_symbol, "KeyedStoreExternalPixelArray")
V(use_strict, "use strict")
// Forward declarations.
class GCTracer;

View File

@ -655,7 +655,7 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
char_at_generator.GenerateSlow(masm, call_helper);
__ bind(&miss);
GenerateMiss(masm);
GenerateMiss(masm, false);
}
@ -698,7 +698,7 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
__ TailCallExternalReference(ref, 2, 1);
__ bind(&slow);
GenerateMiss(masm);
GenerateMiss(masm, false);
}
@ -1222,7 +1222,7 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
}
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@ -1237,8 +1237,10 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
__ push(ebx); // return address
// Perform tail call to the entry.
ExternalReference ref =
ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
ExternalReference ref = force_generic
? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
masm->isolate())
: ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
}
@ -1430,7 +1432,7 @@ void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
}
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
@ -1445,12 +1447,35 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
__ push(ebx);
// Do tail-call to runtime routine.
ExternalReference ref =
ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
ExternalReference ref = force_generic
? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
masm->isolate())
: ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}
void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
__ pop(ebx);
__ push(edx);
__ push(ecx);
__ push(eax);
__ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
__ push(ebx); // return address
// Do tail-call to runtime routine.
ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
__ TailCallExternalReference(ref, 4, 1);
}
#undef __

View File

@ -286,6 +286,21 @@ void MacroAssembler::CheckMap(Register obj,
}
void MacroAssembler::DispatchMap(Register obj,
Handle<Map> map,
Handle<Code> success,
SmiCheckType smi_check_type) {
Label fail;
if (smi_check_type == DONT_DO_SMI_CHECK) {
JumpIfSmi(obj, &fail);
}
cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map));
j(equal, success);
bind(&fail);
}
Condition MacroAssembler::IsObjectStringType(Register heap_object,
Register map,
Register instance_type) {

View File

@ -45,6 +45,7 @@ enum AllocationFlags {
RESULT_CONTAINS_TOP = 1 << 1
};
// Convenience for platform-independent signatures. We do not normally
// distinguish memory operands from other operands on ia32.
typedef Operand MemOperand;
@ -206,14 +207,22 @@ class MacroAssembler: public Assembler {
// Compare instance type for map.
void CmpInstanceType(Register map, InstanceType type);
// Check if the map of an object is equal to a specified map and
// branch to label if not. Skip the smi check if not required
// (object is known to be a heap object)
// Check if the map of an object is equal to a specified map and branch to
// label if not. Skip the smi check if not required (object is known to be a
// heap object)
void CheckMap(Register obj,
Handle<Map> map,
Label* fail,
SmiCheckType smi_check_type);
// Check if the map of an object is equal to a specified map and branch to a
// specified target if equal. Skip the smi check if not required (object is
// known to be a heap object)
void DispatchMap(Register obj,
Handle<Map> map,
Handle<Code> success,
SmiCheckType smi_check_type);
// Check if the object in register heap_object is a string. Afterwards the
// register map contains the object map and the register instance_type
// contains the instance_type. The registers map and instance_type can be the

View File

@ -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,8 +2662,35 @@ 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
// -----------------------------------
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);
Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode(NORMAL, NULL);
}
MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
MapList* receiver_maps,
CodeList* handler_ics) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
@ -2663,51 +2698,22 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
// -- esp[0] : return address
// -----------------------------------
Label miss;
__ JumpIfSmi(edx, &miss);
// Check that the receiver isn't a smi.
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &miss);
// Check that the map matches.
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
Immediate(Handle<Map>(receiver->map())));
__ j(not_equal, &miss);
// 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);
// 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
// -----------------------------------
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);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
return GetCode(NORMAL, NULL);
}
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);
// Check that the receiver isn't a smi.
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &miss);
// Check that the map matches.
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
Immediate(Handle<Map>(receiver->map())));
__ j(not_equal, &miss);
// Check that the key is a smi.
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &miss);
// 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);
// 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);
// Check that the object isn't a smi.
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &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 -------------
// -- 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);
__ j(not_zero, &miss_force_generic);
// Check that the map matches.
__ CheckMap(edx, Handle<Map>(receiver->map()), &slow, DO_SMI_CHECK);
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
// 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);
// Return the generated code.
return GetCode(flags);
}
MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
// ----------- 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);
// Miss case: Jump to runtime.
__ bind(&miss_force_generic);
Handle<Code> miss_ic =
masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
__ jmp(miss_ic, RelocInfo::CODE_TARGET);
}
// Check that the map matches.
__ CheckMap(edx, Handle<Map>(receiver->map()), &slow, DO_SMI_CHECK);
void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
ExternalArrayType array_type) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss_force_generic, slow, check_heap_number;
// 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);
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kSetProperty, 5, 1);
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
return GetCode(flags);
__ bind(&miss_force_generic);
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 -------------
// -- 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);
// 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);
}

432
src/ic.cc
View File

@ -1,4 +1,4 @@
// Copyright 2006-2009 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -67,7 +67,33 @@ void IC::TraceIC(const char* type,
State new_state = StateFrom(new_target,
HEAP->undefined_value(),
HEAP->undefined_value());
PrintF("[%s (%c->%c)%s", type,
PrintF("[%s in ", type);
StackFrameIterator it;
while (it.frame()->fp() != this->fp()) it.Advance();
StackFrame* raw_frame = it.frame();
if (raw_frame->is_internal()) {
Isolate* isolate = new_target->GetIsolate();
Code* apply_builtin = isolate->builtins()->builtin(
Builtins::kFunctionApply);
if (raw_frame->unchecked_code() == apply_builtin) {
PrintF("apply from ");
it.Advance();
raw_frame = it.frame();
}
}
if (raw_frame->is_java_script()) {
JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
Code* js_code = frame->unchecked_code();
// Find the function on the stack and both the active code for the
// function and the original code.
JSFunction* function = JSFunction::cast(frame->function());
function->PrintName();
int code_offset = address() - js_code->instruction_start();
PrintF("+%d", code_offset);
} else {
PrintF("<unknown>");
}
PrintF(" (%c->%c)%s",
TransitionMarkFromState(old_state),
TransitionMarkFromState(new_state),
extra_info);
@ -274,11 +300,9 @@ void IC::Clear(Address address) {
switch (target->kind()) {
case Code::LOAD_IC: return LoadIC::Clear(address, target);
case Code::KEYED_LOAD_IC:
case Code::KEYED_EXTERNAL_ARRAY_LOAD_IC:
return KeyedLoadIC::Clear(address, target);
case Code::STORE_IC: return StoreIC::Clear(address, target);
case Code::KEYED_STORE_IC:
case Code::KEYED_EXTERNAL_ARRAY_STORE_IC:
return KeyedStoreIC::Clear(address, target);
case Code::CALL_IC: return CallIC::Clear(address, target);
case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
@ -1032,9 +1056,49 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
}
String* KeyedLoadIC::GetStubNameForCache(IC::State ic_state) {
if (ic_state == MONOMORPHIC) {
return isolate()->heap()->KeyedLoadSpecializedMonomorphic_symbol();
} else {
ASSERT(ic_state == MEGAMORPHIC);
return isolate()->heap()->KeyedLoadSpecializedPolymorphic_symbol();
}
}
MaybeObject* KeyedLoadIC::GetFastElementStubWithoutMapCheck(
bool is_js_array) {
return KeyedLoadFastElementStub().TryGetCode();
}
MaybeObject* KeyedLoadIC::GetExternalArrayStubWithoutMapCheck(
ExternalArrayType array_type) {
return KeyedLoadExternalArrayStub(array_type).TryGetCode();
}
MaybeObject* KeyedLoadIC::ConstructMegamorphicStub(
MapList* receiver_maps,
CodeList* targets,
StrictModeFlag strict_mode) {
Object* object;
KeyedLoadStubCompiler compiler;
MaybeObject* maybe_code = compiler.CompileLoadMegamorphic(receiver_maps,
targets);
if (!maybe_code->ToObject(&object)) return maybe_code;
isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
PROFILE(isolate(), CodeCreateEvent(
Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG,
Code::cast(object), 0));
return object;
}
MaybeObject* KeyedLoadIC::Load(State state,
Handle<Object> object,
Handle<Object> key) {
Handle<Object> key,
bool force_generic_stub) {
// Check for values that can be converted into a symbol.
// TODO(1295): Remove this code.
HandleScope scope(isolate());
@ -1160,34 +1224,31 @@ MaybeObject* KeyedLoadIC::Load(State state,
if (use_ic) {
Code* stub = generic_stub();
if (state == UNINITIALIZED) {
if (!force_generic_stub) {
if (object->IsString() && key->IsNumber()) {
if (state == UNINITIALIZED) {
stub = string_stub();
}
} else if (object->IsJSObject()) {
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
if (receiver->HasExternalArrayElements()) {
MaybeObject* probe =
isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
*receiver, false, kNonStrictMode);
stub = probe->IsFailure() ?
NULL : Code::cast(probe->ToObjectUnchecked());
} else if (receiver->HasIndexedInterceptor()) {
JSObject* receiver = JSObject::cast(*object);
if (receiver->HasIndexedInterceptor()) {
stub = indexed_interceptor_stub();
} else if (key->IsSmi() &&
receiver->map()->has_fast_elements()) {
MaybeObject* probe =
isolate()->stub_cache()->ComputeKeyedLoadSpecialized(*receiver);
stub = probe->IsFailure() ?
NULL : Code::cast(probe->ToObjectUnchecked());
} else if (key->IsSmi()) {
MaybeObject* maybe_stub = ComputeStub(receiver,
false,
kNonStrictMode,
stub);
stub = maybe_stub->IsFailure() ?
NULL : Code::cast(maybe_stub->ToObjectUnchecked());
}
}
}
if (stub != NULL) set_target(stub);
}
#ifdef DEBUG
TraceIC("KeyedLoadIC", key, state, target());
#endif // DEBUG
}
// Get the property.
return Runtime::GetObjectProperty(isolate(), object, key);
@ -1484,11 +1545,256 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
}
static bool AddOneReceiverMapIfMissing(MapList* receiver_maps,
Map* new_receiver_map) {
for (int current = 0; current < receiver_maps->length(); ++current) {
if (receiver_maps->at(current) == new_receiver_map) {
return false;
}
}
receiver_maps->Add(new_receiver_map);
return true;
}
void KeyedIC::GetReceiverMapsForStub(Code* stub, MapList* result) {
ASSERT(stub->is_inline_cache_stub());
if (stub == string_stub()) {
return result->Add(isolate()->heap()->string_map());
} else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) {
if (stub->ic_state() == MONOMORPHIC) {
result->Add(Map::cast(stub->FindFirstMap()));
} else {
ASSERT(stub->ic_state() == MEGAMORPHIC);
AssertNoAllocation no_allocation;
int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
for (RelocIterator it(stub, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
Object* object = info->target_object();
ASSERT(object->IsMap());
result->Add(Map::cast(object));
}
}
}
}
MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
bool is_store,
StrictModeFlag strict_mode,
Code* generic_stub) {
State ic_state = target()->ic_state();
Code* monomorphic_stub;
// Always compute the MONOMORPHIC stub, even if the MEGAMORPHIC stub ends up
// being used. This is necessary because the megamorphic stub needs to have
// access to more information than what is stored in the receiver map in some
// cases (external arrays need the array type from the MONOMORPHIC stub).
MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver,
is_store,
strict_mode,
generic_stub);
if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub;
if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
return monomorphic_stub;
}
ASSERT(target() != generic_stub);
// Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
// via megamorphic stubs, since they don't have a map in their relocation info
// and so the stubs can't be harvested for the object needed for a map check.
if (target()->type() != NORMAL) {
return generic_stub;
}
// Determine the list of receiver maps that this call site has seen,
// adding the map that was just encountered.
MapList target_receiver_maps;
GetReceiverMapsForStub(target(), &target_receiver_maps);
if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map())) {
// If the miss wasn't due to an unseen map, a MEGAMORPHIC stub
// won't help, use the generic stub.
return generic_stub;
}
// TODO(1385): Currently MEGAMORPHIC stubs are cached in the receiver map stub
// cache, but that can put receiver types together from unrelated call sites
// into the same stub--they always handle the union of all receiver maps seen
// at all call sites involving the receiver map. This is only an
// approximation: ideally, there would be a global cache that mapped sets of
// receiver maps to MEGAMORPHIC stubs. The complexity of the MEGAMORPHIC stub
// computation also leads to direct manipulation of the stub cache from the IC
// code, which the global cache solution would avoid.
Code::Kind kind = this->kind();
Code::Flags flags = Code::ComputeFlags(kind,
NOT_IN_LOOP,
MEGAMORPHIC,
strict_mode);
String* megamorphic_name = GetStubNameForCache(MEGAMORPHIC);
Object* maybe_cached_stub = receiver->map()->FindInCodeCache(megamorphic_name,
flags);
// Create a set of all receiver maps that have been seen at the IC call site
// and those seen by the MEGAMORPHIC cached stub, if that's the stub that's
// been selected.
MapList receiver_maps;
if (!maybe_cached_stub->IsUndefined()) {
GetReceiverMapsForStub(Code::cast(maybe_cached_stub), &receiver_maps);
}
bool added_map = false;
for (int i = 0; i < target_receiver_maps.length(); ++i) {
if (AddOneReceiverMapIfMissing(&receiver_maps,
target_receiver_maps.at(i))) {
added_map = true;
}
}
ASSERT(receiver_maps.length() > 0);
// If the maximum number of receiver maps has been exceeded, use the Generic
// version of the IC.
if (receiver_maps.length() > KeyedIC::kMaxKeyedPolymorphism) {
return generic_stub;
}
// If no maps have been seen at the call site that aren't in the cached
// stub, then use it.
if (!added_map) {
ASSERT(!maybe_cached_stub->IsUndefined());
ASSERT(maybe_cached_stub->IsCode());
return Code::cast(maybe_cached_stub);
}
// Lookup all of the receiver maps in the cache, they should all already
// have MONOMORPHIC stubs.
CodeList handler_ics(KeyedIC::kMaxKeyedPolymorphism);
for (int current = 0; current < receiver_maps.length(); ++current) {
Map* receiver_map(receiver_maps.at(current));
MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
receiver_map,
strict_mode,
generic_stub);
Code* cached_stub;
if (!maybe_cached_stub->To(&cached_stub)) {
return maybe_cached_stub;
}
handler_ics.Add(cached_stub);
}
Code* stub;
// Build the MEGAMORPHIC stub.
maybe_stub = ConstructMegamorphicStub(&receiver_maps,
&handler_ics,
strict_mode);
if (!maybe_stub->To(&stub)) return maybe_stub;
MaybeObject* maybe_update = receiver->UpdateMapCodeCache(
megamorphic_name,
stub);
if (maybe_update->IsFailure()) return maybe_update;
return stub;
}
MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
Map* receiver_map,
StrictModeFlag strict_mode,
Code* generic_stub) {
if ((receiver_map->instance_type() & kNotStringTag) == 0) {
ASSERT(string_stub() != NULL);
return string_stub();
} else if (receiver_map->has_external_array_elements()) {
// Determine the array type from the default MONOMORPHIC already generated
// stub. There is no other way to determine the type of the external array
// directly from the receiver type.
Code::Kind kind = this->kind();
Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
NORMAL,
strict_mode);
String* monomorphic_name = GetStubNameForCache(MONOMORPHIC);
Object* maybe_default_stub = receiver_map->FindInCodeCache(monomorphic_name,
flags);
if (maybe_default_stub->IsUndefined()) {
return generic_stub;
}
Code* default_stub = Code::cast(maybe_default_stub);
return GetExternalArrayStubWithoutMapCheck(
default_stub->external_array_type());
} else if (receiver_map->has_fast_elements()) {
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
return GetFastElementStubWithoutMapCheck(is_js_array);
} else {
return generic_stub;
}
}
MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
bool is_store,
StrictModeFlag strict_mode,
Code* generic_stub) {
Code* result = NULL;
if (receiver->HasExternalArrayElements()) {
MaybeObject* maybe_stub =
isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
receiver, is_store, strict_mode);
if (!maybe_stub->To(&result)) return maybe_stub;
} else if (receiver->map()->has_fast_elements()) {
MaybeObject* maybe_stub =
isolate()->stub_cache()->ComputeKeyedLoadOrStoreFastElement(
receiver, is_store, strict_mode);
if (!maybe_stub->To(&result)) return maybe_stub;
} else {
result = generic_stub;
}
return result;
}
String* KeyedStoreIC::GetStubNameForCache(IC::State ic_state) {
if (ic_state == MONOMORPHIC) {
return isolate()->heap()->KeyedStoreSpecializedMonomorphic_symbol();
} else {
ASSERT(ic_state == MEGAMORPHIC);
return isolate()->heap()->KeyedStoreSpecializedPolymorphic_symbol();
}
}
MaybeObject* KeyedStoreIC::GetFastElementStubWithoutMapCheck(
bool is_js_array) {
return KeyedStoreFastElementStub(is_js_array).TryGetCode();
}
MaybeObject* KeyedStoreIC::GetExternalArrayStubWithoutMapCheck(
ExternalArrayType array_type) {
return KeyedStoreExternalArrayStub(array_type).TryGetCode();
}
MaybeObject* KeyedStoreIC::ConstructMegamorphicStub(
MapList* receiver_maps,
CodeList* targets,
StrictModeFlag strict_mode) {
Object* object;
KeyedStoreStubCompiler compiler(strict_mode);
MaybeObject* maybe_code = compiler.CompileStoreMegamorphic(receiver_maps,
targets);
if (!maybe_code->ToObject(&object)) return maybe_code;
isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
PROFILE(isolate(), CodeCreateEvent(
Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG,
Code::cast(object), 0));
return object;
}
MaybeObject* KeyedStoreIC::Store(State state,
StrictModeFlag strict_mode,
Handle<Object> object,
Handle<Object> key,
Handle<Object> value) {
Handle<Object> value,
bool force_generic) {
if (key->IsSymbol()) {
Handle<String> name = Handle<String>::cast(key);
@ -1530,29 +1836,27 @@ MaybeObject* KeyedStoreIC::Store(State state,
ASSERT(!(use_ic && object->IsJSGlobalProxy()));
if (use_ic) {
Code* stub =
(strict_mode == kStrictMode) ? generic_stub_strict() : generic_stub();
if (state == UNINITIALIZED) {
if (object->IsJSObject()) {
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
if (receiver->HasExternalArrayElements()) {
MaybeObject* probe =
isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
*receiver, true, strict_mode);
stub = probe->IsFailure() ?
NULL : Code::cast(probe->ToObjectUnchecked());
} else if (key->IsSmi() && receiver->map()->has_fast_elements()) {
MaybeObject* probe =
isolate()->stub_cache()->ComputeKeyedStoreSpecialized(
*receiver, strict_mode);
stub = probe->IsFailure() ?
NULL : Code::cast(probe->ToObjectUnchecked());
}
Code* stub = (strict_mode == kStrictMode)
? generic_stub_strict()
: generic_stub();
if (!force_generic) {
if (object->IsJSObject() && key->IsSmi()) {
JSObject* receiver = JSObject::cast(*object);
MaybeObject* maybe_stub = ComputeStub(receiver,
true,
strict_mode,
stub);
stub = maybe_stub->IsFailure() ?
NULL : Code::cast(maybe_stub->ToObjectUnchecked());
}
}
if (stub != NULL) set_target(stub);
}
#ifdef DEBUG
TraceIC("KeyedStoreIC", key, state, target());
#endif
// Set the property.
return Runtime::SetObjectProperty(
isolate(), object , key, value, NONE, strict_mode);
@ -1721,7 +2025,16 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
ASSERT(args.length() == 2);
KeyedLoadIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
return ic.Load(state, args.at<Object>(0), args.at<Object>(1), false);
}
RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
NoHandleAllocation na;
ASSERT(args.length() == 2);
KeyedLoadIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true);
}
@ -1805,7 +2118,42 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
args.at<Object>(0),
args.at<Object>(1),
args.at<Object>(2));
args.at<Object>(2),
false);
}
RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) {
NoHandleAllocation na;
ASSERT(args.length() == 3);
KeyedStoreIC ic(isolate);
Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
Handle<Object> object = args.at<Object>(0);
Handle<Object> key = args.at<Object>(1);
Handle<Object> value = args.at<Object>(2);
StrictModeFlag strict_mode =
static_cast<StrictModeFlag>(extra_ic_state & kStrictMode);
return Runtime::SetObjectProperty(isolate,
object,
key,
value,
NONE,
strict_mode);
}
RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
NoHandleAllocation na;
ASSERT(args.length() == 3);
KeyedStoreIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
return ic.Store(state,
static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
args.at<Object>(0),
args.at<Object>(1),
args.at<Object>(2),
true);
}

130
src/ic.h
View File

@ -1,4 +1,4 @@
// Copyright 2006-2009 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -39,12 +39,15 @@ namespace internal {
#define IC_UTIL_LIST(ICU) \
ICU(LoadIC_Miss) \
ICU(KeyedLoadIC_Miss) \
ICU(KeyedLoadIC_MissForceGeneric) \
ICU(CallIC_Miss) \
ICU(KeyedCallIC_Miss) \
ICU(StoreIC_Miss) \
ICU(StoreIC_ArrayLength) \
ICU(SharedStoreIC_ExtendStorage) \
ICU(KeyedStoreIC_Miss) \
ICU(KeyedStoreIC_MissForceGeneric) \
ICU(KeyedStoreIC_Slow) \
/* Utilities for IC stubs. */ \
ICU(LoadCallbackProperty) \
ICU(StoreCallbackProperty) \
@ -142,7 +145,7 @@ class IC {
void set_target(Code* code) { SetTargetAtAddress(address(), code); }
#ifdef DEBUG
static void TraceIC(const char* type,
void TraceIC(const char* type,
Handle<Object> name,
State old_state,
Code* new_target,
@ -325,23 +328,72 @@ class LoadIC: public IC {
};
class KeyedLoadIC: public IC {
class KeyedIC: public IC {
public:
explicit KeyedLoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
ASSERT(target()->is_keyed_load_stub() ||
target()->is_external_array_load_stub());
explicit KeyedIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {}
virtual ~KeyedIC() {}
static const int kMaxKeyedPolymorphism = 4;
virtual MaybeObject* GetFastElementStubWithoutMapCheck(
bool is_js_array) = 0;
virtual MaybeObject* GetExternalArrayStubWithoutMapCheck(
ExternalArrayType array_type) = 0;
protected:
virtual Code* string_stub() {
return NULL;
}
virtual Code::Kind kind() const = 0;
virtual String* GetStubNameForCache(IC::State ic_state) = 0;
MaybeObject* ComputeStub(JSObject* receiver,
bool is_store,
StrictModeFlag strict_mode,
Code* default_stub);
virtual MaybeObject* ConstructMegamorphicStub(
MapList* receiver_maps,
CodeList* targets,
StrictModeFlag strict_mode) = 0;
private:
void GetReceiverMapsForStub(Code* stub, MapList* result);
MaybeObject* ComputeMonomorphicStubWithoutMapCheck(
Map* receiver_map,
StrictModeFlag strict_mode,
Code* generic_stub);
MaybeObject* ComputeMonomorphicStub(JSObject* receiver,
bool is_store,
StrictModeFlag strict_mode,
Code* default_stub);
};
class KeyedLoadIC: public KeyedIC {
public:
explicit KeyedLoadIC(Isolate* isolate) : KeyedIC(isolate) {
ASSERT(target()->is_keyed_load_stub());
}
MUST_USE_RESULT MaybeObject* Load(State state,
Handle<Object> object,
Handle<Object> key);
Handle<Object> key,
bool force_generic_stub);
// Code generator routines.
static void GenerateMiss(MacroAssembler* masm);
static void GenerateMiss(MacroAssembler* masm, bool force_generic);
static void GenerateRuntimeGetProperty(MacroAssembler* masm);
static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
static void GenerateInitialize(MacroAssembler* masm) {
GenerateMiss(masm, false);
}
static void GeneratePreMonomorphic(MacroAssembler* masm) {
GenerateMiss(masm);
GenerateMiss(masm, false);
}
static void GenerateGeneric(MacroAssembler* masm);
static void GenerateString(MacroAssembler* masm);
@ -355,6 +407,27 @@ class KeyedLoadIC: public IC {
static const int kSlowCaseBitFieldMask =
(1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
virtual MaybeObject* GetFastElementStubWithoutMapCheck(
bool is_js_array);
virtual MaybeObject* GetExternalArrayStubWithoutMapCheck(
ExternalArrayType array_type);
protected:
virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
virtual String* GetStubNameForCache(IC::State ic_state);
virtual MaybeObject* ConstructMegamorphicStub(
MapList* receiver_maps,
CodeList* targets,
StrictModeFlag strict_mode);
virtual Code* string_stub() {
return isolate()->builtins()->builtin(
Builtins::kKeyedLoadIC_String);
}
private:
// Update the inline cache.
void UpdateCaches(LookupResult* lookup,
@ -379,11 +452,6 @@ class KeyedLoadIC: public IC {
return isolate()->builtins()->builtin(
Builtins::kKeyedLoadIC_PreMonomorphic);
}
Code* string_stub() {
return isolate()->builtins()->builtin(
Builtins::kKeyedLoadIC_String);
}
Code* indexed_interceptor_stub() {
return isolate()->builtins()->builtin(
Builtins::kKeyedLoadIC_IndexedInterceptor);
@ -466,23 +534,45 @@ class StoreIC: public IC {
};
class KeyedStoreIC: public IC {
class KeyedStoreIC: public KeyedIC {
public:
explicit KeyedStoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
explicit KeyedStoreIC(Isolate* isolate) : KeyedIC(isolate) {
ASSERT(target()->is_keyed_store_stub());
}
MUST_USE_RESULT MaybeObject* Store(State state,
StrictModeFlag strict_mode,
Handle<Object> object,
Handle<Object> name,
Handle<Object> value);
Handle<Object> value,
bool force_generic);
// Code generators for stub routines. Only called once at startup.
static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
static void GenerateMiss(MacroAssembler* masm);
static void GenerateInitialize(MacroAssembler* masm) {
GenerateMiss(masm, false);
}
static void GenerateMiss(MacroAssembler* masm, bool force_generic);
static void GenerateSlow(MacroAssembler* masm);
static void GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictModeFlag strict_mode);
static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode);
virtual MaybeObject* GetFastElementStubWithoutMapCheck(
bool is_js_array);
virtual MaybeObject* GetExternalArrayStubWithoutMapCheck(
ExternalArrayType array_type);
protected:
virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
virtual String* GetStubNameForCache(IC::State ic_state);
virtual MaybeObject* ConstructMegamorphicStub(
MapList* receiver_maps,
CodeList* targets,
StrictModeFlag strict_mode);
private:
// Update the inline cache.
void UpdateCaches(LookupResult* lookup,

View File

@ -164,6 +164,11 @@ class List {
DISALLOW_COPY_AND_ASSIGN(List);
};
class Map;
class Code;
typedef List<Map*> MapList;
typedef List<Code*> CodeList;
} } // namespace v8::internal
#endif // V8_LIST_H_

View File

@ -1,4 +1,4 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -1620,10 +1620,6 @@ void Logger::LogCodeObject(Object* object) {
description = "A keyed load IC from the snapshot";
tag = Logger::KEYED_LOAD_IC_TAG;
break;
case Code::KEYED_EXTERNAL_ARRAY_LOAD_IC:
description = "A keyed external array load IC from the snapshot";
tag = Logger::KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG;
break;
case Code::LOAD_IC:
description = "A load IC from the snapshot";
tag = Logger::LOAD_IC_TAG;
@ -1636,10 +1632,6 @@ void Logger::LogCodeObject(Object* object) {
description = "A keyed store IC from the snapshot";
tag = Logger::KEYED_STORE_IC_TAG;
break;
case Code::KEYED_EXTERNAL_ARRAY_STORE_IC:
description = "A keyed external array store IC from the snapshot";
tag = Logger::KEYED_EXTERNAL_ARRAY_STORE_IC_TAG;
break;
case Code::CALL_IC:
description = "A call IC from the snapshot";
tag = Logger::CALL_IC_TAG;

View File

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -122,8 +122,10 @@ class Ticker;
V(EVAL_TAG, "Eval") \
V(FUNCTION_TAG, "Function") \
V(KEYED_LOAD_IC_TAG, "KeyedLoadIC") \
V(KEYED_LOAD_MEGAMORPHIC_IC_TAG, "KeyedLoadMegamorphicIC") \
V(KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG, "KeyedExternalArrayLoadIC") \
V(KEYED_STORE_IC_TAG, "KeyedStoreIC") \
V(KEYED_STORE_MEGAMORPHIC_IC_TAG, "KeyedStoreMegamorphicIC") \
V(KEYED_EXTERNAL_ARRAY_STORE_IC_TAG, "KeyedExternalArrayStoreIC") \
V(LAZY_COMPILE_TAG, "LazyCompile") \
V(LOAD_IC_TAG, "LoadIC") \

View File

@ -457,7 +457,7 @@ class StaticMarkingVisitor : public StaticVisitorBase {
static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
Code* code = Code::GetCodeFromTargetAddress(rinfo->target_address());
if (FLAG_cleanup_ics_at_gc && code->is_inline_cache_stub()) {
if (FLAG_cleanup_code_caches_at_gc && code->is_inline_cache_stub()) {
IC::Clear(rinfo->pc());
// Please note targets for cleared inline cached do not have to be
// marked since they are contained in HEAP->non_monomorphic_cache().
@ -1056,7 +1056,7 @@ void MarkCompactCollector::MarkUnmarkedObject(HeapObject* object) {
ASSERT(HEAP->Contains(object));
if (object->IsMap()) {
Map* map = Map::cast(object);
if (FLAG_cleanup_caches_in_maps_at_gc) {
if (FLAG_cleanup_code_caches_at_gc) {
map->ClearCodeCache(heap());
}
SetMark(map);

View File

@ -6613,4 +6613,3 @@ void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_MIPS

View File

@ -2595,7 +2595,6 @@ Code::ExtraICState Code::extra_ic_state() {
PropertyType Code::type() {
ASSERT(ic_state() == MONOMORPHIC);
return ExtractTypeFromFlags(flags());
}
@ -2713,14 +2712,14 @@ void Code::set_check_type(CheckType value) {
ExternalArrayType Code::external_array_type() {
ASSERT(is_external_array_load_stub() || is_external_array_store_stub());
ASSERT(is_keyed_load_stub() || is_keyed_store_stub());
byte type = READ_BYTE_FIELD(this, kExternalArrayTypeOffset);
return static_cast<ExternalArrayType>(type);
}
void Code::set_external_array_type(ExternalArrayType value) {
ASSERT(is_external_array_load_stub() || is_external_array_store_stub());
ASSERT(is_keyed_load_stub() || is_keyed_store_stub());
WRITE_BYTE_FIELD(this, kExternalArrayTypeOffset, value);
}
@ -2792,8 +2791,7 @@ Code::Flags Code::ComputeFlags(Kind kind,
(kind == CALL_IC && (ic_state == MONOMORPHIC ||
ic_state == MONOMORPHIC_PROTOTYPE_FAILURE)) ||
(kind == STORE_IC) ||
(kind == KEYED_STORE_IC) ||
(kind == KEYED_EXTERNAL_ARRAY_STORE_IC));
(kind == KEYED_STORE_IC));
// Compute the bit mask.
int bits = kind << kFlagsKindShift;
if (in_loop) bits |= kFlagsICInLoopMask;

View File

@ -3811,8 +3811,6 @@ void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
MaybeObject* CodeCache::Update(String* name, Code* code) {
ASSERT(code->ic_state() == MONOMORPHIC);
// The number of monomorphic stubs for normal load/store/call IC's can grow to
// a large number and therefore they need to go into a hash table. They are
// used to load global properties from cells.
@ -6555,10 +6553,8 @@ const char* Code::Kind2String(Kind kind) {
case BUILTIN: return "BUILTIN";
case LOAD_IC: return "LOAD_IC";
case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
case KEYED_EXTERNAL_ARRAY_LOAD_IC: return "KEYED_EXTERNAL_ARRAY_LOAD_IC";
case STORE_IC: return "STORE_IC";
case KEYED_STORE_IC: return "KEYED_STORE_IC";
case KEYED_EXTERNAL_ARRAY_STORE_IC: return "KEYED_EXTERNAL_ARRAY_STORE_IC";
case CALL_IC: return "CALL_IC";
case KEYED_CALL_IC: return "KEYED_CALL_IC";
case TYPE_RECORDING_UNARY_OP_IC: return "TYPE_RECORDING_UNARY_OP_IC";

View File

@ -30,6 +30,7 @@
#include "allocation.h"
#include "builtins.h"
#include "list.h"
#include "smart-pointer.h"
#include "unicode-inl.h"
#if V8_TARGET_ARCH_ARM
@ -3275,12 +3276,10 @@ class Code: public HeapObject {
BUILTIN,
LOAD_IC,
KEYED_LOAD_IC,
KEYED_EXTERNAL_ARRAY_LOAD_IC,
CALL_IC,
KEYED_CALL_IC,
STORE_IC,
KEYED_STORE_IC,
KEYED_EXTERNAL_ARRAY_STORE_IC,
TYPE_RECORDING_UNARY_OP_IC,
TYPE_RECORDING_BINARY_OP_IC,
COMPARE_IC,
@ -3363,12 +3362,6 @@ class Code: public HeapObject {
return kind() == TYPE_RECORDING_BINARY_OP_IC;
}
inline bool is_compare_ic_stub() { return kind() == COMPARE_IC; }
inline bool is_external_array_load_stub() {
return kind() == KEYED_EXTERNAL_ARRAY_LOAD_IC;
}
inline bool is_external_array_store_stub() {
return kind() == KEYED_EXTERNAL_ARRAY_STORE_IC;
}
// [major_key]: For kind STUB or BINARY_OP_IC, the major key.
inline int major_key();

View File

@ -1,4 +1,4 @@
// Copyright 2006-2010 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -1564,10 +1564,8 @@ static void ReportCodeKindStatistics() {
CASE(BUILTIN);
CASE(LOAD_IC);
CASE(KEYED_LOAD_IC);
CASE(KEYED_EXTERNAL_ARRAY_LOAD_IC);
CASE(STORE_IC);
CASE(KEYED_STORE_IC);
CASE(KEYED_EXTERNAL_ARRAY_STORE_IC);
CASE(CALL_IC);
CASE(KEYED_CALL_IC);
CASE(TYPE_RECORDING_UNARY_OP_IC);

View File

@ -1,4 +1,4 @@
// Copyright 2006-2009 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -457,34 +457,6 @@ MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype(
}
MaybeObject* StubCache::ComputeKeyedLoadSpecialized(JSObject* receiver) {
// Using NORMAL as the PropertyType for array element loads is a misuse. The
// generated stub always accesses fast elements, not slow-mode fields, but
// some property type is required for the stub lookup. Note that overloading
// the NORMAL PropertyType is only safe as long as no stubs are generated for
// other keyed field loads. This is guaranteed to be the case since all field
// keyed loads that are not array elements go through a generic builtin stub.
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
String* name = heap()->KeyedLoadSpecialized_symbol();
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
KeyedLoadStubCompiler compiler;
{ MaybeObject* maybe_code = compiler.CompileLoadSpecialized(receiver);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
PROFILE(isolate_,
CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
Object* result;
{ MaybeObject* maybe_result =
receiver->UpdateMapCodeCache(name, Code::cast(code));
if (!maybe_result->ToObject(&result)) return maybe_result;
}
}
return code;
}
MaybeObject* StubCache::ComputeStoreField(String* name,
JSObject* receiver,
int field_index,
@ -513,30 +485,6 @@ MaybeObject* StubCache::ComputeStoreField(String* name,
}
MaybeObject* StubCache::ComputeKeyedStoreSpecialized(
JSObject* receiver,
StrictModeFlag strict_mode) {
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode);
String* name = heap()->KeyedStoreSpecialized_symbol();
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
KeyedStoreStubCompiler compiler(strict_mode);
{ MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
PROFILE(isolate_,
CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
Object* result;
{ MaybeObject* maybe_result =
receiver->UpdateMapCodeCache(name, Code::cast(code));
if (!maybe_result->ToObject(&result)) return maybe_result;
}
}
return code;
}
namespace {
ExternalArrayType ElementsKindToExternalArrayType(JSObject::ElementsKind kind) {
@ -565,60 +513,6 @@ ExternalArrayType ElementsKindToExternalArrayType(JSObject::ElementsKind kind) {
}
}
String* ExternalArrayTypeToStubName(Heap* heap,
ExternalArrayType array_type,
bool is_store) {
if (is_store) {
switch (array_type) {
case kExternalByteArray:
return heap->KeyedStoreExternalByteArray_symbol();
case kExternalUnsignedByteArray:
return heap->KeyedStoreExternalUnsignedByteArray_symbol();
case kExternalShortArray:
return heap->KeyedStoreExternalShortArray_symbol();
case kExternalUnsignedShortArray:
return heap->KeyedStoreExternalUnsignedShortArray_symbol();
case kExternalIntArray:
return heap->KeyedStoreExternalIntArray_symbol();
case kExternalUnsignedIntArray:
return heap->KeyedStoreExternalUnsignedIntArray_symbol();
case kExternalFloatArray:
return heap->KeyedStoreExternalFloatArray_symbol();
case kExternalDoubleArray:
return heap->KeyedStoreExternalDoubleArray_symbol();
case kExternalPixelArray:
return heap->KeyedStoreExternalPixelArray_symbol();
default:
UNREACHABLE();
return NULL;
}
} else {
switch (array_type) {
case kExternalByteArray:
return heap->KeyedLoadExternalByteArray_symbol();
case kExternalUnsignedByteArray:
return heap->KeyedLoadExternalUnsignedByteArray_symbol();
case kExternalShortArray:
return heap->KeyedLoadExternalShortArray_symbol();
case kExternalUnsignedShortArray:
return heap->KeyedLoadExternalUnsignedShortArray_symbol();
case kExternalIntArray:
return heap->KeyedLoadExternalIntArray_symbol();
case kExternalUnsignedIntArray:
return heap->KeyedLoadExternalUnsignedIntArray_symbol();
case kExternalFloatArray:
return heap->KeyedLoadExternalFloatArray_symbol();
case kExternalDoubleArray:
return heap->KeyedLoadExternalDoubleArray_symbol();
case kExternalPixelArray:
return heap->KeyedLoadExternalPixelArray_symbol();
default:
UNREACHABLE();
return NULL;
}
}
}
} // anonymous namespace
@ -628,23 +522,29 @@ MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
StrictModeFlag strict_mode) {
Code::Flags flags =
Code::ComputeMonomorphicFlags(
is_store ? Code::KEYED_EXTERNAL_ARRAY_STORE_IC :
Code::KEYED_EXTERNAL_ARRAY_LOAD_IC,
is_store ? Code::KEYED_STORE_IC :
Code::KEYED_LOAD_IC,
NORMAL,
strict_mode);
ExternalArrayType array_type =
ElementsKindToExternalArrayType(receiver->GetElementsKind());
String* name = ExternalArrayTypeToStubName(heap(), array_type, is_store);
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
ExternalArrayStubCompiler compiler;
{ MaybeObject* maybe_code =
is_store ?
compiler.CompileKeyedStoreStub(receiver, array_type, flags) :
compiler.CompileKeyedLoadStub(receiver, array_type, flags);
if (!maybe_code->ToObject(&code)) return maybe_code;
String* name = is_store
? isolate()->heap()->KeyedStoreSpecializedMonomorphic_symbol()
: isolate()->heap()->KeyedLoadSpecializedMonomorphic_symbol();
Object* maybe_code = receiver->map()->FindInCodeCache(name, flags);
if (!maybe_code->IsUndefined()) return Code::cast(maybe_code);
MaybeObject* maybe_new_code = NULL;
if (is_store) {
ExternalArrayStoreStubCompiler compiler;
maybe_new_code = compiler.CompileStore(receiver, array_type);
} else {
ExternalArrayLoadStubCompiler compiler;
maybe_new_code = compiler.CompileLoad(receiver, array_type);
}
Code::cast(code)->set_external_array_type(array_type);
Code* code;
if (!maybe_new_code->To(&code)) return maybe_new_code;
code->set_external_array_type(array_type);
if (is_store) {
PROFILE(isolate_,
CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_STORE_IC_TAG,
@ -654,11 +554,56 @@ MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG,
Code::cast(code), 0));
}
ASSERT(code->IsCode());
Object* result;
{ MaybeObject* maybe_result =
receiver->UpdateMapCodeCache(name, Code::cast(code));
if (!maybe_result->ToObject(&result)) return maybe_result;
}
return code;
}
MaybeObject* StubCache::ComputeKeyedLoadOrStoreFastElement(
JSObject* receiver,
bool is_store,
StrictModeFlag strict_mode) {
Code::Flags flags =
Code::ComputeMonomorphicFlags(
is_store ? Code::KEYED_STORE_IC :
Code::KEYED_LOAD_IC,
NORMAL,
strict_mode);
String* name = is_store
? isolate()->heap()->KeyedStoreSpecializedMonomorphic_symbol()
: isolate()->heap()->KeyedLoadSpecializedMonomorphic_symbol();
Object* maybe_code = receiver->map()->FindInCodeCache(name, flags);
if (!maybe_code->IsUndefined()) return Code::cast(maybe_code);
MaybeObject* maybe_new_code = NULL;
if (is_store) {
KeyedStoreStubCompiler compiler(strict_mode);
maybe_new_code = compiler.CompileStoreFastElement(receiver->map());
} else {
KeyedLoadStubCompiler compiler;
maybe_new_code = compiler.CompileLoadFastElement(receiver->map());
}
Code* code;
if (!maybe_new_code->To(&code)) return maybe_new_code;
if (is_store) {
PROFILE(isolate_,
CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
Code::cast(code), 0));
} else {
PROFILE(isolate_,
CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
Code::cast(code), 0));
}
ASSERT(code->IsCode());
Object* result;
{ MaybeObject* maybe_result =
receiver->UpdateMapCodeCache(name, Code::cast(code));
if (!maybe_result->ToObject(&result)) return maybe_result;
}
return code;
}
@ -1717,8 +1662,11 @@ MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
}
MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type,
String* name,
InlineCacheState state) {
Code::Flags flags = Code::ComputeFlags(
Code::KEYED_LOAD_IC, NOT_IN_LOOP, state, Code::kNoExtraICState, type);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
@ -1750,9 +1698,11 @@ MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
}
MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::KEYED_STORE_IC, type, strict_mode_);
MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type,
String* name,
InlineCacheState state) {
Code::Flags flags = Code::ComputeFlags(
Code::KEYED_STORE_IC, NOT_IN_LOOP, state, strict_mode_, type);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
@ -1930,15 +1880,34 @@ void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
}
MaybeObject* ExternalArrayStubCompiler::GetCode(Code::Flags flags) {
MaybeObject* ExternalArrayLoadStubCompiler::GetCode() {
Object* result;
{ MaybeObject* maybe_result = GetCodeWithFlags(flags, "ExternalArrayStub");
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC,
NORMAL);
{ MaybeObject* maybe_result = GetCodeWithFlags(flags,
"ExternalArrayLoadStub");
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Code* code = Code::cast(result);
USE(code);
PROFILE(isolate(),
CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStub"));
CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayLoadStub"));
return result;
}
MaybeObject* ExternalArrayStoreStubCompiler::GetCode() {
Object* result;
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC,
NORMAL);
{ MaybeObject* maybe_result = GetCodeWithFlags(flags,
"ExternalArrayStoreStub");
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Code* code = Code::cast(result);
USE(code);
PROFILE(isolate(),
CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStoreStub"));
return result;
}

View File

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -31,6 +31,7 @@
#include "allocation.h"
#include "arguments.h"
#include "macro-assembler.h"
#include "objects.h"
#include "zone-inl.h"
namespace v8 {
@ -144,9 +145,6 @@ class StubCache {
String* name,
JSFunction* receiver);
MUST_USE_RESULT MaybeObject* ComputeKeyedLoadSpecialized(
JSObject* receiver);
// ---
MUST_USE_RESULT MaybeObject* ComputeStoreField(
@ -185,16 +183,15 @@ class StubCache {
Map* transition,
StrictModeFlag strict_mode);
MUST_USE_RESULT MaybeObject* ComputeKeyedStoreSpecialized(
JSObject* receiver,
StrictModeFlag strict_mode);
MUST_USE_RESULT MaybeObject* ComputeKeyedLoadOrStoreExternalArray(
JSObject* receiver,
bool is_store,
StrictModeFlag strict_mode);
MUST_USE_RESULT MaybeObject* ComputeKeyedLoadOrStoreFastElement(
JSObject* receiver,
bool is_store,
StrictModeFlag strict_mode);
// ---
MUST_USE_RESULT MaybeObject* ComputeCallField(int argc,
@ -469,7 +466,10 @@ class StubCompiler BASE_EMBEDDED {
Register scratch,
Label* miss_label);
static void GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind);
static void GenerateLoadMiss(MacroAssembler* masm,
Code::Kind kind);
static void GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm);
// Generates code that verifies that the property holder has not changed
// (checking maps of objects in the prototype chain for fast and global
@ -634,10 +634,21 @@ class KeyedLoadStubCompiler: public StubCompiler {
MUST_USE_RESULT MaybeObject* CompileLoadStringLength(String* name);
MUST_USE_RESULT MaybeObject* CompileLoadFunctionPrototype(String* name);
MUST_USE_RESULT MaybeObject* CompileLoadSpecialized(JSObject* receiver);
MUST_USE_RESULT MaybeObject* CompileLoadFastElement(Map* receiver_map);
MUST_USE_RESULT MaybeObject* CompileLoadMegamorphic(
MapList* receiver_maps,
CodeList* handler_ics);
static void GenerateLoadExternalArray(MacroAssembler* masm,
ExternalArrayType array_type);
static void GenerateLoadFastElement(MacroAssembler* masm);
private:
MaybeObject* GetCode(PropertyType type, String* name);
MaybeObject* GetCode(PropertyType type,
String* name,
InlineCacheState state = MONOMORPHIC);
};
@ -678,10 +689,22 @@ class KeyedStoreStubCompiler: public StubCompiler {
Map* transition,
String* name);
MUST_USE_RESULT MaybeObject* CompileStoreSpecialized(JSObject* receiver);
MUST_USE_RESULT MaybeObject* CompileStoreFastElement(Map* receiver_map);
MUST_USE_RESULT MaybeObject* CompileStoreMegamorphic(
MapList* receiver_maps,
CodeList* handler_ics);
static void GenerateStoreFastElement(MacroAssembler* masm,
bool is_js_array);
static void GenerateStoreExternalArray(MacroAssembler* masm,
ExternalArrayType array_type);
private:
MaybeObject* GetCode(PropertyType type, String* name);
MaybeObject* GetCode(PropertyType type,
String* name,
InlineCacheState state = MONOMORPHIC);
StrictModeFlag strict_mode_;
};
@ -848,20 +871,30 @@ class CallOptimization BASE_EMBEDDED {
CallHandlerInfo* api_call_info_;
};
class ExternalArrayStubCompiler: public StubCompiler {
class ExternalArrayLoadStubCompiler: public StubCompiler {
public:
explicit ExternalArrayStubCompiler() {}
explicit ExternalArrayLoadStubCompiler() {}
MUST_USE_RESULT MaybeObject* CompileKeyedLoadStub(
JSObject* receiver, ExternalArrayType array_type, Code::Flags flags);
MUST_USE_RESULT MaybeObject* CompileKeyedStoreStub(
JSObject* receiver, ExternalArrayType array_type, Code::Flags flags);
MUST_USE_RESULT MaybeObject* CompileLoad(
JSObject* receiver, ExternalArrayType array_type);
private:
MaybeObject* GetCode(Code::Flags flags);
MaybeObject* GetCode();
};
class ExternalArrayStoreStubCompiler: public StubCompiler {
public:
explicit ExternalArrayStoreStubCompiler() {}
MUST_USE_RESULT MaybeObject* CompileStore(
JSObject* receiver, ExternalArrayType array_type);
private:
MaybeObject* GetCode();
};
} } // namespace v8::internal
#endif // V8_STUB_CACHE_H_

View File

@ -82,7 +82,8 @@ bool TypeFeedbackOracle::LoadIsMonomorphic(Property* expr) {
if (map_or_code->IsMap()) return true;
if (map_or_code->IsCode()) {
Handle<Code> code(Code::cast(*map_or_code));
return code->kind() == Code::KEYED_EXTERNAL_ARRAY_LOAD_IC &&
return code->is_keyed_load_stub() &&
code->ic_state() == MONOMORPHIC &&
code->FindFirstMap() != NULL;
}
return false;
@ -94,8 +95,8 @@ bool TypeFeedbackOracle::StoreIsMonomorphic(Expression* expr) {
if (map_or_code->IsMap()) return true;
if (map_or_code->IsCode()) {
Handle<Code> code(Code::cast(*map_or_code));
return code->kind() == Code::KEYED_EXTERNAL_ARRAY_STORE_IC &&
code->FindFirstMap() != NULL;
return code->is_keyed_store_stub() &&
code->ic_state() == MONOMORPHIC;
}
return false;
}
@ -113,7 +114,9 @@ Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) {
Handle<HeapObject>::cast(GetInfo(expr->id())));
if (map_or_code->IsCode()) {
Handle<Code> code(Code::cast(*map_or_code));
return Handle<Map>(code->FindFirstMap());
Map* first_map = code->FindFirstMap();
ASSERT(first_map != NULL);
return Handle<Map>(first_map);
}
return Handle<Map>(Map::cast(*map_or_code));
}
@ -445,8 +448,8 @@ void TypeFeedbackOracle::PopulateMap(Handle<Code> code) {
kind == Code::COMPARE_IC) {
SetInfo(id, target);
} else if (state == MONOMORPHIC) {
if (kind == Code::KEYED_EXTERNAL_ARRAY_LOAD_IC ||
kind == Code::KEYED_EXTERNAL_ARRAY_STORE_IC) {
if (kind == Code::KEYED_LOAD_IC ||
kind == Code::KEYED_STORE_IC) {
SetInfo(id, target);
} else if (kind != Code::CALL_IC ||
target->check_type() == RECEIVER_MAP_CHECK) {

View File

@ -1,4 +1,4 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -134,6 +134,7 @@ namespace internal {
SC(keyed_load_generic_symbol, V8.KeyedLoadGenericSymbol) \
SC(keyed_load_generic_lookup_cache, V8.KeyedLoadGenericLookupCache) \
SC(keyed_load_generic_slow, V8.KeyedLoadGenericSlow) \
SC(keyed_load_polymorphic_stubs, V8.KeyedLoadPolymorphicStubs) \
SC(keyed_load_external_array_slow, V8.KeyedLoadExternalArraySlow) \
/* How is the generic keyed-call stub used? */ \
SC(keyed_call_generic_smi_fast, V8.KeyedCallGenericSmiFast) \
@ -179,6 +180,8 @@ namespace internal {
SC(keyed_store_inline_miss, V8.KeyedStoreInlineMiss) \
SC(named_store_global_inline, V8.NamedStoreGlobalInline) \
SC(named_store_global_inline_miss, V8.NamedStoreGlobalInlineMiss) \
SC(keyed_store_polymorphic_stubs, V8.KeyedStorePolymorphicStubs) \
SC(keyed_store_external_array_slow, V8.KeyedStoreExternalArraySlow) \
SC(store_normal_miss, V8.StoreNormalMiss) \
SC(store_normal_hit, V8.StoreNormalHit) \
SC(cow_arrays_created_stub, V8.COWArraysCreatedStub) \

View File

@ -658,7 +658,7 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
char_at_generator.GenerateSlow(masm, call_helper);
__ bind(&miss);
GenerateMiss(masm);
GenerateMiss(masm, false);
}
@ -701,7 +701,7 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1);
__ bind(&slow);
GenerateMiss(masm);
GenerateMiss(masm, false);
}
@ -1240,7 +1240,7 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
}
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
@ -1256,8 +1256,10 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
__ push(rbx); // return address
// Perform tail call to the entry.
ExternalReference ref
= ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
ExternalReference ref = force_generic
? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
masm->isolate())
: ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
}
@ -1441,7 +1443,28 @@ void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
}
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
__ pop(rbx);
__ push(rdx); // receiver
__ push(rcx); // key
__ push(rax); // value
__ Push(Smi::FromInt(NONE)); // PropertyAttributes
__ push(rbx); // return address
// Do tail-call to runtime routine.
ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
__ TailCallExternalReference(ref, 4, 1);
}
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
@ -1456,8 +1479,10 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
__ push(rbx); // return address
// Do tail-call to runtime routine.
ExternalReference ref =
ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
ExternalReference ref = force_generic
? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
masm->isolate())
: ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}

View File

@ -2601,6 +2601,21 @@ void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg,
}
void MacroAssembler::DispatchMap(Register obj,
Handle<Map> map,
Handle<Code> success,
SmiCheckType smi_check_type) {
Label fail;
if (smi_check_type == DO_SMI_CHECK) {
JumpIfSmi(obj, &fail);
}
Cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
j(equal, success, RelocInfo::CODE_TARGET);
bind(&fail);
}
void MacroAssembler::AbortIfNotNumber(Register object) {
Label ok;
Condition is_smi = CheckSmi(object);

View File

@ -45,6 +45,7 @@ enum AllocationFlags {
RESULT_CONTAINS_TOP = 1 << 1
};
// Default scratch register used by MacroAssembler (and other code that needs
// a spare register). The register isn't callee save, and not used by the
// function calling convention.
@ -752,6 +753,14 @@ class MacroAssembler: public Assembler {
Label* fail,
SmiCheckType smi_check_type);
// Check if the map of an object is equal to a specified map and branch to a
// specified target if equal. Skip the smi check if not required (object is
// known to be a heap object)
void DispatchMap(Register obj,
Handle<Map> map,
Handle<Code> success,
SmiCheckType smi_check_type);
// Check if the object in register heap_object is a string. Afterwards the
// register map contains the object map and the register instance_type
// contains the instance_type. The registers map and instance_type can be the

View File

@ -703,6 +703,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);
__ 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,
@ -2484,8 +2492,35 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
}
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
// -----------------------------------
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);
Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode(NORMAL, NULL);
}
MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
MapList* receiver_maps,
CodeList* handler_ics) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
@ -2493,51 +2528,26 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
// -- rsp[0] : return address
// -----------------------------------
Label miss;
// Check that the receiver isn't a smi.
__ JumpIfSmi(rdx, &miss);
// Check that the map matches.
__ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
Handle<Map>(receiver->map()));
__ j(not_equal, &miss);
// 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);
// 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);
// 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);
}
@ -2551,7 +2561,7 @@ MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
// -----------------------------------
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
@ -2942,49 +2952,56 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
}
MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
MaybeObject* KeyedLoadStubCompiler::CompileLoadFastElement(Map* receiver_map) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
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);
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode(NORMAL, NULL);
}
MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
MapList* receiver_maps,
CodeList* handler_ics) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
Label miss;
// Check that the receiver isn't a smi.
__ JumpIfSmi(rdx, &miss);
// Check that the map matches.
__ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
Handle<Map>(receiver->map()));
__ j(not_equal, &miss);
// Check that the key is a smi.
__ JumpIfNotSmi(rax, &miss);
// 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);
// 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);
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);
}
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
return GetCode(NORMAL, NULL);
return GetCode(NORMAL, NULL, MEGAMORPHIC);
}
@ -3121,30 +3138,79 @@ 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 -------------
// -- 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);
// Check that the map matches.
__ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, DO_SMI_CHECK);
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ JumpIfNotSmi(rax, &miss_force_generic);
// Check that the index is in range.
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ 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)
@ -3231,7 +3297,7 @@ 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 -------------
@ -3240,44 +3306,46 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
// -- 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);
// Check that the map matches.
__ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, DO_SMI_CHECK);
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
// 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, &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.
@ -3411,21 +3479,116 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
// -- 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. 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);
// 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