r.ConvertInputsToNumber(frame_state);
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
}
-#if 0
- // TODO(turbofan): Lowering of StringAdd is disabled for now because:
- // a) The inserted ToString operation screws up valueOf vs. toString order.
- // b) Deoptimization at ToString doesn't have corresponding bailout id.
- // c) Our current StringAddStub is actually non-pure and requires context.
- if ((r.OneInputIs(Type::String()) && !r.IsStrong()) ||
- r.BothInputsAre(Type::String())) {
- // JSAdd(x:string, y:string) => StringAdd(x, y)
- // JSAdd(x:string, y) => StringAdd(x, ToString(y))
- // JSAdd(x, y:string) => StringAdd(ToString(x), y)
- r.ConvertInputsToString();
- return r.ChangeToPureOperator(simplified()->StringAdd());
- }
-#endif
+ if (r.BothInputsAre(Type::String())) {
+ // JSAdd(x:string, y:string) => CallStub[StringAdd](x, y)
+ Callable const callable =
+ CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
+ CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
+ isolate(), graph()->zone(), callable.descriptor(), 0,
+ CallDescriptor::kNeedsFrameState, node->op()->properties());
+ DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node->op()));
+ node->RemoveInput(NodeProperties::FirstFrameStateIndex(node) + 1);
+ node->InsertInput(graph()->zone(), 0,
+ jsgraph()->HeapConstant(callable.code()));
+ node->set_op(common()->Call(desc));
+ return Changed(node);
+ }
return NoChange();
}
Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
+Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
+
+
JSOperatorBuilder* JSTypedLowering::javascript() const {
return jsgraph()->javascript();
}
Factory* factory() const;
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }
+ Isolate* isolate() const;
JSOperatorBuilder* javascript() const;
CommonOperatorBuilder* common() const;
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
V(NumberToInt32) \
V(NumberToUint32) \
V(PlainPrimitiveToNumber) \
- V(StringAdd) \
V(ChangeTaggedToInt32) \
V(ChangeTaggedToUint32) \
V(ChangeTaggedToFloat64) \
if (lower()) lowering->DoStringLessThanOrEqual(node);
break;
}
- case IrOpcode::kStringAdd: {
- VisitBinop(node, kMachAnyTagged, kMachAnyTagged);
- if (lower()) lowering->DoStringAdd(node);
- break;
- }
case IrOpcode::kAllocate: {
ProcessInput(node, 0, kMachAnyTagged);
ProcessRemainingInputs(node, 1);
}
-void SimplifiedLowering::DoStringAdd(Node* node) {
- Operator::Properties properties = node->op()->properties();
- Callable callable = CodeFactory::StringAdd(
- jsgraph()->isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
- CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
- CallDescriptor* desc = Linkage::GetStubCallDescriptor(
- jsgraph()->isolate(), zone(), callable.descriptor(), 0, flags,
- properties);
- node->set_op(common()->Call(desc));
- node->InsertInput(graph()->zone(), 0,
- jsgraph()->HeapConstant(callable.code()));
- node->AppendInput(graph()->zone(), jsgraph()->UndefinedConstant());
- node->AppendInput(graph()->zone(), graph()->start());
- node->AppendInput(graph()->zone(), graph()->start());
-}
-
-
Node* SimplifiedLowering::StringComparison(Node* node, bool requires_ordering) {
Runtime::FunctionId f =
requires_ordering ? Runtime::kStringCompareRT : Runtime::kStringEquals;
void DoStoreBuffer(Node* node);
void DoLoadElement(Node* node);
void DoStoreElement(Node* node);
- void DoStringAdd(Node* node);
void DoStringEqual(Node* node);
void DoStringLessThan(Node* node);
void DoStringLessThanOrEqual(Node* node);
V(StringEqual, Operator::kCommutative, 2) \
V(StringLessThan, Operator::kNoProperties, 2) \
V(StringLessThanOrEqual, Operator::kNoProperties, 2) \
- V(StringAdd, Operator::kNoProperties, 2) \
V(ChangeTaggedToInt32, Operator::kNoProperties, 1) \
V(ChangeTaggedToUint32, Operator::kNoProperties, 1) \
V(ChangeTaggedToFloat64, Operator::kNoProperties, 1) \
const Operator* StringEqual();
const Operator* StringLessThan();
const Operator* StringLessThanOrEqual();
- const Operator* StringAdd();
const Operator* ChangeTaggedToInt32();
const Operator* ChangeTaggedToUint32();
}
-Bounds Typer::Visitor::TypeStringAdd(Node* node) {
- return Bounds(Type::None(zone()), Type::String(zone()));
-}
-
-
namespace {
Type* ChangeRepresentation(Type* type, Type* rep, Zone* zone) {
CheckValueInputIs(node, 1, Type::String());
CheckUpperIs(node, Type::Boolean());
break;
- case IrOpcode::kStringAdd:
- // (String, String) -> String
- CheckValueInputIs(node, 0, Type::String());
- CheckValueInputIs(node, 1, Type::String());
- CheckUpperIs(node, Type::String());
- break;
case IrOpcode::kReferenceEqual: {
// (Unique, Any) -> Boolean and
// (Any, Unique) -> Boolean
Node* StringLessThanOrEqual(Node* a, Node* b) {
return NewNode(simplified()->StringLessThanOrEqual(), a, b);
}
- Node* StringAdd(Node* a, Node* b) {
- return NewNode(simplified()->StringAdd(), a, b);
- }
Node* ChangeTaggedToInt32(Node* a) {
return NewNode(simplified()->ChangeTaggedToInt32(), a);
t.CheckLoweringBinop(compare_eq, t.simplified()->StringEqual());
t.CheckLoweringBinop(compare_lt, t.simplified()->StringLessThan());
t.CheckLoweringBinop(compare_le, t.simplified()->StringLessThanOrEqual());
- t.CheckLoweringBinop(IrOpcode::kCall, t.simplified()->StringAdd());
}
}
return reducer.Reduce(node);
}
- Node* EmptyFrameState() {
- MachineOperatorBuilder machine(zone());
- JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine);
- return jsgraph.EmptyFrameState();
- }
-
Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) {
Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer();
Runtime::SetupArrayBuffer(isolate(), buffer, true, bytes, byte_length);
}
}
+#if V8_TURBOFAN_TARGET
+
+// -----------------------------------------------------------------------------
+// JSAdd
+
+
+TEST_F(JSTypedLoweringTest, JSAddWithString) {
+ TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
+ Node* lhs = Parameter(Type::String(), 0);
+ Node* rhs = Parameter(Type::String(), 1);
+ Node* context = Parameter(Type::Any(), 2);
+ Node* frame_state0 = EmptyFrameState();
+ Node* frame_state1 = EmptyFrameState();
+ Node* effect = graph()->start();
+ Node* control = graph()->start();
+ Reduction r = Reduce(graph()->NewNode(javascript()->Add(language_mode), lhs,
+ rhs, context, frame_state0,
+ frame_state1, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(
+ r.replacement(),
+ IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
+ CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE,
+ NOT_TENURED).code())),
+ lhs, rhs, context, frame_state0, effect, control));
+ }
+}
+
// -----------------------------------------------------------------------------
// JSCreateClosure
-#if V8_TURBOFAN_TARGET
+
TEST_F(JSTypedLoweringTest, JSCreateClosure) {
Node* const context = UndefinedConstant();
Node* const effect = graph()->start();
CodeFactory::FastCloneShallowObject(isolate(), 6).code())),
input0, input1, input2, _, context, frame_state, effect, control));
}
-#endif
+
+#endif // V8_TURBOFAN_TARGET
// -----------------------------------------------------------------------------
PURE(StringEqual, Operator::kCommutative, 2),
PURE(StringLessThan, Operator::kNoProperties, 2),
PURE(StringLessThanOrEqual, Operator::kNoProperties, 2),
- PURE(StringAdd, Operator::kNoProperties, 2),
PURE(ChangeTaggedToInt32, Operator::kNoProperties, 1),
PURE(ChangeTaggedToUint32, Operator::kNoProperties, 1),
PURE(ChangeTaggedToFloat64, Operator::kNoProperties, 1),