diff --git a/src/compiler/graph.h b/src/compiler/graph.h index 7b38035a9c..d619da252f 100644 --- a/src/compiler/graph.h +++ b/src/compiler/graph.h @@ -16,8 +16,10 @@ namespace v8 { namespace internal { namespace compiler { +// Forward declarations. class GraphDecorator; + class Graph : public ZoneObject { public: explicit Graph(Zone* zone); @@ -28,7 +30,7 @@ class Graph : public ZoneObject { // Factories for nodes with static input counts. Node* NewNode(const Operator* op) { - return NewNode(op, 0, static_cast(NULL)); + return NewNode(op, 0, static_cast(nullptr)); } Node* NewNode(const Operator* op, Node* n1) { return NewNode(op, 1, &n1); } Node* NewNode(const Operator* op, Node* n1, Node* n2) { @@ -60,7 +62,7 @@ class Graph : public ZoneObject { } template - void VisitNodeInputsFromEnd(Visitor* visitor); + inline void VisitNodeInputsFromEnd(Visitor* visitor); Zone* zone() const { return zone_; } Node* start() const { return start_; } diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc index 28580a1a3d..263b0feedd 100644 --- a/src/compiler/js-builtin-reducer.cc +++ b/src/compiler/js-builtin-reducer.cc @@ -5,6 +5,7 @@ #include "src/compiler/diamond.h" #include "src/compiler/graph-inl.h" #include "src/compiler/js-builtin-reducer.h" +#include "src/compiler/js-graph.h" #include "src/compiler/node-matchers.h" #include "src/compiler/node-properties-inl.h" #include "src/types.h" @@ -96,6 +97,10 @@ class JSCallReduction { }; +JSBuiltinReducer::JSBuiltinReducer(JSGraph* jsgraph) + : jsgraph_(jsgraph), simplified_(jsgraph->zone()) {} + + // ECMA-262, section 15.8.2.1. Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) { JSCallReduction r(node); @@ -232,6 +237,19 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { return NoChange(); } + +Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); } + + +CommonOperatorBuilder* JSBuiltinReducer::common() const { + return jsgraph()->common(); +} + + +MachineOperatorBuilder* JSBuiltinReducer::machine() const { + return jsgraph()->machine(); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/src/compiler/js-builtin-reducer.h b/src/compiler/js-builtin-reducer.h index 4b3be29caa..ac6f266eed 100644 --- a/src/compiler/js-builtin-reducer.h +++ b/src/compiler/js-builtin-reducer.h @@ -6,30 +6,26 @@ #define V8_COMPILER_JS_BUILTIN_REDUCER_H_ #include "src/compiler/graph-reducer.h" -#include "src/compiler/js-graph.h" -#include "src/compiler/machine-operator.h" -#include "src/compiler/node.h" #include "src/compiler/simplified-operator.h" namespace v8 { namespace internal { namespace compiler { +// Forward declarations. +class CommonOperatorBuilder; +class JSGraph; +class MachineOperatorBuilder; + + class JSBuiltinReducer FINAL : public Reducer { public: - explicit JSBuiltinReducer(JSGraph* jsgraph) - : jsgraph_(jsgraph), simplified_(jsgraph->zone()) {} - virtual ~JSBuiltinReducer() {} + explicit JSBuiltinReducer(JSGraph* jsgraph); + ~JSBuiltinReducer() FINAL {} - virtual Reduction Reduce(Node* node) OVERRIDE; + Reduction Reduce(Node* node) FINAL; private: - JSGraph* jsgraph() const { return jsgraph_; } - Graph* graph() const { return jsgraph_->graph(); } - CommonOperatorBuilder* common() const { return jsgraph_->common(); } - MachineOperatorBuilder* machine() const { return jsgraph_->machine(); } - SimplifiedOperatorBuilder* simplified() { return &simplified_; } - Reduction ReduceMathAbs(Node* node); Reduction ReduceMathSqrt(Node* node); Reduction ReduceMathMax(Node* node); @@ -38,6 +34,12 @@ class JSBuiltinReducer FINAL : public Reducer { Reduction ReduceMathFloor(Node* node); Reduction ReduceMathCeil(Node* node); + JSGraph* jsgraph() const { return jsgraph_; } + Graph* graph() const; + CommonOperatorBuilder* common() const; + MachineOperatorBuilder* machine() const; + SimplifiedOperatorBuilder* simplified() { return &simplified_; } + JSGraph* jsgraph_; SimplifiedOperatorBuilder simplified_; }; diff --git a/src/compiler/js-graph.h b/src/compiler/js-graph.h index 064359423f..040a745e3c 100644 --- a/src/compiler/js-graph.h +++ b/src/compiler/js-graph.h @@ -115,6 +115,7 @@ class JSGraph : public ZoneObject { Graph* graph() { return graph_; } Zone* zone() { return graph()->zone(); } Isolate* isolate() { return zone()->isolate(); } + Factory* factory() { return isolate()->factory(); } void GetCachedNodes(NodeVector* nodes); @@ -140,8 +141,6 @@ class JSGraph : public ZoneObject { Node* ImmovableHeapConstant(Handle value); Node* NumberConstant(double value); - Factory* factory() { return isolate()->factory(); } - DISALLOW_COPY_AND_ASSIGN(JSGraph); }; diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index ce3ecc59d4..9094a66208 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -4,7 +4,7 @@ #include "src/compiler/access-builder.h" #include "src/compiler/graph-inl.h" -#include "src/compiler/js-builtin-reducer.h" +#include "src/compiler/js-graph.h" #include "src/compiler/js-typed-lowering.h" #include "src/compiler/node-aux-data-inl.h" #include "src/compiler/node-matchers.h" @@ -32,28 +32,27 @@ static void RelaxEffects(Node* node) { JSTypedLowering::JSTypedLowering(JSGraph* jsgraph) : jsgraph_(jsgraph), simplified_(jsgraph->zone()) { - Factory* factory = zone()->isolate()->factory(); - Handle zero = factory->NewNumber(0.0); - Handle one = factory->NewNumber(1.0); - zero_range_ = Type::Range(zero, zero, zone()); - one_range_ = Type::Range(one, one, zone()); - Handle thirtyone = factory->NewNumber(31.0); - zero_thirtyone_range_ = Type::Range(zero, thirtyone, zone()); + Handle zero = factory()->NewNumber(0.0); + Handle one = factory()->NewNumber(1.0); + zero_range_ = Type::Range(zero, zero, graph()->zone()); + one_range_ = Type::Range(one, one, graph()->zone()); + Handle thirtyone = factory()->NewNumber(31.0); + zero_thirtyone_range_ = Type::Range(zero, thirtyone, graph()->zone()); // TODO(jarin): Can we have a correctification of the stupid type system? // These stupid work-arounds are just stupid! shifted_int32_ranges_[0] = Type::Signed32(); if (SmiValuesAre31Bits()) { shifted_int32_ranges_[1] = Type::SignedSmall(); for (size_t k = 2; k < arraysize(shifted_int32_ranges_); ++k) { - Handle min = factory->NewNumber(kMinInt / (1 << k)); - Handle max = factory->NewNumber(kMaxInt / (1 << k)); - shifted_int32_ranges_[k] = Type::Range(min, max, zone()); + Handle min = factory()->NewNumber(kMinInt / (1 << k)); + Handle max = factory()->NewNumber(kMaxInt / (1 << k)); + shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); } } else { for (size_t k = 1; k < arraysize(shifted_int32_ranges_); ++k) { - Handle min = factory->NewNumber(kMinInt / (1 << k)); - Handle max = factory->NewNumber(kMaxInt / (1 << k)); - shifted_int32_ranges_[k] = Type::Range(min, max, zone()); + Handle min = factory()->NewNumber(kMinInt / (1 << k)); + Handle max = factory()->NewNumber(kMaxInt / (1 << k)); + shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); } } } @@ -69,7 +68,7 @@ Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) { // JSOperator. This class manages the rewriting of context, control, and effect // dependencies during lowering of a binop and contains numerous helper // functions for matching the types of inputs to an operation. -class JSBinopReduction { +class JSBinopReduction FINAL { public: JSBinopReduction(JSTypedLowering* lowering, Node* node) : lowering_(lowering), @@ -82,9 +81,10 @@ class JSBinopReduction { node_->ReplaceInput(1, ConvertToNumber(right())); } - void ConvertInputsToInt32(bool left_signed, bool right_signed) { - node_->ReplaceInput(0, ConvertToI32(left_signed, left())); - node_->ReplaceInput(1, ConvertToI32(right_signed, right())); + void ConvertInputsToUI32(Signedness left_signedness, + Signedness right_signedness) { + node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); + node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness)); } void ConvertInputsToString() { @@ -93,9 +93,9 @@ class JSBinopReduction { } // Convert inputs for bitwise shift operation (ES5 spec 11.7). - void ConvertInputsForShift(bool left_signed) { - node_->ReplaceInput(0, ConvertToI32(left_signed, left())); - Node* rnum = ConvertToI32(false, right()); + void ConvertInputsForShift(Signedness left_signedness) { + node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); + Node* rnum = ConvertToUI32(right(), kUnsigned); Type* rnum_type = NodeProperties::GetBounds(rnum).upper; if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) { rnum = graph()->NewNode(machine()->Word32And(), rnum, @@ -205,18 +205,21 @@ class JSBinopReduction { return n; } - Node* ConvertToI32(bool is_signed, Node* node) { + Node* ConvertToUI32(Node* node, Signedness signedness) { // Avoid introducing too many eager NumberToXXnt32() operations. node = ConvertToNumber(node); - Type* type = is_signed ? Type::Signed32() : Type::Unsigned32(); - Type* input_type = NodeProperties::GetBounds(node).upper; - - if (input_type->Is(type)) return node; // already in the value range. - - const Operator* op = is_signed ? simplified()->NumberToInt32() - : simplified()->NumberToUint32(); - Node* n = graph()->NewNode(op, node); - return n; + Type* type = NodeProperties::GetBounds(node).upper; + if (signedness == kSigned) { + if (!type->Is(Type::Signed32())) { + node = graph()->NewNode(simplified()->NumberToInt32(), node); + } + } else { + DCHECK_EQ(kUnsigned, signedness); + if (!type->Is(Type::Unsigned32())) { + node = graph()->NewNode(simplified()->NumberToUint32(), node); + } + } + return node; } void update_effect(Node* effect) { @@ -231,8 +234,8 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) { // JSAdd(x:number, y:number) => NumberAdd(x, y) return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); } - Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone()); - if (r.BothInputsAre(Type::Primitive()) && r.NeitherInputCanBe(maybe_string)) { + if (r.BothInputsAre(Type::Primitive()) && + r.NeitherInputCanBe(Type::StringOrReceiver())) { // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) r.ConvertInputsToNumber(); return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); @@ -273,7 +276,7 @@ Reduction JSTypedLowering::ReduceJSBitwiseOr(Node* node) { // operations // on some platforms. // TODO(turbofan): make this heuristic configurable for code size. - r.ConvertInputsToInt32(true, true); + r.ConvertInputsToUI32(kSigned, kSigned); return r.ChangeToPureOperator(machine()->Word32Or(), Type::Integral32()); } return NoChange(); @@ -318,9 +321,7 @@ Reduction JSTypedLowering::ReduceNumberBinop(Node* node, } -Reduction JSTypedLowering::ReduceI32Binop(Node* node, bool left_signed, - bool right_signed, - const Operator* intOp) { +Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { JSBinopReduction r(this, node); if (r.BothInputsAre(Type::Primitive())) { // TODO(titzer): some Smi bitwise operations don't really require going @@ -328,18 +329,19 @@ Reduction JSTypedLowering::ReduceI32Binop(Node* node, bool left_signed, // operations // on some platforms. // TODO(turbofan): make this heuristic configurable for code size. - r.ConvertInputsToInt32(left_signed, right_signed); + r.ConvertInputsToUI32(kSigned, kSigned); return r.ChangeToPureOperator(intOp, Type::Integral32()); } return NoChange(); } -Reduction JSTypedLowering::ReduceI32Shift(Node* node, bool left_signed, - const Operator* shift_op) { +Reduction JSTypedLowering::ReduceUI32Shift(Node* node, + Signedness left_signedness, + const Operator* shift_op) { JSBinopReduction r(this, node); if (r.BothInputsAre(Type::Primitive())) { - r.ConvertInputsForShift(left_signed); + r.ConvertInputsForShift(left_signedness); return r.ChangeToPureOperator(shift_op, Type::Integral32()); } return NoChange(); @@ -381,8 +383,8 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) { ... } #endif - Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone()); - if (r.BothInputsAre(Type::Primitive()) && r.OneInputCannotBe(maybe_string)) { + if (r.BothInputsAre(Type::Primitive()) && + r.OneInputCannotBe(Type::StringOrReceiver())) { const Operator* less_than; const Operator* less_than_or_equal; if (r.BothInputsAre(Type::Unsigned32())) { @@ -451,8 +453,7 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { return ReplaceEagerly(node, jsgraph()->BooleanConstant(!invert)); } } - Type* string_or_number = Type::Union(Type::String(), Type::Number(), zone()); - if (r.OneInputCannotBe(string_or_number)) { + if (r.OneInputCannotBe(Type::NumberOrString())) { // For values with canonical representation (i.e. not string nor number) an // empty type intersection means the values cannot be strictly equal. if (!r.left_type()->Maybe(r.right_type())) { @@ -490,115 +491,6 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { } -Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { - if (input->opcode() == IrOpcode::kJSToNumber) { - // Recursively try to reduce the input first. - Reduction result = ReduceJSToNumber(input); - if (result.Changed()) return result; - return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) - } - Type* input_type = NodeProperties::GetBounds(input).upper; - if (input_type->Is(Type::Number())) { - // JSToNumber(x:number) => x - return Changed(input); - } - if (input_type->Is(Type::Undefined())) { - // JSToNumber(undefined) => #NaN - return Replace(jsgraph()->NaNConstant()); - } - if (input_type->Is(Type::Null())) { - // JSToNumber(null) => #0 - return Replace(jsgraph()->ZeroConstant()); - } - if (input_type->Is(Type::Boolean())) { - // JSToNumber(x:boolean) => BooleanToNumber(x) - return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input)); - } - // TODO(turbofan): js-typed-lowering of ToNumber(x:string) - return NoChange(); -} - - -Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { - // Try to reduce the input first. - Node* const input = node->InputAt(0); - Reduction reduction = ReduceJSToNumberInput(input); - if (reduction.Changed()) { - NodeProperties::ReplaceWithValue(node, reduction.replacement()); - return reduction; - } - Type* const input_type = NodeProperties::GetBounds(input).upper; - if (input_type->Is(Type::PlainPrimitive())) { - // Converting a plain primitive to a number has no observable side effects. - RelaxEffects(node); - // JSToNumber(phi(x1,...,xn,control):plain-primitive,context) - // => phi(JSToNumber(x1,no-context),...,JSToNumber(xn,no-context),control) - if (input->opcode() == IrOpcode::kPhi) { - int const input_count = input->InputCount() - 1; - Node* const control = input->InputAt(input_count); - DCHECK_LE(0, input_count); - DCHECK(NodeProperties::IsControl(control)); - DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number())); - DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); - node->set_op(common()->Phi(kMachAnyTagged, input_count)); - for (int i = 0; i < input_count; ++i) { - Node* value = input->InputAt(i); - // Recursively try to reduce the value first. - Reduction reduction = ReduceJSToNumberInput(value); - if (reduction.Changed()) { - value = reduction.replacement(); - } else { - value = graph()->NewNode(javascript()->ToNumber(), value, - jsgraph()->NoContextConstant(), - graph()->start(), graph()->start()); - } - if (i < node->InputCount()) { - node->ReplaceInput(i, value); - } else { - node->AppendInput(graph()->zone(), value); - } - } - if (input_count < node->InputCount()) { - node->ReplaceInput(input_count, control); - } else { - node->AppendInput(graph()->zone(), control); - } - node->TrimInputCount(input_count + 1); - } - return Changed(node); - } - return NoChange(); -} - - -Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { - if (input->opcode() == IrOpcode::kJSToString) { - // Recursively try to reduce the input first. - Reduction result = ReduceJSToStringInput(input->InputAt(0)); - if (result.Changed()) { - RelaxEffects(input); - return result; - } - return Changed(input); // JSToString(JSToString(x)) => JSToString(x) - } - Type* input_type = NodeProperties::GetBounds(input).upper; - if (input_type->Is(Type::String())) { - return Changed(input); // JSToString(x:string) => x - } - if (input_type->Is(Type::Undefined())) { - return Replace(jsgraph()->HeapConstant( - graph()->zone()->isolate()->factory()->undefined_string())); - } - if (input_type->Is(Type::Null())) { - return Replace(jsgraph()->HeapConstant( - graph()->zone()->isolate()->factory()->null_string())); - } - // TODO(turbofan): js-typed-lowering of ToString(x:boolean) - // TODO(turbofan): js-typed-lowering of ToString(x:number) - return NoChange(); -} - - Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { if (input->opcode() == IrOpcode::kJSToBoolean) { // Recursively try to reduce the input first. @@ -727,6 +619,160 @@ Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { } +Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { + if (input->opcode() == IrOpcode::kJSToNumber) { + // Recursively try to reduce the input first. + Reduction result = ReduceJSToNumber(input); + if (result.Changed()) return result; + return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) + } + Type* input_type = NodeProperties::GetBounds(input).upper; + if (input_type->Is(Type::Number())) { + // JSToNumber(x:number) => x + return Changed(input); + } + if (input_type->Is(Type::Undefined())) { + // JSToNumber(undefined) => #NaN + return Replace(jsgraph()->NaNConstant()); + } + if (input_type->Is(Type::Null())) { + // JSToNumber(null) => #0 + return Replace(jsgraph()->ZeroConstant()); + } + if (input_type->Is(Type::Boolean())) { + // JSToNumber(x:boolean) => BooleanToNumber(x) + return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input)); + } + // TODO(turbofan): js-typed-lowering of ToNumber(x:string) + return NoChange(); +} + + +Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { + // Try to reduce the input first. + Node* const input = node->InputAt(0); + Reduction reduction = ReduceJSToNumberInput(input); + if (reduction.Changed()) { + NodeProperties::ReplaceWithValue(node, reduction.replacement()); + return reduction; + } + Type* const input_type = NodeProperties::GetBounds(input).upper; + if (input_type->Is(Type::PlainPrimitive())) { + // Converting a plain primitive to a number has no observable side effects. + RelaxEffects(node); + if (input->opcode() == IrOpcode::kPhi) { + // JSToNumber(phi(x1,...,xn,control):plain-primitive,context) + // => phi(JSToNumber(x1,no-context), + // ..., + // JSToNumber(xn,no-context),control) + int const input_count = input->InputCount() - 1; + Node* const control = input->InputAt(input_count); + DCHECK_LE(0, input_count); + DCHECK(NodeProperties::IsControl(control)); + DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number())); + DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); + node->set_op(common()->Phi(kMachAnyTagged, input_count)); + for (int i = 0; i < input_count; ++i) { + Node* value = input->InputAt(i); + // Recursively try to reduce the value first. + Reduction reduction = ReduceJSToNumberInput(value); + if (reduction.Changed()) { + value = reduction.replacement(); + } else { + // We must be very careful not to introduce cycles when pushing + // operations into phis. It is safe for {value}, since it appears + // as input to the phi that we are replacing, but it's not safe + // to simply reuse the context of the {node}. However, ToNumber() + // does not require a context anyways, so it's safe to discard it + // here and pass the dummy context. + value = graph()->NewNode(javascript()->ToNumber(), value, + jsgraph()->NoContextConstant(), + graph()->start(), graph()->start()); + } + if (i < node->InputCount()) { + node->ReplaceInput(i, value); + } else { + node->AppendInput(graph()->zone(), value); + } + } + if (input_count < node->InputCount()) { + node->ReplaceInput(input_count, control); + } else { + node->AppendInput(graph()->zone(), control); + } + node->TrimInputCount(input_count + 1); + } else if (input->opcode() == IrOpcode::kSelect) { + // JSToNumber(select(c,x1,x2):plain-primitive,context) + // => select(c,JSToNumber(x1,no-context),JSToNumber(x2,no-context)) + int const input_count = input->InputCount(); + BranchHint const input_hint = SelectParametersOf(input->op()).hint(); + DCHECK_EQ(3, input_count); + DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number())); + DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); + node->set_op(common()->Select(kMachAnyTagged, input_hint)); + node->ReplaceInput(0, input->InputAt(0)); + for (int i = 1; i < input_count; ++i) { + Node* value = input->InputAt(i); + // Recursively try to reduce the value first. + Reduction reduction = ReduceJSToNumberInput(value); + if (reduction.Changed()) { + value = reduction.replacement(); + } else { + // We must be very careful not to introduce cycles when pushing + // operations into selects. It is safe for {value}, since it appears + // as input to the select that we are replacing, but it's not safe + // to simply reuse the context of the {node}. However, ToNumber() + // does not require a context anyways, so it's safe to discard it + // here and pass the dummy context. + value = graph()->NewNode(javascript()->ToNumber(), value, + jsgraph()->NoContextConstant(), + graph()->start(), graph()->start()); + } + node->ReplaceInput(i, value); + } + node->TrimInputCount(input_count); + } + return Changed(node); + } + return NoChange(); +} + + +Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { + if (input->opcode() == IrOpcode::kJSToString) { + // Recursively try to reduce the input first. + Reduction result = ReduceJSToString(input); + if (result.Changed()) return result; + return Changed(input); // JSToString(JSToString(x)) => JSToString(x) + } + Type* input_type = NodeProperties::GetBounds(input).upper; + if (input_type->Is(Type::String())) { + return Changed(input); // JSToString(x:string) => x + } + if (input_type->Is(Type::Undefined())) { + return Replace(jsgraph()->HeapConstant(factory()->undefined_string())); + } + if (input_type->Is(Type::Null())) { + return Replace(jsgraph()->HeapConstant(factory()->null_string())); + } + // TODO(turbofan): js-typed-lowering of ToString(x:boolean) + // TODO(turbofan): js-typed-lowering of ToString(x:number) + return NoChange(); +} + + +Reduction JSTypedLowering::ReduceJSToString(Node* node) { + // Try to reduce the input first. + Node* const input = node->InputAt(0); + Reduction reduction = ReduceJSToStringInput(input); + if (reduction.Changed()) { + NodeProperties::ReplaceWithValue(node, reduction.replacement()); + return reduction; + } + return NoChange(); +} + + Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { Node* key = NodeProperties::GetValueInput(node, 1); Node* base = NodeProperties::GetValueInput(node, 0); @@ -888,15 +934,6 @@ Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) { } -static Reduction ReplaceWithReduction(Node* node, Reduction reduction) { - if (reduction.Changed()) { - NodeProperties::ReplaceWithValue(node, reduction.replacement()); - return reduction; - } - return Reducer::NoChange(); -} - - Reduction JSTypedLowering::Reduce(Node* node) { // Check if the output type is a singleton. In that case we already know the // result value and can simply replace the node unless there are effects. @@ -925,15 +962,15 @@ Reduction JSTypedLowering::Reduce(Node* node) { case IrOpcode::kJSBitwiseOr: return ReduceJSBitwiseOr(node); case IrOpcode::kJSBitwiseXor: - return ReduceI32Binop(node, true, true, machine()->Word32Xor()); + return ReduceInt32Binop(node, machine()->Word32Xor()); case IrOpcode::kJSBitwiseAnd: - return ReduceI32Binop(node, true, true, machine()->Word32And()); + return ReduceInt32Binop(node, machine()->Word32And()); case IrOpcode::kJSShiftLeft: - return ReduceI32Shift(node, true, machine()->Word32Shl()); + return ReduceUI32Shift(node, kSigned, machine()->Word32Shl()); case IrOpcode::kJSShiftRight: - return ReduceI32Shift(node, true, machine()->Word32Sar()); + return ReduceUI32Shift(node, kSigned, machine()->Word32Sar()); case IrOpcode::kJSShiftRightLogical: - return ReduceI32Shift(node, false, machine()->Word32Shr()); + return ReduceUI32Shift(node, kUnsigned, machine()->Word32Shr()); case IrOpcode::kJSAdd: return ReduceJSAdd(node); case IrOpcode::kJSSubtract: @@ -961,8 +998,7 @@ Reduction JSTypedLowering::Reduce(Node* node) { case IrOpcode::kJSToNumber: return ReduceJSToNumber(node); case IrOpcode::kJSToString: - return ReplaceWithReduction(node, - ReduceJSToStringInput(node->InputAt(0))); + return ReduceJSToString(node); case IrOpcode::kJSLoadProperty: return ReduceJSLoadProperty(node); case IrOpcode::kJSStoreProperty: @@ -971,8 +1007,6 @@ Reduction JSTypedLowering::Reduce(Node* node) { return ReduceJSLoadContext(node); case IrOpcode::kJSStoreContext: return ReduceJSStoreContext(node); - case IrOpcode::kJSCallFunction: - return JSBuiltinReducer(jsgraph()).Reduce(node); default: break; } @@ -986,6 +1020,27 @@ Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { jsgraph()->Int32Constant(rhs)); } + +Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } + + +Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); } + + +JSOperatorBuilder* JSTypedLowering::javascript() const { + return jsgraph()->javascript(); +} + + +CommonOperatorBuilder* JSTypedLowering::common() const { + return jsgraph()->common(); +} + + +MachineOperatorBuilder* JSTypedLowering::machine() const { + return jsgraph()->machine(); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/src/compiler/js-typed-lowering.h b/src/compiler/js-typed-lowering.h index 47571d49bc..015cfe0644 100644 --- a/src/compiler/js-typed-lowering.h +++ b/src/compiler/js-typed-lowering.h @@ -6,26 +6,26 @@ #define V8_COMPILER_JS_TYPED_LOWERING_H_ #include "src/compiler/graph-reducer.h" -#include "src/compiler/js-graph.h" -#include "src/compiler/machine-operator.h" -#include "src/compiler/node.h" #include "src/compiler/simplified-operator.h" namespace v8 { namespace internal { namespace compiler { +// Forward declarations. +class CommonOperatorBuilder; +class JSGraph; +class JSOperatorBuilder; +class MachineOperatorBuilder; + + // Lowers JS-level operators to simplified operators based on types. class JSTypedLowering FINAL : public Reducer { public: explicit JSTypedLowering(JSGraph* jsgraph); - ~JSTypedLowering() {} + ~JSTypedLowering() FINAL {} - Reduction Reduce(Node* node) OVERRIDE; - - JSGraph* jsgraph() { return jsgraph_; } - Graph* graph() { return jsgraph_->graph(); } - Zone* zone() { return jsgraph_->zone(); } + Reduction Reduce(Node* node) FINAL; private: friend class JSBinopReduction; @@ -41,23 +41,26 @@ class JSTypedLowering FINAL : public Reducer { Reduction ReduceJSStoreContext(Node* node); Reduction ReduceJSEqual(Node* node, bool invert); Reduction ReduceJSStrictEqual(Node* node, bool invert); + Reduction ReduceJSToBooleanInput(Node* input); + Reduction ReduceJSToBoolean(Node* node); Reduction ReduceJSToNumberInput(Node* input); Reduction ReduceJSToNumber(Node* node); Reduction ReduceJSToStringInput(Node* input); - Reduction ReduceJSToBooleanInput(Node* input); - Reduction ReduceJSToBoolean(Node* node); + Reduction ReduceJSToString(Node* node); Reduction ReduceNumberBinop(Node* node, const Operator* numberOp); - Reduction ReduceI32Binop(Node* node, bool left_signed, bool right_signed, - const Operator* intOp); - Reduction ReduceI32Shift(Node* node, bool left_signed, - const Operator* shift_op); + Reduction ReduceInt32Binop(Node* node, const Operator* intOp); + Reduction ReduceUI32Shift(Node* node, Signedness left_signedness, + const Operator* shift_op); Node* Word32Shl(Node* const lhs, int32_t const rhs); - JSOperatorBuilder* javascript() { return jsgraph_->javascript(); } - CommonOperatorBuilder* common() { return jsgraph_->common(); } + Factory* factory() const; + Graph* graph() const; + JSGraph* jsgraph() const { return jsgraph_; } + JSOperatorBuilder* javascript() const; + CommonOperatorBuilder* common() const; SimplifiedOperatorBuilder* simplified() { return &simplified_; } - MachineOperatorBuilder* machine() { return jsgraph_->machine(); } + MachineOperatorBuilder* machine() const; JSGraph* jsgraph_; SimplifiedOperatorBuilder simplified_; diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc index eb0d15bee4..5515babdca 100644 --- a/src/compiler/pipeline.cc +++ b/src/compiler/pipeline.cc @@ -18,6 +18,7 @@ #include "src/compiler/graph-visualizer.h" #include "src/compiler/instruction.h" #include "src/compiler/instruction-selector.h" +#include "src/compiler/js-builtin-reducer.h" #include "src/compiler/js-context-specialization.h" #include "src/compiler/js-generic-lowering.h" #include "src/compiler/js-inlining.h" @@ -417,11 +418,13 @@ struct TypedLoweringPhase { SourcePosition::Unknown()); ValueNumberingReducer vn_reducer(temp_zone); LoadElimination load_elimination; - JSTypedLowering lowering(data->jsgraph()); + JSBuiltinReducer builtin_reducer(data->jsgraph()); + JSTypedLowering typed_lowering(data->jsgraph()); SimplifiedOperatorReducer simple_reducer(data->jsgraph()); GraphReducer graph_reducer(data->graph(), temp_zone); graph_reducer.AddReducer(&vn_reducer); - graph_reducer.AddReducer(&lowering); + graph_reducer.AddReducer(&builtin_reducer); + graph_reducer.AddReducer(&typed_lowering); graph_reducer.AddReducer(&load_elimination); graph_reducer.AddReducer(&simple_reducer); graph_reducer.ReduceGraph(); diff --git a/src/types.h b/src/types.h index e9fc5d6b79..4b7d8ba979 100644 --- a/src/types.h +++ b/src/types.h @@ -231,6 +231,7 @@ namespace internal { V(Detectable, kDetectableReceiver | kNumber | kName) \ V(Object, kDetectableObject | kUndetectable) \ V(Receiver, kObject | kProxy) \ + V(StringOrReceiver, kString | kReceiver) \ V(Unique, kBoolean | kUniqueName | kNull | kUndefined | \ kReceiver) \ V(NonNumber, kUnique | kString | kInternal) \ diff --git a/test/cctest/compiler/test-js-typed-lowering.cc b/test/cctest/compiler/test-js-typed-lowering.cc index 667ed61d1b..11a7215e15 100644 --- a/test/cctest/compiler/test-js-typed-lowering.cc +++ b/test/cctest/compiler/test-js-typed-lowering.cc @@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/v8.h" -#include "test/cctest/cctest.h" - #include "src/compiler/graph-inl.h" +#include "src/compiler/js-graph.h" #include "src/compiler/js-typed-lowering.h" +#include "src/compiler/machine-operator.h" #include "src/compiler/node-properties-inl.h" #include "src/compiler/opcodes.h" #include "src/compiler/typer.h" +#include "test/cctest/cctest.h" using namespace v8::internal; using namespace v8::internal::compiler;