Commit 43a1f5e2 authored by danno@chromium.org's avatar danno@chromium.org

Eliminate redundant smi checks

R=mstarzinger@chromium.org

Review URL: https://chromiumcodereview.appspot.com/10543094

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11774 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 06723da2
......@@ -1710,10 +1710,9 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} 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()
......
......@@ -2753,9 +2753,14 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
// 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());
}
}
}
......
......@@ -1712,14 +1712,14 @@ void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
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 @@ HValue* HLoadKeyedGeneric::Canonicalize() {
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(
......
......@@ -1848,7 +1848,9 @@ class HCallRuntime: public HCall<1> {
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 @@ class HJSArrayLength: public HTemplateInstruction<2> {
DECLARE_CONCRETE_INSTRUCTION(JSArrayLength)
protected:
virtual bool DataEquals(HValue* other) { return true; }
virtual bool DataEquals(HValue* other_raw) { return true; }
};
......@@ -3980,18 +3982,19 @@ class ArrayInstructionInterface {
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 @@ class HLoadKeyedFastElement
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 @@ class HLoadKeyedFastElement
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 @@ class HLoadKeyedFastDoubleElement
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); }
......
......@@ -4128,8 +4128,7 @@ void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
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 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
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 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
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 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
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 @@ void HGraphBuilder::VisitProperty(Property* expr) {
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));
......
......@@ -2505,8 +2505,13 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
// 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 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
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));
}
......
......@@ -1707,8 +1707,9 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} 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 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
: 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()) {
......
......@@ -243,8 +243,6 @@ void MacroAssembler::RecordWriteForMap(
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 @@ void MacroAssembler::RecordWriteForMap(
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));
......
......@@ -2389,8 +2389,13 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
// 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 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
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);
}
......
......@@ -1644,14 +1644,13 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} 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()) {
......
// 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));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment