Revision: 11774
Author: [email protected]
Date: Tue Jun 12 05:16:19 2012
Log: Eliminate redundant smi checks
[email protected]
Review URL: https://chromiumcodereview.appspot.com/10543094
http://code.google.com/p/v8/source/detail?r=11774
Added:
/branches/bleeding_edge/test/mjsunit/fast-array-length.js
Modified:
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/hydrogen-instructions.cc
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.cc
/branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.cc
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/fast-array-length.js Tue Jun 12
05:16:19 2012
@@ -0,0 +1,37 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+// This is a regression test for overlapping key and value registers.
+
+
+var a = [0, 1, 2, 3, 4, 5];
+assertTrue(%HasFastSmiElements(a));
+a.length = (1 << 30);
+assertFalse(%HasFastSmiElements(a));
+
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Mon Jun 11 05:42:31 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Tue Jun 12 05:16:19 2012
@@ -1710,10 +1710,9 @@
} else {
ASSERT(to.IsInteger32());
LOperand* value = UseRegisterAtStart(instr->value());
- bool needs_check = !instr->value()->type().IsSmi();
LInstruction* res = NULL;
- if (!needs_check) {
- res = DefineAsRegister(new(zone()) LSmiUntag(value, needs_check));
+ if (instr->value()->type().IsSmi()) {
+ res = DefineAsRegister(new(zone()) LSmiUntag(value, false));
} else {
LOperand* temp1 = TempRegister();
LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister()
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Jun 11
05:42:31 2012
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Jun 12
05:16:19 2012
@@ -2753,9 +2753,14 @@
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
- __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
- __ cmp(result, scratch);
- DeoptimizeIf(eq, instr->environment());
+ if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
+ __ tst(result, Operand(kSmiTagMask));
+ DeoptimizeIf(ne, instr->environment());
+ } else {
+ __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
+ __ cmp(result, scratch);
+ DeoptimizeIf(eq, instr->environment());
+ }
}
}
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Mon Jun 11
05:42:31 2012
+++ /branches/bleeding_edge/src/hydrogen-instructions.cc Tue Jun 12
05:16:19 2012
@@ -1712,14 +1712,14 @@
stream->Add("[");
key()->PrintNameTo(stream);
stream->Add("]");
- if (hole_check_mode_ == PERFORM_HOLE_CHECK) {
+ if (RequiresHoleCheck()) {
stream->Add(" check_hole");
}
}
bool HLoadKeyedFastElement::RequiresHoleCheck() {
- if (hole_check_mode_ == OMIT_HOLE_CHECK) {
+ if (IsFastPackedElementsKind(elements_kind())) {
return false;
}
@@ -1765,8 +1765,7 @@
new(block()->zone()) HCheckMapValue(object(),
names_cache->map());
HInstruction* index = new(block()->zone()) HLoadKeyedFastElement(
index_cache,
- key_load->key(),
- OMIT_HOLE_CHECK);
+ key_load->key());
map_check->InsertBefore(this);
index->InsertBefore(this);
HLoadFieldByIndex* load = new(block()->zone()) HLoadFieldByIndex(
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Mon Jun 11 05:42:31
2012
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Tue Jun 12 05:16:19
2012
@@ -1848,7 +1848,9 @@
class HJSArrayLength: public HTemplateInstruction<2> {
public:
- HJSArrayLength(HValue* value, HValue* typecheck) {
+ HJSArrayLength(HValue* value, HValue* typecheck,
+ HType type = HType::Tagged()) {
+ set_type(type);
// The length of an array is stored as a tagged value in the array
// object. It is guaranteed to be 32 bit integer, but it can be
// represented as either a smi or heap number.
@@ -1872,7 +1874,7 @@
DECLARE_CONCRETE_INSTRUCTION(JSArrayLength)
protected:
- virtual bool DataEquals(HValue* other) { return true; }
+ virtual bool DataEquals(HValue* other_raw) { return true; }
};
@@ -3980,18 +3982,19 @@
virtual ~ArrayInstructionInterface() { };
};
-
-enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK };
-
class HLoadKeyedFastElement
: public HTemplateInstruction<2>, public ArrayInstructionInterface {
public:
HLoadKeyedFastElement(HValue* obj,
HValue* key,
- HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK)
- : hole_check_mode_(hole_check_mode),
- index_offset_(0),
- is_dehoisted_(false) {
+ ElementsKind elements_kind = FAST_ELEMENTS)
+ : bit_field_(0) {
+ ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
+ bit_field_ = ElementsKindField::encode(elements_kind);
+ if (IsFastSmiElementsKind(elements_kind) &&
+ IsFastPackedElementsKind(elements_kind)) {
+ set_type(HType::Smi());
+ }
SetOperandAt(0, obj);
SetOperandAt(1, key);
set_representation(Representation::Tagged());
@@ -4001,12 +4004,19 @@
HValue* object() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
- uint32_t index_offset() { return index_offset_; }
- void SetIndexOffset(uint32_t index_offset) { index_offset_ =
index_offset; }
+ uint32_t index_offset() { return IndexOffsetField::decode(bit_field_); }
+ void SetIndexOffset(uint32_t index_offset) {
+ bit_field_ = IndexOffsetField::update(bit_field_, index_offset);
+ }
HValue* GetKey() { return key(); }
void SetKey(HValue* key) { SetOperandAt(1, key); }
- bool IsDehoisted() { return is_dehoisted_; }
- void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
+ bool IsDehoisted() { return IsDehoistedField::decode(bit_field_); }
+ void SetDehoisted(bool is_dehoisted) {
+ bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
+ }
+ ElementsKind elements_kind() const {
+ return ElementsKindField::decode(bit_field_);
+ }
virtual Representation RequiredInputRepresentation(int index) {
// The key is supposed to be Integer32.
@@ -4025,18 +4035,22 @@
virtual bool DataEquals(HValue* other) {
if (!other->IsLoadKeyedFastElement()) return false;
HLoadKeyedFastElement* other_load = HLoadKeyedFastElement::cast(other);
- if (is_dehoisted_ && index_offset_ != other_load->index_offset_)
+ if (IsDehoisted() && index_offset() != other_load->index_offset())
return false;
- return hole_check_mode_ == other_load->hole_check_mode_;
+ return elements_kind() == other_load->elements_kind();
}
private:
- HoleCheckMode hole_check_mode_;
- uint32_t index_offset_;
- bool is_dehoisted_;
+ class ElementsKindField: public BitField<ElementsKind, 0, 4> {};
+ class IndexOffsetField: public BitField<uint32_t, 4, 27> {};
+ class IsDehoistedField: public BitField<bool, 31, 1> {};
+ uint32_t bit_field_;
};
+enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK };
+
+
class HLoadKeyedFastDoubleElement
: public HTemplateInstruction<2>, public ArrayInstructionInterface {
public:
@@ -4044,15 +4058,15 @@
HValue* elements,
HValue* key,
HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK)
- : index_offset_(0),
- is_dehoisted_(false),
- hole_check_mode_(hole_check_mode) {
- SetOperandAt(0, elements);
- SetOperandAt(1, key);
- set_representation(Representation::Double());
+ : index_offset_(0),
+ is_dehoisted_(false),
+ hole_check_mode_(hole_check_mode) {
+ SetOperandAt(0, elements);
+ SetOperandAt(1, key);
+ set_representation(Representation::Double());
SetGVNFlag(kDependsOnDoubleArrayElements);
SetFlag(kUseGVN);
- }
+ }
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Tue Jun 12 03:22:33 2012
+++ /branches/bleeding_edge/src/hydrogen.cc Tue Jun 12 05:16:19 2012
@@ -4128,8 +4128,7 @@
HValue* key = AddInstruction(
new(zone()) HLoadKeyedFastElement(
environment()->ExpressionStackAt(2), // Enum cache.
- environment()->ExpressionStackAt(0), // Iteration index.
- OMIT_HOLE_CHECK));
+ environment()->ExpressionStackAt(0))); // Iteration index.
// Check if the expected map still matches that of the enumerable.
// If not just deoptimize.
@@ -5483,7 +5482,8 @@
if (IsFastDoubleElementsKind(elements_kind)) {
return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key,
mode);
} else { // Smi or Object elements.
- return new(zone()) HLoadKeyedFastElement(elements, checked_key, mode);
+ return new(zone()) HLoadKeyedFastElement(elements, checked_key,
+ elements_kind);
}
}
@@ -5531,7 +5531,8 @@
fast_elements ||
map->has_fast_double_elements());
if (map->instance_type() == JS_ARRAY_TYPE) {
- length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck));
+ length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck,
+ HType::Smi()));
} else {
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
}
@@ -5686,7 +5687,8 @@
set_current_block(if_jsarray);
HInstruction* length;
- length = AddInstruction(new(zone()) HJSArrayLength(object,
typecheck));
+ length = AddInstruction(new(zone()) HJSArrayLength(object,
typecheck,
+ HType::Smi()));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key,
length));
access = AddInstruction(BuildFastElementAccess(
elements, checked_key, val, elements_kind, is_store));
@@ -5886,7 +5888,6 @@
HInstruction* mapcheck =
AddInstruction(HCheckInstanceType::NewIsJSArray(array, zone()));
instr = new(zone()) HJSArrayLength(array, mapcheck);
-
} else if (expr->IsStringLength()) {
HValue* string = Pop();
AddInstruction(new(zone()) HCheckNonSmi(string));
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Jun 12
03:22:33 2012
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Jun 12
05:16:19 2012
@@ -2505,8 +2505,13 @@
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
- __ cmp(result, factory()->the_hole_value());
- DeoptimizeIf(equal, instr->environment());
+ if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
+ __ test(result, Immediate(kSmiTagMask));
+ DeoptimizeIf(not_equal, instr->environment());
+ } else {
+ __ cmp(result, factory()->the_hole_value());
+ DeoptimizeIf(equal, instr->environment());
+ }
}
}
@@ -3944,6 +3949,10 @@
if (instr->needs_check()) {
__ test(ToRegister(input), Immediate(kSmiTagMask));
DeoptimizeIf(not_zero, instr->environment());
+ } else {
+ if (FLAG_debug_code) {
+ __ AbortIfNotSmi(ToRegister(input));
+ }
}
__ SmiUntag(ToRegister(input));
}
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Tue Jun 12 03:22:33
2012
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Tue Jun 12 05:16:19
2012
@@ -1707,8 +1707,9 @@
} else {
ASSERT(to.IsInteger32());
LOperand* value = UseRegister(instr->value());
- bool needs_check = !instr->value()->type().IsSmi();
- if (needs_check) {
+ if (instr->value()->type().IsSmi()) {
+ return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
+ } else {
bool truncating = instr->CanTruncateToInt32();
LOperand* xmm_temp =
(truncating && CpuFeatures::IsSupported(SSE3))
@@ -1716,8 +1717,6 @@
: FixedTemp(xmm1);
LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp);
return AssignEnvironment(DefineSameAsFirst(res));
- } else {
- return DefineSameAsFirst(new(zone()) LSmiUntag(value,
needs_check));
}
}
} else if (from.IsDouble()) {
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Sun Jun 10
23:59:56 2012
+++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue Jun 12
05:16:19 2012
@@ -243,8 +243,6 @@
Register scratch1,
Register scratch2,
SaveFPRegsMode save_fp) {
- // First, check if a write barrier is even needed. The tests below
- // catch stores of Smis.
Label done;
Register address = scratch1;
@@ -281,7 +279,7 @@
Label::kNear);
// Delay the initialization of |address| and |value| for the stub until
it's
- // known that the will be needed. Up until this point their value are not
+ // known that the will be needed. Up until this point their values are
not
// needed since they are embedded in the operands of instructions that
need
// them.
lea(address, FieldOperand(object, HeapObject::kMapOffset));
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon Jun 11
05:42:31 2012
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Jun 12
05:16:19 2012
@@ -2389,8 +2389,13 @@
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
- __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
- DeoptimizeIf(equal, instr->environment());
+ if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
+ Condition smi = __ CheckSmi(result);
+ DeoptimizeIf(NegateCondition(smi), instr->environment());
+ } else {
+ __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
+ DeoptimizeIf(equal, instr->environment());
+ }
}
}
@@ -3790,6 +3795,10 @@
if (instr->needs_check()) {
Condition is_smi = __ CheckSmi(input);
DeoptimizeIf(NegateCondition(is_smi), instr->environment());
+ } else {
+ if (FLAG_debug_code) {
+ __ AbortIfNotSmi(input);
+ }
}
__ SmiToInteger32(input, input);
}
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Mon Jun 11 05:42:31 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Tue Jun 12 05:16:19 2012
@@ -1644,14 +1644,13 @@
} else {
ASSERT(to.IsInteger32());
LOperand* value = UseRegister(instr->value());
- bool needs_check = !instr->value()->type().IsSmi();
- if (needs_check) {
+ if (instr->value()->type().IsSmi()) {
+ return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
+ } else {
bool truncating = instr->CanTruncateToInt32();
LOperand* xmm_temp = truncating ? NULL : FixedTemp(xmm1);
LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp);
return AssignEnvironment(DefineSameAsFirst(res));
- } else {
- return DefineSameAsFirst(new(zone()) LSmiUntag(value,
needs_check));
}
}
} else if (from.IsDouble()) {
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev