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(
}
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(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
BuildCastOperator(javascript()->ToBoolean(), iterator);
}
void BytecodeGraphBuilder::VisitToName(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
BuildCastOperator(javascript()->ToName(), iterator);
}
void BytecodeGraphBuilder::VisitToNumber(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
BuildCastOperator(javascript()->ToNumber(), iterator);
}
void BytecodeGraphBuilder::VisitToObject(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
BuildCastOperator(javascript()->ToObject(), iterator);
}
......
......@@ -117,6 +117,8 @@ class BytecodeGraphBuilder {
void BuildCompareOp(const Operator* op,
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
// new nodes.
......
......@@ -8,6 +8,53 @@ namespace v8 {
namespace internal {
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)
: isolate_(isolate),
zone_(zone),
......@@ -277,6 +324,16 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() {
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadBooleanConstant(bool value) {
if (value) {
LoadTrue();
} else {
LoadFalse();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
Register reg) {
if (!IsRegisterInAccumulator(reg)) {
......@@ -523,15 +580,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
bool BytecodeArrayBuilder::NeedToBooleanCast() {
if (!LastBytecodeInSameBlock()) {
// If the previous bytecode was from a different block return false.
return true;
}
// If the previous bytecode puts a boolean in the accumulator return true.
switch (Bytecodes::FromByte(bytecodes()->at(last_bytecode_start_))) {
PreviousBytecodeHelper previous_bytecode(*this);
switch (previous_bytecode.GetBytecode()) {
case Bytecode::kToBoolean:
UNREACHABLE();
// If the previous bytecode puts a boolean in the accumulator return true.
case Bytecode::kLdaTrue:
case Bytecode::kLdaFalse:
case Bytecode::kLogicalNot:
......@@ -547,6 +600,8 @@ bool BytecodeArrayBuilder::NeedToBooleanCast() {
case Bytecode::kTestIn:
case Bytecode::kForInDone:
return false;
// Also handles the case where the previous bytecode was in a different
// block.
default:
return true;
}
......@@ -554,10 +609,28 @@ bool BytecodeArrayBuilder::NeedToBooleanCast() {
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
PreviousBytecodeHelper previous_bytecode(*this);
// If the previous bytecode puts a boolean in the accumulator
// there is no need to emit an instruction.
if (NeedToBooleanCast()) {
Output(Bytecode::kToBoolean);
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);
}
}
return *this;
}
......@@ -570,6 +643,20 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() {
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);
return *this;
}
......@@ -1002,14 +1089,10 @@ bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const {
bool BytecodeArrayBuilder::IsRegisterInAccumulator(Register reg) {
if (!LastBytecodeInSameBlock()) return false;
Bytecode previous_bytecode =
Bytecodes::FromByte(bytecodes()->at(last_bytecode_start_));
if (previous_bytecode == Bytecode::kLdar ||
previous_bytecode == Bytecode::kStar) {
size_t operand_offset = last_bytecode_start_ +
Bytecodes::GetOperandOffset(previous_bytecode, 0);
if (reg == Register::FromOperand(bytecodes()->at(operand_offset))) {
PreviousBytecodeHelper previous_bytecode(*this);
if (previous_bytecode.GetBytecode() == Bytecode::kLdar ||
previous_bytecode.GetBytecode() == Bytecode::kStar) {
if (reg == Register::FromOperand(previous_bytecode.GetOperand(0))) {
return true;
}
}
......
......@@ -79,6 +79,7 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder& LoadTheHole();
BytecodeArrayBuilder& LoadTrue();
BytecodeArrayBuilder& LoadFalse();
BytecodeArrayBuilder& LoadBooleanConstant(bool value);
// Global loads to the accumulator and stores from the accumulator.
BytecodeArrayBuilder& LoadGlobal(size_t name_index, int feedback_slot,
......@@ -286,6 +287,7 @@ class BytecodeArrayBuilder {
ZoneSet<int> free_temporaries_;
class PreviousBytecodeHelper;
friend class TemporaryRegisterScope;
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
};
......
......@@ -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) {
HandleAndZoneScope scope;
Isolate* isolate = scope.main_isolate();
......
......@@ -3321,7 +3321,7 @@ TEST(ObjectLiterals) {
{"var n = 'name'; return { [n]: 'val', get a() { }, set a(b) {} };",
5 * kPointerSize,
1,
67,
65,
{
B(LdaConstant), U8(0), //
B(Star), R(0), //
......@@ -3338,7 +3338,6 @@ TEST(ObjectLiterals) {
B(CallRuntime), U16(Runtime::kDefineDataPropertyUnchecked), R(1), //
U8(4), //
B(LdaConstant), U8(3), //
B(ToName), //
B(Star), R(2), //
B(CreateClosure), U8(4), U8(0), //
B(Star), R(3), //
......@@ -3347,7 +3346,6 @@ TEST(ObjectLiterals) {
B(CallRuntime), U16(Runtime::kDefineGetterPropertyUnchecked), //
R(1), U8(4), //
B(LdaConstant), U8(3), //
B(ToName), //
B(Star), R(2), //
B(CreateClosure), U8(5), U8(0), //
B(Star), R(3), //
......
......@@ -2075,8 +2075,6 @@ IS_UNOP_MATCHER(NumberToInt32)
IS_UNOP_MATCHER(NumberToUint32)
IS_UNOP_MATCHER(ObjectIsSmi)
IS_UNOP_MATCHER(Word32Clz)
IS_UNOP_MATCHER(JSUnaryNot)
IS_UNOP_MATCHER(JSTypeOf)
#undef IS_UNOP_MATCHER
} // 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