MIPS: Handle single element array growth + transition in generic KeyedStoreIC
Port r10583 (505679e). BUG= TEST= Review URL: https://chromiumcodereview.appspot.com/9316061 Patch from Daniel Kalmar <kalmard@homejinni.com>. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10645 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
3c6459285c
commit
7639836eca
@ -116,7 +116,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
|
|||||||
Label* gc_required) {
|
Label* gc_required) {
|
||||||
const int initial_capacity = JSArray::kPreallocatedArrayElements;
|
const int initial_capacity = JSArray::kPreallocatedArrayElements;
|
||||||
STATIC_ASSERT(initial_capacity >= 0);
|
STATIC_ASSERT(initial_capacity >= 0);
|
||||||
__ LoadGlobalInitialConstructedArrayMap(array_function, scratch2, scratch1);
|
__ LoadInitialArrayMap(array_function, scratch2, scratch1);
|
||||||
|
|
||||||
// Allocate the JSArray object together with space for a fixed array with the
|
// Allocate the JSArray object together with space for a fixed array with the
|
||||||
// requested elements.
|
// requested elements.
|
||||||
@ -212,8 +212,7 @@ static void AllocateJSArray(MacroAssembler* masm,
|
|||||||
bool fill_with_hole,
|
bool fill_with_hole,
|
||||||
Label* gc_required) {
|
Label* gc_required) {
|
||||||
// Load the initial map from the array function.
|
// Load the initial map from the array function.
|
||||||
__ LoadGlobalInitialConstructedArrayMap(array_function, scratch2,
|
__ LoadInitialArrayMap(array_function, scratch2, elements_array_storage);
|
||||||
elements_array_storage);
|
|
||||||
|
|
||||||
if (FLAG_debug_code) { // Assert that array size is not zero.
|
if (FLAG_debug_code) { // Assert that array size is not zero.
|
||||||
__ Assert(
|
__ Assert(
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011 the V8 project authors. All rights reserved.
|
// Copyright 2012 the V8 project authors. All rights reserved.
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
// modification, are permitted provided that the following conditions are
|
// modification, are permitted provided that the following conditions are
|
||||||
// met:
|
// met:
|
||||||
@ -1198,14 +1198,16 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
|
|||||||
Label slow, array, extra, check_if_double_array;
|
Label slow, array, extra, check_if_double_array;
|
||||||
Label fast_object_with_map_check, fast_object_without_map_check;
|
Label fast_object_with_map_check, fast_object_without_map_check;
|
||||||
Label fast_double_with_map_check, fast_double_without_map_check;
|
Label fast_double_with_map_check, fast_double_without_map_check;
|
||||||
|
Label transition_smi_elements, finish_object_store, non_double_value;
|
||||||
|
Label transition_double_elements;
|
||||||
|
|
||||||
// Register usage.
|
// Register usage.
|
||||||
Register value = a0;
|
Register value = a0;
|
||||||
Register key = a1;
|
Register key = a1;
|
||||||
Register receiver = a2;
|
Register receiver = a2;
|
||||||
Register elements = a3; // Elements array of the receiver.
|
Register receiver_map = a3;
|
||||||
Register elements_map = t2;
|
Register elements_map = t2;
|
||||||
Register receiver_map = t3;
|
Register elements = t3; // Elements array of the receiver.
|
||||||
// t0 and t1 are used as general scratch registers.
|
// t0 and t1 are used as general scratch registers.
|
||||||
|
|
||||||
// Check that the key is a smi.
|
// Check that the key is a smi.
|
||||||
@ -1298,9 +1300,11 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
|
|||||||
__ mov(v0, value);
|
__ mov(v0, value);
|
||||||
|
|
||||||
__ bind(&non_smi_value);
|
__ bind(&non_smi_value);
|
||||||
// Escape to slow case when writing non-smi into smi-only array.
|
// Escape to elements kind transition case.
|
||||||
__ CheckFastObjectElements(receiver_map, scratch_value, &slow);
|
__ CheckFastObjectElements(receiver_map, scratch_value,
|
||||||
|
&transition_smi_elements);
|
||||||
// Fast elements array, store the value to the elements backing store.
|
// Fast elements array, store the value to the elements backing store.
|
||||||
|
__ bind(&finish_object_store);
|
||||||
__ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
__ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
||||||
__ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize);
|
__ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize);
|
||||||
__ Addu(address, address, scratch_value);
|
__ Addu(address, address, scratch_value);
|
||||||
@ -1326,13 +1330,57 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
|
|||||||
key,
|
key,
|
||||||
receiver,
|
receiver,
|
||||||
elements,
|
elements,
|
||||||
|
a3,
|
||||||
t0,
|
t0,
|
||||||
t1,
|
t1,
|
||||||
t2,
|
t2,
|
||||||
t3,
|
&transition_double_elements);
|
||||||
&slow);
|
|
||||||
__ Ret(USE_DELAY_SLOT);
|
__ Ret(USE_DELAY_SLOT);
|
||||||
__ mov(v0, value);
|
__ mov(v0, value);
|
||||||
|
|
||||||
|
__ bind(&transition_smi_elements);
|
||||||
|
// Transition the array appropriately depending on the value type.
|
||||||
|
__ lw(t0, FieldMemOperand(value, HeapObject::kMapOffset));
|
||||||
|
__ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
|
||||||
|
__ Branch(&non_double_value, ne, t0, Operand(at));
|
||||||
|
|
||||||
|
// Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
|
||||||
|
// FAST_DOUBLE_ELEMENTS and complete the store.
|
||||||
|
__ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
|
||||||
|
FAST_DOUBLE_ELEMENTS,
|
||||||
|
receiver_map,
|
||||||
|
t0,
|
||||||
|
&slow);
|
||||||
|
ASSERT(receiver_map.is(a3)); // Transition code expects map in a3
|
||||||
|
ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
|
||||||
|
__ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
|
||||||
|
__ jmp(&fast_double_without_map_check);
|
||||||
|
|
||||||
|
__ bind(&non_double_value);
|
||||||
|
// Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
|
||||||
|
__ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
|
||||||
|
FAST_ELEMENTS,
|
||||||
|
receiver_map,
|
||||||
|
t0,
|
||||||
|
&slow);
|
||||||
|
ASSERT(receiver_map.is(a3)); // Transition code expects map in a3
|
||||||
|
ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
|
||||||
|
__ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
|
||||||
|
__ jmp(&finish_object_store);
|
||||||
|
|
||||||
|
__ bind(&transition_double_elements);
|
||||||
|
// Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
|
||||||
|
// HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
|
||||||
|
// transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
|
||||||
|
__ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
|
||||||
|
FAST_ELEMENTS,
|
||||||
|
receiver_map,
|
||||||
|
t0,
|
||||||
|
&slow);
|
||||||
|
ASSERT(receiver_map.is(a3)); // Transition code expects map in a3
|
||||||
|
ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
|
||||||
|
__ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
|
||||||
|
__ jmp(&finish_object_store);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4279,26 +4279,41 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroAssembler::LoadGlobalInitialConstructedArrayMap(
|
void MacroAssembler::LoadTransitionedArrayMapConditional(
|
||||||
|
ElementsKind expected_kind,
|
||||||
|
ElementsKind transitioned_kind,
|
||||||
|
Register map_in_out,
|
||||||
|
Register scratch,
|
||||||
|
Label* no_map_match) {
|
||||||
|
// Load the global or builtins object from the current context.
|
||||||
|
lw(scratch, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||||
|
lw(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
|
||||||
|
|
||||||
|
// Check that the function's map is the same as the expected cached map.
|
||||||
|
int expected_index =
|
||||||
|
Context::GetContextMapIndexFromElementsKind(expected_kind);
|
||||||
|
lw(at, MemOperand(scratch, Context::SlotOffset(expected_index)));
|
||||||
|
Branch(no_map_match, ne, map_in_out, Operand(at));
|
||||||
|
|
||||||
|
// Use the transitioned cached map.
|
||||||
|
int trans_index =
|
||||||
|
Context::GetContextMapIndexFromElementsKind(transitioned_kind);
|
||||||
|
lw(map_in_out, MemOperand(scratch, Context::SlotOffset(trans_index)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MacroAssembler::LoadInitialArrayMap(
|
||||||
Register function_in, Register scratch, Register map_out) {
|
Register function_in, Register scratch, Register map_out) {
|
||||||
ASSERT(!function_in.is(map_out));
|
ASSERT(!function_in.is(map_out));
|
||||||
Label done;
|
Label done;
|
||||||
lw(map_out, FieldMemOperand(function_in,
|
lw(map_out, FieldMemOperand(function_in,
|
||||||
JSFunction::kPrototypeOrInitialMapOffset));
|
JSFunction::kPrototypeOrInitialMapOffset));
|
||||||
if (!FLAG_smi_only_arrays) {
|
if (!FLAG_smi_only_arrays) {
|
||||||
// Load the global or builtins object from the current context.
|
LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
|
||||||
lw(scratch, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
FAST_ELEMENTS,
|
||||||
lw(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
|
map_out,
|
||||||
|
scratch,
|
||||||
// Check that the function's map is same as the cached map.
|
&done);
|
||||||
lw(at, MemOperand(
|
|
||||||
scratch, Context::SlotOffset(Context::SMI_JS_ARRAY_MAP_INDEX)));
|
|
||||||
Branch(&done, ne, map_out, Operand(at));
|
|
||||||
|
|
||||||
// Use the cached transitioned map.
|
|
||||||
lw(map_out,
|
|
||||||
MemOperand(scratch,
|
|
||||||
Context::SlotOffset(Context::OBJECT_JS_ARRAY_MAP_INDEX)));
|
|
||||||
}
|
}
|
||||||
bind(&done);
|
bind(&done);
|
||||||
}
|
}
|
||||||
|
@ -772,10 +772,21 @@ class MacroAssembler: public Assembler {
|
|||||||
|
|
||||||
void LoadContext(Register dst, int context_chain_length);
|
void LoadContext(Register dst, int context_chain_length);
|
||||||
|
|
||||||
// Load the initial map for new Arrays of a given type.
|
// Conditionally load the cached Array transitioned map of type
|
||||||
void LoadGlobalInitialConstructedArrayMap(Register function_in,
|
// transitioned_kind from the global context if the map in register
|
||||||
Register scratch,
|
// map_in_out is the cached Array map in the global context of
|
||||||
Register map_out);
|
// expected_kind.
|
||||||
|
void LoadTransitionedArrayMapConditional(
|
||||||
|
ElementsKind expected_kind,
|
||||||
|
ElementsKind transitioned_kind,
|
||||||
|
Register map_in_out,
|
||||||
|
Register scratch,
|
||||||
|
Label* no_map_match);
|
||||||
|
|
||||||
|
// Load the initial map for new Arrays from a JSFunction.
|
||||||
|
void LoadInitialArrayMap(Register function_in,
|
||||||
|
Register scratch,
|
||||||
|
Register map_out);
|
||||||
|
|
||||||
void LoadGlobalFunction(int index, Register function);
|
void LoadGlobalFunction(int index, Register function);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user