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:
danno@chromium.org 2011-02-14 21:21:33 +00:00
parent 7e6bbab2c8
commit 36088cb64f
17 changed files with 634 additions and 103 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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") \

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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);

View File

@ -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) {

View File

@ -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);
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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) {"