Implement specialized IC code stubs for pixel array stores.
Review URL: http://codereview.chromium.org/6478027 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6781 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
7e6bbab2c8
commit
36088cb64f
@ -6028,6 +6028,91 @@ void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
void GenerateFastPixelArrayStore(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register key,
|
||||
Register value,
|
||||
Register elements,
|
||||
Register elements_map,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
bool load_elements_from_receiver,
|
||||
bool load_elements_map_from_elements,
|
||||
Label* key_not_smi,
|
||||
Label* value_not_smi,
|
||||
Label* not_pixel_array,
|
||||
Label* out_of_range) {
|
||||
// Register use:
|
||||
// receiver - holds the receiver and is unchanged unless the
|
||||
// store succeeds.
|
||||
// key - holds the key (must be a smi) and is unchanged.
|
||||
// value - holds the value (must be a smi) and is unchanged.
|
||||
// elements - holds the element object of the receiver on entry if
|
||||
// load_elements_from_receiver is false, otherwise used
|
||||
// internally to store the pixel arrays elements and
|
||||
// external array pointer.
|
||||
// elements_map - holds the map of the element object if
|
||||
// load_elements_map_from_elements is false, otherwise
|
||||
// loaded with the element map.
|
||||
//
|
||||
Register external_pointer = elements;
|
||||
Register untagged_key = scratch1;
|
||||
Register untagged_value = scratch2;
|
||||
|
||||
if (load_elements_from_receiver) {
|
||||
__ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
|
||||
}
|
||||
|
||||
// By passing NULL as not_pixel_array, callers signal that they have already
|
||||
// verified that the receiver has pixel array elements.
|
||||
if (not_pixel_array != NULL) {
|
||||
if (load_elements_map_from_elements) {
|
||||
__ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
|
||||
}
|
||||
__ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
|
||||
__ cmp(elements_map, ip);
|
||||
__ b(ne, not_pixel_array);
|
||||
} else {
|
||||
if (FLAG_debug_code) {
|
||||
// Map check should have already made sure that elements is a pixel array.
|
||||
__ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
|
||||
__ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
|
||||
__ cmp(elements_map, ip);
|
||||
__ Assert(eq, "Elements isn't a pixel array");
|
||||
}
|
||||
}
|
||||
|
||||
// Some callers already have verified that the key is a smi. key_not_smi is
|
||||
// set to NULL as a sentinel for that case. Otherwise, add an explicit check
|
||||
// to ensure the key is a smi must be added.
|
||||
if (key_not_smi != NULL) {
|
||||
__ JumpIfNotSmi(key, key_not_smi);
|
||||
} else {
|
||||
if (FLAG_debug_code) {
|
||||
__ AbortIfNotSmi(key);
|
||||
}
|
||||
}
|
||||
|
||||
__ SmiUntag(untagged_key, key);
|
||||
|
||||
// Perform bounds check.
|
||||
__ ldr(scratch2, FieldMemOperand(elements, PixelArray::kLengthOffset));
|
||||
__ cmp(untagged_key, scratch2);
|
||||
__ b(hs, out_of_range); // unsigned check handles negative keys.
|
||||
|
||||
__ JumpIfNotSmi(value, value_not_smi);
|
||||
__ SmiUntag(untagged_value, value);
|
||||
|
||||
// Clamp the value to [0..255].
|
||||
__ Usat(untagged_value, 8, Operand(untagged_value));
|
||||
// Get the pointer to the external array. This clobbers elements.
|
||||
__ ldr(external_pointer,
|
||||
FieldMemOperand(elements, PixelArray::kExternalPointerOffset));
|
||||
__ strb(untagged_value, MemOperand(external_pointer, untagged_key));
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
#undef __
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -589,14 +589,14 @@ class DirectCEntryStub: public CodeStub {
|
||||
};
|
||||
|
||||
|
||||
// Generate code the to load an element from a pixel array. The receiver is
|
||||
// assumed to not be a smi and to have elements, the caller must guarantee this
|
||||
// precondition. If the receiver does not have elements that are pixel arrays,
|
||||
// the generated code jumps to not_pixel_array. If key is not a smi, then the
|
||||
// generated code branches to key_not_smi. Callers can specify NULL for
|
||||
// key_not_smi to signal that a smi check has already been performed on key so
|
||||
// that the smi check is not generated . If key is not a valid index within the
|
||||
// bounds of the pixel array, the generated code jumps to out_of_range.
|
||||
// Generate code to load an element from a pixel array. The receiver is assumed
|
||||
// to not be a smi and to have elements, the caller must guarantee this
|
||||
// precondition. If key is not a smi, then the generated code branches to
|
||||
// key_not_smi. Callers can specify NULL for key_not_smi to signal that a smi
|
||||
// check has already been performed on key so that the smi check is not
|
||||
// generated. If key is not a valid index within the bounds of the pixel array,
|
||||
// the generated code jumps to out_of_range. receiver, key and elements are
|
||||
// unchanged throughout the generated code sequence.
|
||||
void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register key,
|
||||
@ -609,6 +609,35 @@ void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||
Label* key_not_smi,
|
||||
Label* out_of_range);
|
||||
|
||||
// Generate code to store an element into a pixel array, clamping values between
|
||||
// [0..255]. The receiver is assumed to not be a smi and to have elements, the
|
||||
// caller must guarantee this precondition. If key is not a smi, then the
|
||||
// generated code branches to key_not_smi. Callers can specify NULL for
|
||||
// key_not_smi to signal that a smi check has already been performed on key so
|
||||
// that the smi check is not generated. If value is not a smi, the generated
|
||||
// code will branch to value_not_smi. If the receiver doesn't have pixel array
|
||||
// elements, the generated code will branch to not_pixel_array, unless
|
||||
// not_pixel_array is NULL, in which case the caller must ensure that the
|
||||
// receiver has pixel array elements. If key is not a valid index within the
|
||||
// bounds of the pixel array, the generated code jumps to out_of_range. If
|
||||
// load_elements_from_receiver is true, then the elements of receiver is loaded
|
||||
// into elements, otherwise elements is assumed to already be the receiver's
|
||||
// elements. If load_elements_map_from_elements is true, elements_map is loaded
|
||||
// from elements, otherwise it is assumed to already contain the element map.
|
||||
void GenerateFastPixelArrayStore(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register key,
|
||||
Register value,
|
||||
Register elements,
|
||||
Register elements_map,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
bool load_elements_from_receiver,
|
||||
bool load_elements_map_from_elements,
|
||||
Label* key_not_smi,
|
||||
Label* value_not_smi,
|
||||
Label* not_pixel_array,
|
||||
Label* out_of_range);
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
|
@ -1475,24 +1475,20 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
// Check whether the elements is a pixel array.
|
||||
// r4: elements map.
|
||||
__ bind(&check_pixel_array);
|
||||
__ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
|
||||
__ cmp(r4, ip);
|
||||
__ b(ne, &slow);
|
||||
// Check that the value is a smi. If a conversion is needed call into the
|
||||
// runtime to convert and clamp.
|
||||
__ JumpIfNotSmi(value, &slow);
|
||||
__ mov(r4, Operand(key, ASR, kSmiTagSize)); // Untag the key.
|
||||
__ ldr(ip, FieldMemOperand(elements, PixelArray::kLengthOffset));
|
||||
__ cmp(r4, Operand(ip));
|
||||
__ b(hs, &slow);
|
||||
__ mov(r5, Operand(value, ASR, kSmiTagSize)); // Untag the value.
|
||||
__ Usat(r5, 8, Operand(r5)); // Clamp the value to [0..255].
|
||||
|
||||
// Get the pointer to the external array. This clobbers elements.
|
||||
__ ldr(elements,
|
||||
FieldMemOperand(elements, PixelArray::kExternalPointerOffset));
|
||||
__ strb(r5, MemOperand(elements, r4)); // Elements is now external array.
|
||||
__ Ret();
|
||||
GenerateFastPixelArrayStore(masm,
|
||||
r2,
|
||||
r1,
|
||||
r0,
|
||||
elements,
|
||||
r4,
|
||||
r5,
|
||||
r6,
|
||||
false,
|
||||
false,
|
||||
NULL,
|
||||
&slow,
|
||||
&slow,
|
||||
&slow);
|
||||
|
||||
// Extra capacity case: Check if there is extra capacity to
|
||||
// perform the store and update the length. Used for adding one
|
||||
|
@ -3259,6 +3259,47 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray(
|
||||
JSObject* receiver) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : value
|
||||
// -- r1 : key
|
||||
// -- r2 : receiver
|
||||
// -- r3 : scratch
|
||||
// -- r4 : scratch
|
||||
// -- r5 : scratch
|
||||
// -- r6 : scratch
|
||||
// -- lr : return address
|
||||
// -----------------------------------
|
||||
Label miss;
|
||||
|
||||
// Check that the map matches.
|
||||
__ CheckMap(r2, r6, Handle<Map>(receiver->map()), &miss, false);
|
||||
|
||||
GenerateFastPixelArrayStore(masm(),
|
||||
r2,
|
||||
r1,
|
||||
r0,
|
||||
r3,
|
||||
r4,
|
||||
r5,
|
||||
r6,
|
||||
true,
|
||||
true,
|
||||
&miss,
|
||||
&miss,
|
||||
NULL,
|
||||
&miss);
|
||||
|
||||
__ bind(&miss);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
|
||||
__ Jump(ic, RelocInfo::CODE_TARGET);
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(NORMAL, NULL);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : argc
|
||||
|
@ -184,6 +184,7 @@ namespace internal {
|
||||
V(KeyedLoadSpecialized_symbol, "KeyedLoadSpecialized") \
|
||||
V(KeyedStoreSpecialized_symbol, "KeyedStoreSpecialized") \
|
||||
V(KeyedLoadPixelArray_symbol, "KeyedLoadPixelArray") \
|
||||
V(KeyedStorePixelArray_symbol, "KeyedStorePixelArray") \
|
||||
V(stack_overflow_symbol, "kStackOverflowBoilerplate") \
|
||||
V(illegal_access_symbol, "illegal access") \
|
||||
V(out_of_memory_symbol, "out-of-memory") \
|
||||
|
@ -6559,9 +6559,19 @@ void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||
__ mov(untagged_key, key);
|
||||
__ SmiUntag(untagged_key);
|
||||
|
||||
// Verify that the receiver has pixel array elements.
|
||||
__ mov(elements, FieldOperand(receiver, JSObject::kElementsOffset));
|
||||
__ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
|
||||
// By passing NULL as not_pixel_array, callers signal that they have already
|
||||
// verified that the receiver has pixel array elements.
|
||||
if (not_pixel_array != NULL) {
|
||||
__ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
|
||||
} else {
|
||||
if (FLAG_debug_code) {
|
||||
// Map check should have already made sure that elements is a pixel array.
|
||||
__ cmp(FieldOperand(elements, HeapObject::kMapOffset),
|
||||
Immediate(Factory::pixel_array_map()));
|
||||
__ Assert(equal, "Elements isn't a pixel array");
|
||||
}
|
||||
}
|
||||
|
||||
// Key must be in range.
|
||||
__ cmp(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
|
||||
@ -6575,6 +6585,90 @@ void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Stores an indexed element into a pixel array, clamping the stored value.
|
||||
void GenerateFastPixelArrayStore(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register key,
|
||||
Register value,
|
||||
Register elements,
|
||||
Register scratch1,
|
||||
bool load_elements_from_receiver,
|
||||
Label* key_not_smi,
|
||||
Label* value_not_smi,
|
||||
Label* not_pixel_array,
|
||||
Label* out_of_range) {
|
||||
// Register use:
|
||||
// receiver - holds the receiver and is unchanged unless the
|
||||
// store succeeds.
|
||||
// key - holds the key (must be a smi) and is unchanged.
|
||||
// value - holds the value (must be a smi) and is unchanged.
|
||||
// elements - holds the element object of the receiver on entry if
|
||||
// load_elements_from_receiver is false, otherwise used
|
||||
// internally to store the pixel arrays elements and
|
||||
// external array pointer.
|
||||
//
|
||||
// receiver, key and value remain unmodified until it's guaranteed that the
|
||||
// store will succeed.
|
||||
Register external_pointer = elements;
|
||||
Register untagged_key = scratch1;
|
||||
Register untagged_value = receiver; // Only set once success guaranteed.
|
||||
|
||||
// Fetch the receiver's elements if the caller hasn't already done so.
|
||||
if (load_elements_from_receiver) {
|
||||
__ mov(elements, FieldOperand(receiver, JSObject::kElementsOffset));
|
||||
}
|
||||
|
||||
// By passing NULL as not_pixel_array, callers signal that they have already
|
||||
// verified that the receiver has pixel array elements.
|
||||
if (not_pixel_array != NULL) {
|
||||
__ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
|
||||
} else {
|
||||
if (FLAG_debug_code) {
|
||||
// Map check should have already made sure that elements is a pixel array.
|
||||
__ cmp(FieldOperand(elements, HeapObject::kMapOffset),
|
||||
Immediate(Factory::pixel_array_map()));
|
||||
__ Assert(equal, "Elements isn't a pixel array");
|
||||
}
|
||||
}
|
||||
|
||||
// Some callers already have verified that the key is a smi. key_not_smi is
|
||||
// set to NULL as a sentinel for that case. Otherwise, add an explicit check
|
||||
// to ensure the key is a smi must be added.
|
||||
if (key_not_smi != NULL) {
|
||||
__ JumpIfNotSmi(key, key_not_smi);
|
||||
} else {
|
||||
if (FLAG_debug_code) {
|
||||
__ AbortIfNotSmi(key);
|
||||
}
|
||||
}
|
||||
|
||||
// Key must be a smi and it must be in range.
|
||||
__ mov(untagged_key, key);
|
||||
__ SmiUntag(untagged_key);
|
||||
__ cmp(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
|
||||
__ j(above_equal, out_of_range); // unsigned check handles negative keys.
|
||||
|
||||
// Value must be a smi.
|
||||
__ JumpIfNotSmi(value, value_not_smi);
|
||||
__ mov(untagged_value, value);
|
||||
__ SmiUntag(untagged_value);
|
||||
|
||||
{ // Clamp the value to [0..255].
|
||||
NearLabel done;
|
||||
__ test(untagged_value, Immediate(0xFFFFFF00));
|
||||
__ j(zero, &done);
|
||||
__ setcc(negative, untagged_value); // 1 if negative, 0 if positive.
|
||||
__ dec_b(untagged_value); // 0 if negative, 255 if positive.
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
__ mov(external_pointer,
|
||||
FieldOperand(elements, PixelArray::kExternalPointerOffset));
|
||||
__ mov_b(Operand(external_pointer, untagged_key, times_1, 0), untagged_value);
|
||||
__ ret(0); // Return value in eax.
|
||||
}
|
||||
|
||||
|
||||
#undef __
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -490,14 +490,14 @@ class NumberToStringStub: public CodeStub {
|
||||
};
|
||||
|
||||
|
||||
// Generate code the to load an element from a pixel array. The receiver is
|
||||
// assumed to not be a smi and to have elements, the caller must guarantee this
|
||||
// precondition. If the receiver does not have elements that are pixel arrays,
|
||||
// the generated code jumps to not_pixel_array. If key is not a smi, then the
|
||||
// generated code branches to key_not_smi. Callers can specify NULL for
|
||||
// key_not_smi to signal that a smi check has already been performed on key so
|
||||
// that the smi check is not generated . If key is not a valid index within the
|
||||
// bounds of the pixel array, the generated code jumps to out_of_range.
|
||||
// Generate code to load an element from a pixel array. The receiver is assumed
|
||||
// to not be a smi and to have elements, the caller must guarantee this
|
||||
// precondition. If key is not a smi, then the generated code branches to
|
||||
// key_not_smi. Callers can specify NULL for key_not_smi to signal that a smi
|
||||
// check has already been performed on key so that the smi check is not
|
||||
// generated. If key is not a valid index within the bounds of the pixel array,
|
||||
// the generated code jumps to out_of_range. receiver, key and elements are
|
||||
// unchanged throughout the generated code sequence.
|
||||
void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register key,
|
||||
@ -508,6 +508,28 @@ void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||
Label* key_not_smi,
|
||||
Label* out_of_range);
|
||||
|
||||
// Generate code to store an element into a pixel array, clamping values between
|
||||
// [0..255]. The receiver is assumed to not be a smi and to have elements, the
|
||||
// caller must guarantee this precondition. If key is not a smi, then the
|
||||
// generated code branches to key_not_smi. Callers can specify NULL for
|
||||
// key_not_smi to signal that a smi check has already been performed on key so
|
||||
// that the smi check is not generated. If the value is not a smi, the generated
|
||||
// code will branch to value_not_smi. If the receiver doesn't have pixel array
|
||||
// elements, the generated code will branch to not_pixel_array, unless
|
||||
// not_pixel_array is NULL, in which case the caller must ensure that the
|
||||
// receiver has pixel array elements. If key is not a valid index within the
|
||||
// bounds of the pixel array, the generated code jumps to out_of_range.
|
||||
void GenerateFastPixelArrayStore(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register key,
|
||||
Register value,
|
||||
Register elements,
|
||||
Register scratch1,
|
||||
bool load_elements_from_receiver,
|
||||
Label* key_not_smi,
|
||||
Label* value_not_smi,
|
||||
Label* not_pixel_array,
|
||||
Label* out_of_range);
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
|
@ -809,28 +809,17 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
// ecx: key (a smi)
|
||||
// edx: receiver
|
||||
// edi: elements array
|
||||
__ CheckMap(edi, Factory::pixel_array_map(), &slow, true);
|
||||
// Check that the value is a smi. If a conversion is needed call into the
|
||||
// runtime to convert and clamp.
|
||||
__ test(eax, Immediate(kSmiTagMask));
|
||||
__ j(not_zero, &slow);
|
||||
__ mov(ebx, ecx);
|
||||
__ SmiUntag(ebx);
|
||||
__ cmp(ebx, FieldOperand(edi, PixelArray::kLengthOffset));
|
||||
__ j(above_equal, &slow);
|
||||
__ mov(ecx, eax); // Save the value. Key is not longer needed.
|
||||
__ SmiUntag(ecx);
|
||||
{ // Clamp the value to [0..255].
|
||||
Label done;
|
||||
__ test(ecx, Immediate(0xFFFFFF00));
|
||||
__ j(zero, &done);
|
||||
__ setcc(negative, ecx); // 1 if negative, 0 if positive.
|
||||
__ dec_b(ecx); // 0 if negative, 255 if positive.
|
||||
__ bind(&done);
|
||||
}
|
||||
__ mov(edi, FieldOperand(edi, PixelArray::kExternalPointerOffset));
|
||||
__ mov_b(Operand(edi, ebx, times_1, 0), ecx);
|
||||
__ ret(0); // Return value in eax.
|
||||
GenerateFastPixelArrayStore(masm,
|
||||
edx,
|
||||
ecx,
|
||||
eax,
|
||||
edi,
|
||||
ebx,
|
||||
false,
|
||||
NULL,
|
||||
&slow,
|
||||
&slow,
|
||||
&slow);
|
||||
|
||||
// Extra capacity case: Check if there is extra capacity to
|
||||
// perform the store and update the length. Used for adding one
|
||||
|
@ -2709,6 +2709,42 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray(
|
||||
JSObject* receiver) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : value
|
||||
// -- ecx : key
|
||||
// -- edx : receiver
|
||||
// -- esp[0] : return address
|
||||
// -----------------------------------
|
||||
Label miss;
|
||||
|
||||
// Check that the map matches.
|
||||
__ CheckMap(edx, Handle<Map>(receiver->map()), &miss, false);
|
||||
|
||||
// Do the load.
|
||||
GenerateFastPixelArrayStore(masm(),
|
||||
edx,
|
||||
ecx,
|
||||
eax,
|
||||
edi,
|
||||
ebx,
|
||||
true,
|
||||
&miss,
|
||||
&miss,
|
||||
NULL,
|
||||
&miss);
|
||||
|
||||
// Handle store cache miss.
|
||||
__ bind(&miss);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
|
||||
__ jmp(ic, RelocInfo::CODE_TARGET);
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(NORMAL, NULL);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
|
||||
JSObject* object,
|
||||
JSObject* last) {
|
||||
|
32
src/ic.cc
32
src/ic.cc
@ -1632,19 +1632,25 @@ MaybeObject* KeyedStoreIC::Store(State state,
|
||||
|
||||
if (use_ic) {
|
||||
Code* stub = generic_stub();
|
||||
if (object->IsJSObject()) {
|
||||
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
||||
if (receiver->HasExternalArrayElements()) {
|
||||
MaybeObject* probe =
|
||||
StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, true);
|
||||
stub =
|
||||
probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked());
|
||||
} else if (state == UNINITIALIZED &&
|
||||
key->IsSmi() &&
|
||||
receiver->map()->has_fast_elements()) {
|
||||
MaybeObject* probe = StubCache::ComputeKeyedStoreSpecialized(*receiver);
|
||||
stub =
|
||||
probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked());
|
||||
if (state == UNINITIALIZED) {
|
||||
if (object->IsJSObject()) {
|
||||
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
||||
if (receiver->HasExternalArrayElements()) {
|
||||
MaybeObject* probe =
|
||||
StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, true);
|
||||
stub = probe->IsFailure() ?
|
||||
NULL : Code::cast(probe->ToObjectUnchecked());
|
||||
} else if (receiver->HasPixelElements()) {
|
||||
MaybeObject* probe =
|
||||
StubCache::ComputeKeyedStorePixelArray(*receiver);
|
||||
stub = probe->IsFailure() ?
|
||||
NULL : Code::cast(probe->ToObjectUnchecked());
|
||||
} else if (key->IsSmi() && receiver->map()->has_fast_elements()) {
|
||||
MaybeObject* probe =
|
||||
StubCache::ComputeKeyedStoreSpecialized(*receiver);
|
||||
stub = probe->IsFailure() ?
|
||||
NULL : Code::cast(probe->ToObjectUnchecked());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stub != NULL) set_target(stub);
|
||||
|
@ -542,6 +542,33 @@ MaybeObject* StubCache::ComputeKeyedStoreSpecialized(JSObject* receiver) {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* StubCache::ComputeKeyedStorePixelArray(JSObject* receiver) {
|
||||
// Using NORMAL as the PropertyType for array element stores 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 stores. This is guaranteed to be the case since all field
|
||||
// keyed stores that are not array elements go through a generic builtin stub.
|
||||
Code::Flags flags =
|
||||
Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL);
|
||||
String* name = Heap::KeyedStorePixelArray_symbol();
|
||||
Object* code = receiver->map()->FindInCodeCache(name, flags);
|
||||
if (code->IsUndefined()) {
|
||||
KeyedStoreStubCompiler compiler;
|
||||
{ MaybeObject* maybe_code = compiler.CompileStorePixelArray(receiver);
|
||||
if (!maybe_code->ToObject(&code)) return maybe_code;
|
||||
}
|
||||
PROFILE(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) {
|
||||
|
@ -176,6 +176,9 @@ class StubCache : public AllStatic {
|
||||
MUST_USE_RESULT static MaybeObject* ComputeKeyedStoreSpecialized(
|
||||
JSObject* receiver);
|
||||
|
||||
MUST_USE_RESULT static MaybeObject* ComputeKeyedStorePixelArray(
|
||||
JSObject* receiver);
|
||||
|
||||
MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadOrStoreExternalArray(
|
||||
JSObject* receiver,
|
||||
bool is_store);
|
||||
@ -659,6 +662,8 @@ class KeyedStoreStubCompiler: public StubCompiler {
|
||||
|
||||
MUST_USE_RESULT MaybeObject* CompileStoreSpecialized(JSObject* receiver);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* CompileStorePixelArray(JSObject* receiver);
|
||||
|
||||
private:
|
||||
MaybeObject* GetCode(PropertyType type, String* name);
|
||||
};
|
||||
|
@ -4767,9 +4767,19 @@ void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||
}
|
||||
__ SmiToInteger32(untagged_key, key);
|
||||
|
||||
// Verify that the receiver has pixel array elements.
|
||||
__ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
|
||||
__ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
|
||||
// By passing NULL as not_pixel_array, callers signal that they have already
|
||||
// verified that the receiver has pixel array elements.
|
||||
if (not_pixel_array != NULL) {
|
||||
__ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
|
||||
} else {
|
||||
if (FLAG_debug_code) {
|
||||
// Map check should have already made sure that elements is a pixel array.
|
||||
__ Cmp(FieldOperand(elements, HeapObject::kMapOffset),
|
||||
Factory::pixel_array_map());
|
||||
__ Assert(equal, "Elements isn't a pixel array");
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the smi is in range.
|
||||
__ cmpl(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
|
||||
@ -4783,6 +4793,89 @@ void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Stores an indexed element into a pixel array, clamping the stored value.
|
||||
void GenerateFastPixelArrayStore(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register key,
|
||||
Register value,
|
||||
Register elements,
|
||||
Register scratch1,
|
||||
bool load_elements_from_receiver,
|
||||
bool key_is_untagged,
|
||||
Label* key_not_smi,
|
||||
Label* value_not_smi,
|
||||
Label* not_pixel_array,
|
||||
Label* out_of_range) {
|
||||
// Register use:
|
||||
// receiver - holds the receiver and is unchanged.
|
||||
// key - holds the key (must be a smi) and is unchanged.
|
||||
// value - holds the value (must be a smi) and is unchanged.
|
||||
// elements - holds the element object of the receiver on entry if
|
||||
// load_elements_from_receiver is false, otherwise used
|
||||
// internally to store the pixel arrays elements and
|
||||
// external array pointer.
|
||||
//
|
||||
Register external_pointer = elements;
|
||||
Register untagged_key = scratch1;
|
||||
Register untagged_value = receiver; // Only set once success guaranteed.
|
||||
|
||||
// Fetch the receiver's elements if the caller hasn't already done so.
|
||||
if (load_elements_from_receiver) {
|
||||
__ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
|
||||
}
|
||||
|
||||
// By passing NULL as not_pixel_array, callers signal that they have already
|
||||
// verified that the receiver has pixel array elements.
|
||||
if (not_pixel_array != NULL) {
|
||||
__ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
|
||||
} else {
|
||||
if (FLAG_debug_code) {
|
||||
// Map check should have already made sure that elements is a pixel array.
|
||||
__ Cmp(FieldOperand(elements, HeapObject::kMapOffset),
|
||||
Factory::pixel_array_map());
|
||||
__ Assert(equal, "Elements isn't a pixel array");
|
||||
}
|
||||
}
|
||||
|
||||
// Some callers already have verified that the key is a smi. key_not_smi is
|
||||
// set to NULL as a sentinel for that case. Otherwise, add an explicit check
|
||||
// to ensure the key is a smi must be added.
|
||||
if (key_not_smi != NULL) {
|
||||
__ JumpIfNotSmi(key, key_not_smi);
|
||||
} else {
|
||||
if (FLAG_debug_code) {
|
||||
__ AbortIfNotSmi(key);
|
||||
}
|
||||
}
|
||||
|
||||
// Key must be a smi and it must be in range.
|
||||
if (key_is_untagged) {
|
||||
untagged_key = key;
|
||||
} else {
|
||||
__ SmiToInteger32(untagged_key, key);
|
||||
}
|
||||
__ cmpl(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
|
||||
__ j(above_equal, out_of_range); // unsigned check handles negative keys.
|
||||
|
||||
// Value must be a smi.
|
||||
__ JumpIfNotSmi(value, value_not_smi);
|
||||
__ SmiToInteger32(untagged_value, value);
|
||||
|
||||
{ // Clamp the value to [0..255].
|
||||
NearLabel done;
|
||||
__ testl(untagged_value, Immediate(0xFFFFFF00));
|
||||
__ j(zero, &done);
|
||||
__ setcc(negative, untagged_value); // 1 if negative, 0 if positive.
|
||||
__ decb(untagged_value); // 0 if negative, 255 if positive.
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
__ movq(external_pointer,
|
||||
FieldOperand(elements, PixelArray::kExternalPointerOffset));
|
||||
__ movb(Operand(external_pointer, untagged_key, times_1, 0), untagged_value);
|
||||
__ ret(0); // Return value in eax.
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -452,14 +452,14 @@ class NumberToStringStub: public CodeStub {
|
||||
};
|
||||
|
||||
|
||||
// Generate code the to load an element from a pixel array. The receiver is
|
||||
// assumed to not be a smi and to have elements, the caller must guarantee this
|
||||
// precondition. If the receiver does not have elements that are pixel arrays,
|
||||
// the generated code jumps to not_pixel_array. If key is not a smi, then the
|
||||
// generated code branches to key_not_smi. Callers can specify NULL for
|
||||
// key_not_smi to signal that a smi check has already been performed on key so
|
||||
// that the smi check is not generated . If key is not a valid index within the
|
||||
// bounds of the pixel array, the generated code jumps to out_of_range.
|
||||
// Generate code to load an element from a pixel array. The receiver is assumed
|
||||
// to not be a smi and to have elements, the caller must guarantee this
|
||||
// precondition. If key is not a smi, then the generated code branches to
|
||||
// key_not_smi. Callers can specify NULL for key_not_smi to signal that a smi
|
||||
// check has already been performed on key so that the smi check is not
|
||||
// generated. If key is not a valid index within the bounds of the pixel array,
|
||||
// the generated code jumps to out_of_range. receiver, key and elements are
|
||||
// unchanged throughout the generated code sequence.
|
||||
void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register key,
|
||||
@ -470,6 +470,30 @@ void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||
Label* key_not_smi,
|
||||
Label* out_of_range);
|
||||
|
||||
// Generate code to store an element into a pixel array, clamping values between
|
||||
// [0..255]. The receiver is assumed to not be a smi and to have elements, the
|
||||
// caller must guarantee this precondition. If key is not a smi, then the
|
||||
// generated code branches to key_not_smi. Callers can specify NULL for
|
||||
// key_not_smi to signal that a smi check has already been performed on key so
|
||||
// that the smi check is not generated. If the value is not a smi, the
|
||||
// generated code will branch to value_not_smi. If the receiver
|
||||
// doesn't have pixel array elements, the generated code will branch to
|
||||
// not_pixel_array, unless not_pixel_array is NULL, in which case the caller
|
||||
// must ensure that the receiver has pixel array elements. If key is not a
|
||||
// valid index within the bounds of the pixel array, the generated code jumps to
|
||||
// out_of_range.
|
||||
void GenerateFastPixelArrayStore(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register key,
|
||||
Register value,
|
||||
Register elements,
|
||||
Register scratch1,
|
||||
bool load_elements_from_receiver,
|
||||
bool key_is_untagged,
|
||||
Label* key_not_smi,
|
||||
Label* value_not_smi,
|
||||
Label* not_pixel_array,
|
||||
Label* out_of_range);
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
|
@ -822,27 +822,18 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
// rbx: receiver's elements array
|
||||
// rcx: index, zero-extended.
|
||||
__ bind(&check_pixel_array);
|
||||
__ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
|
||||
Heap::kPixelArrayMapRootIndex);
|
||||
__ j(not_equal, &slow);
|
||||
// Check that the value is a smi. If a conversion is needed call into the
|
||||
// runtime to convert and clamp.
|
||||
__ JumpIfNotSmi(rax, &slow);
|
||||
__ cmpl(rcx, FieldOperand(rbx, PixelArray::kLengthOffset));
|
||||
__ j(above_equal, &slow);
|
||||
// No more bailouts to slow case on this path, so key not needed.
|
||||
__ SmiToInteger32(rdi, rax);
|
||||
{ // Clamp the value to [0..255].
|
||||
NearLabel done;
|
||||
__ testl(rdi, Immediate(0xFFFFFF00));
|
||||
__ j(zero, &done);
|
||||
__ setcc(negative, rdi); // 1 if negative, 0 if positive.
|
||||
__ decb(rdi); // 0 if negative, 255 if positive.
|
||||
__ bind(&done);
|
||||
}
|
||||
__ movq(rbx, FieldOperand(rbx, PixelArray::kExternalPointerOffset));
|
||||
__ movb(Operand(rbx, rcx, times_1, 0), rdi);
|
||||
__ ret(0);
|
||||
GenerateFastPixelArrayStore(masm,
|
||||
rdx,
|
||||
rcx,
|
||||
rax,
|
||||
rbx,
|
||||
rdi,
|
||||
false,
|
||||
true,
|
||||
NULL,
|
||||
&slow,
|
||||
&slow,
|
||||
&slow);
|
||||
|
||||
// Extra capacity case: Check if there is extra capacity to
|
||||
// perform the store and update the length. Used for adding one
|
||||
|
@ -2559,6 +2559,43 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray(
|
||||
JSObject* receiver) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : value
|
||||
// -- rcx : key
|
||||
// -- rdx : receiver
|
||||
// -- rsp[0] : return address
|
||||
// -----------------------------------
|
||||
Label miss;
|
||||
|
||||
// Check that the map matches.
|
||||
__ CheckMap(rdx, Handle<Map>(receiver->map()), &miss, false);
|
||||
|
||||
// Do the load.
|
||||
GenerateFastPixelArrayStore(masm(),
|
||||
rdx,
|
||||
rcx,
|
||||
rax,
|
||||
rdi,
|
||||
rbx,
|
||||
true,
|
||||
false,
|
||||
&miss,
|
||||
&miss,
|
||||
NULL,
|
||||
&miss);
|
||||
|
||||
// Handle store cache miss.
|
||||
__ bind(&miss);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
|
||||
__ jmp(ic, RelocInfo::CODE_TARGET);
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(NORMAL, NULL);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
|
||||
JSObject* object,
|
||||
JSObject* last) {
|
||||
|
@ -10691,7 +10691,62 @@ THREADED_TEST(PixelArray) {
|
||||
"result");
|
||||
CHECK_EQ(32640, result->Int32Value());
|
||||
|
||||
// Make sure that pixel array loads are optimized by crankshaft.
|
||||
// Make sure that pixel array store ICs clamp values correctly.
|
||||
result = CompileRun("function pa_store(p) {"
|
||||
" for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
|
||||
"}"
|
||||
"pa_store(pixels);"
|
||||
"var sum = 0;"
|
||||
"for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
|
||||
"sum");
|
||||
CHECK_EQ(48896, result->Int32Value());
|
||||
|
||||
// Make sure that pixel array stores correctly handle accesses outside
|
||||
// of the pixel array..
|
||||
result = CompileRun("function pa_store(p,start) {"
|
||||
" for (var j = 0; j < 256; j++) {"
|
||||
" p[j+start] = j * 2;"
|
||||
" }"
|
||||
"}"
|
||||
"pa_store(pixels,0);"
|
||||
"pa_store(pixels,-128);"
|
||||
"var sum = 0;"
|
||||
"for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
|
||||
"sum");
|
||||
CHECK_EQ(65280, result->Int32Value());
|
||||
|
||||
// Make sure that the generic store stub correctly handle accesses outside
|
||||
// of the pixel array..
|
||||
result = CompileRun("function pa_store(p,start) {"
|
||||
" for (var j = 0; j < 256; j++) {"
|
||||
" p[j+start] = j * 2;"
|
||||
" }"
|
||||
"}"
|
||||
"pa_store(pixels,0);"
|
||||
"just_ints = new Object();"
|
||||
"for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
|
||||
"pa_store(just_ints, 0);"
|
||||
"pa_store(pixels,-128);"
|
||||
"var sum = 0;"
|
||||
"for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
|
||||
"sum");
|
||||
CHECK_EQ(65280, result->Int32Value());
|
||||
|
||||
// Make sure that the generic keyed store stub clamps pixel array values
|
||||
// correctly.
|
||||
result = CompileRun("function pa_store(p) {"
|
||||
" for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
|
||||
"}"
|
||||
"pa_store(pixels);"
|
||||
"just_ints = new Object();"
|
||||
"pa_store(just_ints);"
|
||||
"pa_store(pixels);"
|
||||
"var sum = 0;"
|
||||
"for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
|
||||
"sum");
|
||||
CHECK_EQ(48896, result->Int32Value());
|
||||
|
||||
// Make sure that pixel array loads are optimized by crankshaft.
|
||||
result = CompileRun("function pa_load(p) {"
|
||||
" var sum = 0;"
|
||||
" for (var i=0; i<256; ++i) {"
|
||||
|
Loading…
Reference in New Issue
Block a user