Commit b587aa2b authored by mythria's avatar mythria Committed by Commit bot

[Interpreter] Add support for cast operators to bytecode graph builder and

an optomization to remove redundant cast operations.

1. Adds an optimization to remove redundant ToBoolean and ToName operations.
2. Adds implementation and tests for cast operatorts to bytecode graph builder.

BUG=v8:4280
LOG=N

Review URL: https://codereview.chromium.org/1468003002

Cr-Commit-Position: refs/heads/master@{#32408}
parent 9e644881
...@@ -1021,27 +1021,35 @@ void BytecodeGraphBuilder::VisitTestInstanceOf( ...@@ -1021,27 +1021,35 @@ void BytecodeGraphBuilder::VisitTestInstanceOf(
} }
void BytecodeGraphBuilder::BuildCastOperator(
const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) {
Node* node = NewNode(js_op, environment()->LookupAccumulator());
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitToBoolean( void BytecodeGraphBuilder::VisitToBoolean(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED(); BuildCastOperator(javascript()->ToBoolean(), iterator);
} }
void BytecodeGraphBuilder::VisitToName( void BytecodeGraphBuilder::VisitToName(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED(); BuildCastOperator(javascript()->ToName(), iterator);
} }
void BytecodeGraphBuilder::VisitToNumber( void BytecodeGraphBuilder::VisitToNumber(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED(); BuildCastOperator(javascript()->ToNumber(), iterator);
} }
void BytecodeGraphBuilder::VisitToObject( void BytecodeGraphBuilder::VisitToObject(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED(); BuildCastOperator(javascript()->ToObject(), iterator);
} }
......
...@@ -117,6 +117,8 @@ class BytecodeGraphBuilder { ...@@ -117,6 +117,8 @@ class BytecodeGraphBuilder {
void BuildCompareOp(const Operator* op, void BuildCompareOp(const Operator* op,
const interpreter::BytecodeArrayIterator& iterator); const interpreter::BytecodeArrayIterator& iterator);
void BuildDelete(const interpreter::BytecodeArrayIterator& iterator); void BuildDelete(const interpreter::BytecodeArrayIterator& iterator);
void BuildCastOperator(const Operator* js_op,
const interpreter::BytecodeArrayIterator& iterator);
// Growth increment for the temporary buffer used to construct input lists to // Growth increment for the temporary buffer used to construct input lists to
// new nodes. // new nodes.
......
...@@ -8,6 +8,53 @@ namespace v8 { ...@@ -8,6 +8,53 @@ namespace v8 {
namespace internal { namespace internal {
namespace interpreter { namespace interpreter {
class BytecodeArrayBuilder::PreviousBytecodeHelper {
public:
explicit PreviousBytecodeHelper(const BytecodeArrayBuilder& array_builder)
: array_builder_(array_builder) {}
Bytecode GetBytecode() const {
// Returns the previous bytecode in the same basicblock. If there is none it
// returns Bytecode::kLast.
if (!array_builder_.LastBytecodeInSameBlock()) {
return Bytecode::kLast;
}
return Bytecodes::FromByte(
array_builder_.bytecodes()->at(array_builder_.last_bytecode_start_));
}
uint32_t GetOperand(int operand_index) const {
Bytecode bytecode = GetBytecode();
DCHECK_GE(operand_index, 0);
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode));
size_t operand_offset =
array_builder_.last_bytecode_start_ +
Bytecodes::GetOperandOffset(bytecode, operand_index);
OperandSize size = Bytecodes::GetOperandSize(bytecode, operand_index);
switch (size) {
default:
case OperandSize::kNone:
UNREACHABLE();
case OperandSize::kByte:
return static_cast<uint32_t>(
array_builder_.bytecodes()->at(operand_offset));
case OperandSize::kShort:
uint16_t operand =
(array_builder_.bytecodes()->at(operand_offset) << 8) +
array_builder_.bytecodes()->at(operand_offset + 1);
return static_cast<uint32_t>(operand);
}
}
Handle<Object> GetConstantForIndexOperand(int operand_index) const {
return array_builder_.constants_.at(GetOperand(operand_index));
}
private:
const BytecodeArrayBuilder& array_builder_;
};
BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone)
: isolate_(isolate), : isolate_(isolate),
zone_(zone), zone_(zone),
...@@ -277,6 +324,16 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() { ...@@ -277,6 +324,16 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() {
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadBooleanConstant(bool value) {
if (value) {
LoadTrue();
} else {
LoadFalse();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister( BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
Register reg) { Register reg) {
if (!IsRegisterInAccumulator(reg)) { if (!IsRegisterInAccumulator(reg)) {
...@@ -523,15 +580,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { ...@@ -523,15 +580,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
bool BytecodeArrayBuilder::NeedToBooleanCast() { bool BytecodeArrayBuilder::NeedToBooleanCast() {
if (!LastBytecodeInSameBlock()) { PreviousBytecodeHelper previous_bytecode(*this);
// If the previous bytecode was from a different block return false. switch (previous_bytecode.GetBytecode()) {
return true;
}
// If the previous bytecode puts a boolean in the accumulator return true.
switch (Bytecodes::FromByte(bytecodes()->at(last_bytecode_start_))) {
case Bytecode::kToBoolean: case Bytecode::kToBoolean:
UNREACHABLE(); UNREACHABLE();
// If the previous bytecode puts a boolean in the accumulator return true.
case Bytecode::kLdaTrue: case Bytecode::kLdaTrue:
case Bytecode::kLdaFalse: case Bytecode::kLdaFalse:
case Bytecode::kLogicalNot: case Bytecode::kLogicalNot:
...@@ -547,6 +600,8 @@ bool BytecodeArrayBuilder::NeedToBooleanCast() { ...@@ -547,6 +600,8 @@ bool BytecodeArrayBuilder::NeedToBooleanCast() {
case Bytecode::kTestIn: case Bytecode::kTestIn:
case Bytecode::kForInDone: case Bytecode::kForInDone:
return false; return false;
// Also handles the case where the previous bytecode was in a different
// block.
default: default:
return true; return true;
} }
...@@ -554,11 +609,29 @@ bool BytecodeArrayBuilder::NeedToBooleanCast() { ...@@ -554,11 +609,29 @@ bool BytecodeArrayBuilder::NeedToBooleanCast() {
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() { BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
PreviousBytecodeHelper previous_bytecode(*this);
// If the previous bytecode puts a boolean in the accumulator // If the previous bytecode puts a boolean in the accumulator
// there is no need to emit an instruction. // there is no need to emit an instruction.
if (NeedToBooleanCast()) { if (NeedToBooleanCast()) {
switch (previous_bytecode.GetBytecode()) {
// If the previous bytecode is a constant evaluate it and return false.
case Bytecode::kLdaZero: {
LoadFalse();
break;
}
case Bytecode::kLdaSmi8: {
LoadBooleanConstant(previous_bytecode.GetOperand(0) != 0);
break;
}
case Bytecode::kLdaConstant: {
Handle<Object> object = previous_bytecode.GetConstantForIndexOperand(0);
LoadBooleanConstant(object->BooleanValue());
break;
}
default:
Output(Bytecode::kToBoolean); Output(Bytecode::kToBoolean);
} }
}
return *this; return *this;
} }
...@@ -570,6 +643,20 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() { ...@@ -570,6 +643,20 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() {
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() { BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() {
PreviousBytecodeHelper previous_bytecode(*this);
switch (previous_bytecode.GetBytecode()) {
case Bytecode::kLdaConstantWide:
case Bytecode::kLdaConstant: {
Handle<Object> object = previous_bytecode.GetConstantForIndexOperand(0);
if (object->IsName()) return *this;
break;
}
case Bytecode::kToName:
case Bytecode::kTypeOf:
return *this;
default:
break;
}
Output(Bytecode::kToName); Output(Bytecode::kToName);
return *this; return *this;
} }
...@@ -1002,14 +1089,10 @@ bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { ...@@ -1002,14 +1089,10 @@ bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const {
bool BytecodeArrayBuilder::IsRegisterInAccumulator(Register reg) { bool BytecodeArrayBuilder::IsRegisterInAccumulator(Register reg) {
if (!LastBytecodeInSameBlock()) return false; PreviousBytecodeHelper previous_bytecode(*this);
Bytecode previous_bytecode = if (previous_bytecode.GetBytecode() == Bytecode::kLdar ||
Bytecodes::FromByte(bytecodes()->at(last_bytecode_start_)); previous_bytecode.GetBytecode() == Bytecode::kStar) {
if (previous_bytecode == Bytecode::kLdar || if (reg == Register::FromOperand(previous_bytecode.GetOperand(0))) {
previous_bytecode == Bytecode::kStar) {
size_t operand_offset = last_bytecode_start_ +
Bytecodes::GetOperandOffset(previous_bytecode, 0);
if (reg == Register::FromOperand(bytecodes()->at(operand_offset))) {
return true; return true;
} }
} }
......
...@@ -79,6 +79,7 @@ class BytecodeArrayBuilder { ...@@ -79,6 +79,7 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder& LoadTheHole(); BytecodeArrayBuilder& LoadTheHole();
BytecodeArrayBuilder& LoadTrue(); BytecodeArrayBuilder& LoadTrue();
BytecodeArrayBuilder& LoadFalse(); BytecodeArrayBuilder& LoadFalse();
BytecodeArrayBuilder& LoadBooleanConstant(bool value);
// Global loads to the accumulator and stores from the accumulator. // Global loads to the accumulator and stores from the accumulator.
BytecodeArrayBuilder& LoadGlobal(size_t name_index, int feedback_slot, BytecodeArrayBuilder& LoadGlobal(size_t name_index, int feedback_slot,
...@@ -286,6 +287,7 @@ class BytecodeArrayBuilder { ...@@ -286,6 +287,7 @@ class BytecodeArrayBuilder {
ZoneSet<int> free_temporaries_; ZoneSet<int> free_temporaries_;
class PreviousBytecodeHelper;
friend class TemporaryRegisterScope; friend class TemporaryRegisterScope;
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder); DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
}; };
......
...@@ -706,6 +706,16 @@ TEST(BytecodeGraphBuilderGlobals) { ...@@ -706,6 +706,16 @@ TEST(BytecodeGraphBuilderGlobals) {
} }
TEST(BytecodeGraphBuilderCast) {
// TODO(mythria): tests for ToBoolean, ToObject, ToName, ToNumber.
// They need other unimplemented features to test.
// ToBoolean -> If
// ToObject -> ForIn
// ToNumber -> Inc/Dec
// ToName -> CreateObjectLiteral
}
TEST(BytecodeGraphBuilderLogicalNot) { TEST(BytecodeGraphBuilderLogicalNot) {
HandleAndZoneScope scope; HandleAndZoneScope scope;
Isolate* isolate = scope.main_isolate(); Isolate* isolate = scope.main_isolate();
......
...@@ -3321,7 +3321,7 @@ TEST(ObjectLiterals) { ...@@ -3321,7 +3321,7 @@ TEST(ObjectLiterals) {
{"var n = 'name'; return { [n]: 'val', get a() { }, set a(b) {} };", {"var n = 'name'; return { [n]: 'val', get a() { }, set a(b) {} };",
5 * kPointerSize, 5 * kPointerSize,
1, 1,
67, 65,
{ {
B(LdaConstant), U8(0), // B(LdaConstant), U8(0), //
B(Star), R(0), // B(Star), R(0), //
...@@ -3338,7 +3338,6 @@ TEST(ObjectLiterals) { ...@@ -3338,7 +3338,6 @@ TEST(ObjectLiterals) {
B(CallRuntime), U16(Runtime::kDefineDataPropertyUnchecked), R(1), // B(CallRuntime), U16(Runtime::kDefineDataPropertyUnchecked), R(1), //
U8(4), // U8(4), //
B(LdaConstant), U8(3), // B(LdaConstant), U8(3), //
B(ToName), //
B(Star), R(2), // B(Star), R(2), //
B(CreateClosure), U8(4), U8(0), // B(CreateClosure), U8(4), U8(0), //
B(Star), R(3), // B(Star), R(3), //
...@@ -3347,7 +3346,6 @@ TEST(ObjectLiterals) { ...@@ -3347,7 +3346,6 @@ TEST(ObjectLiterals) {
B(CallRuntime), U16(Runtime::kDefineGetterPropertyUnchecked), // B(CallRuntime), U16(Runtime::kDefineGetterPropertyUnchecked), //
R(1), U8(4), // R(1), U8(4), //
B(LdaConstant), U8(3), // B(LdaConstant), U8(3), //
B(ToName), //
B(Star), R(2), // B(Star), R(2), //
B(CreateClosure), U8(5), U8(0), // B(CreateClosure), U8(5), U8(0), //
B(Star), R(3), // B(Star), R(3), //
......
...@@ -2075,8 +2075,6 @@ IS_UNOP_MATCHER(NumberToInt32) ...@@ -2075,8 +2075,6 @@ IS_UNOP_MATCHER(NumberToInt32)
IS_UNOP_MATCHER(NumberToUint32) IS_UNOP_MATCHER(NumberToUint32)
IS_UNOP_MATCHER(ObjectIsSmi) IS_UNOP_MATCHER(ObjectIsSmi)
IS_UNOP_MATCHER(Word32Clz) IS_UNOP_MATCHER(Word32Clz)
IS_UNOP_MATCHER(JSUnaryNot)
IS_UNOP_MATCHER(JSTypeOf)
#undef IS_UNOP_MATCHER #undef IS_UNOP_MATCHER
} // namespace compiler } // namespace compiler
......
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