Revision: 7840
Author: [email protected]
Date: Tue May 10 07:17:23 2011
Log: Refactor HCheckInstanceType to allow mask/tag tests.
This allows us to get rid of totally fake LAST_STRING_TYPE and makes
it possible to test for symbols.
I considered splitting HCheckInstanceType into two instructions, but
it seems nice to be able to hide the instance type implementation
details from the hydrogen level.
Review URL: http://codereview.chromium.org/6964011
http://code.google.com/p/v8/source/detail?r=7840
Modified:
/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/objects-printer.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon May 9
08:21:40 2011
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue May 10
07:17:23 2011
@@ -3869,22 +3869,41 @@
void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
Register input = ToRegister(instr->InputAt(0));
Register scratch = scratch0();
- InstanceType first = instr->hydrogen()->first();
- InstanceType last = instr->hydrogen()->last();
__ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
__ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
- __ cmp(scratch, Operand(first));
-
- // If there is only one type in the interval check for equality.
- if (first == last) {
- DeoptimizeIf(ne, instr->environment());
+
+ if (instr->hydrogen()->is_interval_check()) {
+ InstanceType first;
+ InstanceType last;
+ instr->hydrogen()->GetCheckInterval(&first, &last);
+
+ __ cmp(scratch, Operand(first));
+
+ // If there is only one type in the interval check for equality.
+ if (first == last) {
+ DeoptimizeIf(ne, instr->environment());
+ } else {
+ DeoptimizeIf(lo, instr->environment());
+ // Omit check for the last type.
+ if (last != LAST_TYPE) {
+ __ cmp(scratch, Operand(last));
+ DeoptimizeIf(hi, instr->environment());
+ }
+ }
} else {
- DeoptimizeIf(lo, instr->environment());
- // Omit check for the last type.
- if (last != LAST_TYPE) {
- __ cmp(scratch, Operand(last));
- DeoptimizeIf(hi, instr->environment());
+ uint8_t mask;
+ uint8_t tag;
+ instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
+
+ if (IsPowerOf2(mask)) {
+ ASSERT(tag == 0 || IsPowerOf2(tag));
+ __ tst(scratch, Operand(mask));
+ DeoptimizeIf(tag == 0 ? ne : eq, instr->environment());
+ } else {
+ __ and_(scratch, scratch, Operand(mask));
+ __ cmp(scratch, Operand(tag));
+ DeoptimizeIf(ne, instr->environment());
}
}
}
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Mon May 9
08:21:40 2011
+++ /branches/bleeding_edge/src/hydrogen-instructions.cc Tue May 10
07:17:23 2011
@@ -751,10 +751,38 @@
}
-HCheckInstanceType* HCheckInstanceType::NewIsJSObjectOrJSFunction(
- HValue* value) {
- STATIC_ASSERT((LAST_JS_OBJECT_TYPE + 1) == JS_FUNCTION_TYPE);
- return new HCheckInstanceType(value, FIRST_JS_OBJECT_TYPE,
JS_FUNCTION_TYPE);
+void HCheckInstanceType::GetCheckInterval(InstanceType* first,
+ InstanceType* last) {
+ ASSERT(is_interval_check());
+ switch (check_) {
+ case IS_JS_OBJECT_OR_JS_FUNCTION:
+ STATIC_ASSERT((LAST_JS_OBJECT_TYPE + 1) == JS_FUNCTION_TYPE);
+ *first = FIRST_JS_OBJECT_TYPE;
+ *last = JS_FUNCTION_TYPE;
+ return;
+ case IS_JS_ARRAY:
+ *first = *last = JS_ARRAY_TYPE;
+ return;
+ default:
+ UNREACHABLE();
+ }
+}
+
+
+void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) {
+ ASSERT(!is_interval_check());
+ switch (check_) {
+ case IS_STRING:
+ *mask = kIsNotStringMask;
+ *tag = kStringTag;
+ return;
+ case IS_SYMBOL:
+ *mask = kIsSymbolMask;
+ *tag = kSymbolTag;
+ return;
+ default:
+ UNREACHABLE();
+ }
}
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Mon May 9 08:21:40
2011
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Tue May 10 07:17:23
2011
@@ -1757,19 +1757,17 @@
class HCheckInstanceType: public HUnaryOperation {
public:
- // Check that the instance type is in the range [first, last] where
- // both first and last are included.
- HCheckInstanceType(HValue* value, InstanceType first, InstanceType last)
- : HUnaryOperation(value), first_(first), last_(last) {
- ASSERT(first <= last);
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- if ((FIRST_STRING_TYPE < first && last <= LAST_STRING_TYPE) ||
- (FIRST_STRING_TYPE <= first && last < LAST_STRING_TYPE)) {
- // A particular string instance type can change because of GC or
- // externalization, but the value still remains a string.
- SetFlag(kDependsOnMaps);
- }
+ static HCheckInstanceType* NewIsJSObjectOrJSFunction(HValue* value) {
+ return new HCheckInstanceType(value, IS_JS_OBJECT_OR_JS_FUNCTION);
+ }
+ static HCheckInstanceType* NewIsJSArray(HValue* value) {
+ return new HCheckInstanceType(value, IS_JS_ARRAY);
+ }
+ static HCheckInstanceType* NewIsString(HValue* value) {
+ return new HCheckInstanceType(value, IS_STRING);
+ }
+ static HCheckInstanceType* NewIsSymbol(HValue* value) {
+ return new HCheckInstanceType(value, IS_SYMBOL);
}
virtual bool IsCheckInstruction() const { return true; }
@@ -1785,17 +1783,15 @@
virtual HValue* Canonicalize() {
if (!value()->type().IsUninitialized() &&
value()->type().IsString() &&
- first() == FIRST_STRING_TYPE &&
- last() == LAST_STRING_TYPE) {
+ check_ == IS_STRING) {
return NULL;
}
return this;
}
- static HCheckInstanceType* NewIsJSObjectOrJSFunction(HValue* value);
-
- InstanceType first() const { return first_; }
- InstanceType last() const { return last_; }
+ bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
+ void GetCheckInterval(InstanceType* first, InstanceType* last);
+ void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
@@ -1805,12 +1801,25 @@
// with a larger range.
virtual bool DataEquals(HValue* other) {
HCheckInstanceType* b = HCheckInstanceType::cast(other);
- return (first_ == b->first()) && (last_ == b->last());
+ return check_ == b->check_;
}
private:
- InstanceType first_;
- InstanceType last_;
+ enum Check {
+ IS_JS_OBJECT_OR_JS_FUNCTION,
+ IS_JS_ARRAY,
+ IS_STRING,
+ IS_SYMBOL,
+ LAST_INTERVAL_CHECK = IS_JS_ARRAY
+ };
+
+ HCheckInstanceType(HValue* value, Check check)
+ : HUnaryOperation(value), check_(check) {
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
+
+ const Check check_;
};
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Tue May 10 06:29:57 2011
+++ /branches/bleeding_edge/src/hydrogen.cc Tue May 10 07:17:23 2011
@@ -3796,17 +3796,13 @@
if (expr->IsArrayLength()) {
HValue* array = Pop();
AddInstruction(new(zone()) HCheckNonSmi(array));
- AddInstruction(new(zone()) HCheckInstanceType(array,
- JS_ARRAY_TYPE,
- JS_ARRAY_TYPE));
+ AddInstruction(HCheckInstanceType::NewIsJSArray(array));
instr = new(zone()) HJSArrayLength(array);
} else if (expr->IsStringLength()) {
HValue* string = Pop();
AddInstruction(new(zone()) HCheckNonSmi(string));
- AddInstruction(new(zone()) HCheckInstanceType(string,
- FIRST_STRING_TYPE,
- LAST_STRING_TYPE));
+ AddInstruction(HCheckInstanceType::NewIsString(string));
instr = new(zone()) HStringLength(string);
} else if (expr->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(expr->key()));
@@ -4853,8 +4849,7 @@
HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string,
HValue* index) {
AddInstruction(new(zone()) HCheckNonSmi(string));
- AddInstruction(new(zone()) HCheckInstanceType(
- string, FIRST_STRING_TYPE, LAST_STRING_TYPE));
+ AddInstruction(HCheckInstanceType::NewIsString(string));
HStringLength* length = new(zone()) HStringLength(string);
AddInstruction(length);
AddInstruction(new(zone()) HBoundsCheck(index, length));
@@ -4894,11 +4889,9 @@
case Token::ADD:
if (info.IsString()) {
AddInstruction(new(zone()) HCheckNonSmi(left));
- AddInstruction(new(zone()) HCheckInstanceType(left,
FIRST_STRING_TYPE,
- LAST_STRING_TYPE));
+ AddInstruction(HCheckInstanceType::NewIsString(left));
AddInstruction(new(zone()) HCheckNonSmi(right));
- AddInstruction(new(zone()) HCheckInstanceType(right,
FIRST_STRING_TYPE,
- LAST_STRING_TYPE));
+ AddInstruction(HCheckInstanceType::NewIsString(right));
return new(zone()) HStringAdd(left, right);
} else {
return new(zone()) HAdd(left, right);
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue May 10
02:03:42 2011
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue May 10
07:17:23 2011
@@ -3829,29 +3829,43 @@
void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
Register input = ToRegister(instr->InputAt(0));
Register temp = ToRegister(instr->TempAt(0));
- InstanceType first = instr->hydrogen()->first();
- InstanceType last = instr->hydrogen()->last();
__ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
- // If there is only one type in the interval check for equality.
- if (first == last) {
+ if (instr->hydrogen()->is_interval_check()) {
+ InstanceType first;
+ InstanceType last;
+ instr->hydrogen()->GetCheckInterval(&first, &last);
+
__ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
static_cast<int8_t>(first));
- DeoptimizeIf(not_equal, instr->environment());
- } else if (first == FIRST_STRING_TYPE && last == LAST_STRING_TYPE) {
- // String has a dedicated bit in instance type.
- __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset),
kIsNotStringMask);
- DeoptimizeIf(not_zero, instr->environment());
- } else {
- __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
- static_cast<int8_t>(first));
- DeoptimizeIf(below, instr->environment());
- // Omit check for the last type.
- if (last != LAST_TYPE) {
- __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
- static_cast<int8_t>(last));
- DeoptimizeIf(above, instr->environment());
+
+ // If there is only one type in the interval check for equality.
+ if (first == last) {
+ DeoptimizeIf(not_equal, instr->environment());
+ } else {
+ DeoptimizeIf(below, instr->environment());
+ // Omit check for the last type.
+ if (last != LAST_TYPE) {
+ __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
+ static_cast<int8_t>(last));
+ DeoptimizeIf(above, instr->environment());
+ }
+ }
+ } else {
+ uint8_t mask;
+ uint8_t tag;
+ instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
+
+ if (IsPowerOf2(mask)) {
+ ASSERT(tag == 0 || IsPowerOf2(tag));
+ __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
+ DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
+ } else {
+ __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
+ __ and_(temp, mask);
+ __ cmpb(Operand(temp), tag);
+ DeoptimizeIf(not_equal, instr->environment());
}
}
}
=======================================
--- /branches/bleeding_edge/src/objects-printer.cc Tue Apr 26 06:53:19 2011
+++ /branches/bleeding_edge/src/objects-printer.cc Tue May 10 07:17:23 2011
@@ -414,7 +414,6 @@
case JS_BUILTINS_OBJECT_TYPE: return "JS_BUILTINS_OBJECT";
case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY";
case PROXY_TYPE: return "PROXY";
- case LAST_STRING_TYPE: return "LAST_STRING_TYPE";
case JS_MESSAGE_OBJECT_TYPE: return "JS_MESSAGE_OBJECT_TYPE";
#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME;
STRUCT_LIST(MAKE_STRUCT_CASE)
=======================================
--- /branches/bleeding_edge/src/objects.h Thu May 5 23:50:20 2011
+++ /branches/bleeding_edge/src/objects.h Tue May 10 07:17:23 2011
@@ -485,7 +485,6 @@
enum InstanceType {
// String types.
- // FIRST_STRING_TYPE
SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kSeqStringTag,
ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kSeqStringTag,
CONS_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kConsStringTag,
@@ -568,8 +567,6 @@
LAST_TYPE = JS_FUNCTION_TYPE,
INVALID_TYPE = FIRST_TYPE - 1,
FIRST_NONSTRING_TYPE = MAP_TYPE,
- FIRST_STRING_TYPE = FIRST_TYPE,
- LAST_STRING_TYPE = FIRST_NONSTRING_TYPE - 1,
// Boundaries for testing for an external array.
FIRST_EXTERNAL_ARRAY_TYPE = EXTERNAL_BYTE_ARRAY_TYPE,
LAST_EXTERNAL_ARRAY_TYPE = EXTERNAL_PIXEL_ARRAY_TYPE,
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue May 10
02:03:42 2011
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue May 10
07:17:23 2011
@@ -3650,30 +3650,45 @@
void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
Register input = ToRegister(instr->InputAt(0));
- InstanceType first = instr->hydrogen()->first();
- InstanceType last = instr->hydrogen()->last();
__ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
- // If there is only one type in the interval check for equality.
- if (first == last) {
+ if (instr->hydrogen()->is_interval_check()) {
+ InstanceType first;
+ InstanceType last;
+ instr->hydrogen()->GetCheckInterval(&first, &last);
+
__ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
Immediate(static_cast<int8_t>(first)));
- DeoptimizeIf(not_equal, instr->environment());
- } else if (first == FIRST_STRING_TYPE && last == LAST_STRING_TYPE) {
- // String has a dedicated bit in instance type.
- __ testb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
- Immediate(kIsNotStringMask));
- DeoptimizeIf(not_zero, instr->environment());
+
+ // If there is only one type in the interval check for equality.
+ if (first == last) {
+ DeoptimizeIf(not_equal, instr->environment());
+ } else {
+ DeoptimizeIf(below, instr->environment());
+ // Omit check for the last type.
+ if (last != LAST_TYPE) {
+ __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
+ Immediate(static_cast<int8_t>(last)));
+ DeoptimizeIf(above, instr->environment());
+ }
+ }
} else {
- __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
- Immediate(static_cast<int8_t>(first)));
- DeoptimizeIf(below, instr->environment());
- // Omit check for the last type.
- if (last != LAST_TYPE) {
- __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
- Immediate(static_cast<int8_t>(last)));
- DeoptimizeIf(above, instr->environment());
+ uint8_t mask;
+ uint8_t tag;
+ instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
+
+ if (IsPowerOf2(mask)) {
+ ASSERT(tag == 0 || IsPowerOf2(tag));
+ __ testb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
+ Immediate(mask));
+ DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
+ } else {
+ __ movzxbl(kScratchRegister,
+ FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
+ __ andb(kScratchRegister, Immediate(mask));
+ __ cmpb(kScratchRegister, Immediate(tag));
+ DeoptimizeIf(not_equal, instr->environment());
}
}
}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev