Revision: 6781
Author: [email protected]
Date: Mon Feb 14 13:21:33 2011
Log: Implement specialized IC code stubs for pixel array stores.
Review URL: http://codereview.chromium.org/6478027
http://code.google.com/p/v8/source/detail?r=6781
Modified:
/branches/bleeding_edge/src/arm/code-stubs-arm.cc
/branches/bleeding_edge/src/arm/code-stubs-arm.h
/branches/bleeding_edge/src/arm/ic-arm.cc
/branches/bleeding_edge/src/arm/stub-cache-arm.cc
/branches/bleeding_edge/src/heap.h
/branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
/branches/bleeding_edge/src/ia32/code-stubs-ia32.h
/branches/bleeding_edge/src/ia32/ic-ia32.cc
/branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/stub-cache.cc
/branches/bleeding_edge/src/stub-cache.h
/branches/bleeding_edge/src/x64/code-stubs-x64.cc
/branches/bleeding_edge/src/x64/code-stubs-x64.h
/branches/bleeding_edge/src/x64/ic-x64.cc
/branches/bleeding_edge/src/x64/stub-cache-x64.cc
/branches/bleeding_edge/test/cctest/test-api.cc
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Feb 10 12:04:54
2011
+++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Mon Feb 14 13:21:33
2011
@@ -6026,6 +6026,91 @@
__ SmiTag(r0, scratch1);
__ Ret();
}
+
+
+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 __
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.h Fri Feb 4 05:43:38
2011
+++ /branches/bleeding_edge/src/arm/code-stubs-arm.h Mon Feb 14 13:21:33
2011
@@ -589,14 +589,14 @@
};
-// 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 @@
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
=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc Mon Feb 14 05:13:41 2011
+++ /branches/bleeding_edge/src/arm/ic-arm.cc Mon Feb 14 13:21:33 2011
@@ -1475,24 +1475,20 @@
// 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
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Fri Feb 4 05:43:38
2011
+++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Mon Feb 14 13:21:33
2011
@@ -3257,6 +3257,47 @@
// Return the generated code.
return GetCode(NORMAL, NULL);
}
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/heap.h Fri Feb 4 05:43:38 2011
+++ /branches/bleeding_edge/src/heap.h Mon Feb 14 13:21:33 2011
@@ -184,6 +184,7 @@
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") \
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Tue Feb 8 12:13:08
2011
+++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Mon Feb 14 13:21:33
2011
@@ -6559,9 +6559,19 @@
__ 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));
@@ -6573,6 +6583,90 @@
__ SmiTag(result);
__ ret(0);
}
+
+
+// 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 __
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.h Thu Feb 3 04:50:50
2011
+++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.h Mon Feb 14 13:21:33
2011
@@ -490,14 +490,14 @@
};
-// 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 @@
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
=======================================
--- /branches/bleeding_edge/src/ia32/ic-ia32.cc Mon Feb 14 05:13:41 2011
+++ /branches/bleeding_edge/src/ia32/ic-ia32.cc Mon Feb 14 13:21:33 2011
@@ -809,28 +809,17 @@
// 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
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Feb 3 04:50:50
2011
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Mon Feb 14 13:21:33
2011
@@ -2707,6 +2707,42 @@
// Return the generated code.
return GetCode(NORMAL, NULL);
}
+
+
+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,
=======================================
--- /branches/bleeding_edge/src/ic.cc Sun Feb 13 08:19:53 2011
+++ /branches/bleeding_edge/src/ic.cc Mon Feb 14 13:21:33 2011
@@ -1632,19 +1632,25 @@
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);
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc Sun Feb 13 08:19:53 2011
+++ /branches/bleeding_edge/src/stub-cache.cc Mon Feb 14 13:21:33 2011
@@ -540,6 +540,33 @@
}
return code;
}
+
+
+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 {
=======================================
--- /branches/bleeding_edge/src/stub-cache.h Sun Feb 13 08:19:53 2011
+++ /branches/bleeding_edge/src/stub-cache.h Mon Feb 14 13:21:33 2011
@@ -176,6 +176,9 @@
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 @@
MUST_USE_RESULT MaybeObject* CompileStoreSpecialized(JSObject* receiver);
+ MUST_USE_RESULT MaybeObject* CompileStorePixelArray(JSObject* receiver);
+
private:
MaybeObject* GetCode(PropertyType type, String* name);
};
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Feb 7 23:49:59
2011
+++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Feb 14 13:21:33
2011
@@ -4767,9 +4767,19 @@
}
__ 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));
@@ -4782,6 +4792,89 @@
__ ret(0);
}
+
+// 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 __
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.h Thu Feb 3 07:36:44
2011
+++ /branches/bleeding_edge/src/x64/code-stubs-x64.h Mon Feb 14 13:21:33
2011
@@ -452,14 +452,14 @@
};
-// 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 @@
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
=======================================
--- /branches/bleeding_edge/src/x64/ic-x64.cc Mon Feb 14 05:13:41 2011
+++ /branches/bleeding_edge/src/x64/ic-x64.cc Mon Feb 14 13:21:33 2011
@@ -822,27 +822,18 @@
// 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
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Thu Feb 3 04:50:50
2011
+++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Mon Feb 14 13:21:33
2011
@@ -2557,6 +2557,43 @@
// Return the generated code.
return GetCode(NORMAL, NULL);
}
+
+
+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,
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Thu Feb 10 06:09:52 2011
+++ /branches/bleeding_edge/test/cctest/test-api.cc Mon Feb 14 13:21:33 2011
@@ -10691,7 +10691,62 @@
"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) {"
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev