Commit 3ec1d591 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[gasm] Strengthen typing

This is an initial (and partial) step towards full typing in graph
assembler. It removes all uses of SloppyTNode, starts to introduce
types in the GraphAssembler base class, and makes lambda function
types (for if- and for-builders) more specific.

Plenty of TODOs remain; e.g. checked casts and complete typing of
GraphAssembler are left to follow-up work.

Bug: v8:9972
Change-Id: I780adf83b53ad76beda4726960d95ab6df13e2ce
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1940476
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65241}
parent 9ac62c4d
...@@ -81,6 +81,12 @@ struct is_same<T> : public std::true_type {}; ...@@ -81,6 +81,12 @@ struct is_same<T> : public std::true_type {};
template <typename T, typename... Ts> template <typename T, typename... Ts>
struct is_same<T, T, Ts...> : public is_same<T, Ts...> {}; struct is_same<T, T, Ts...> : public is_same<T, Ts...> {};
// Returns true, iff all values (implicitly converted to bool) are trueish.
template <typename... Args>
constexpr bool all(Args... rest) {
return fold(std::logical_and<>{}, true, rest...);
}
} // namespace base } // namespace base
} // namespace v8 } // namespace v8
......
...@@ -7,6 +7,11 @@ ...@@ -7,6 +7,11 @@
#include "src/codegen/code-factory.h" #include "src/codegen/code-factory.h"
#include "src/compiler/linkage.h" #include "src/compiler/linkage.h"
#include "src/compiler/schedule.h" #include "src/compiler/schedule.h"
// For TNode types.
#include "src/objects/heap-number.h"
#include "src/objects/oddball.h"
#include "src/objects/smi.h"
#include "src/objects/string.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -376,8 +381,9 @@ Node* GraphAssembler::HeapConstant(Handle<HeapObject> object) { ...@@ -376,8 +381,9 @@ Node* GraphAssembler::HeapConstant(Handle<HeapObject> object) {
return AddClonedNode(jsgraph()->HeapConstant(object)); return AddClonedNode(jsgraph()->HeapConstant(object));
} }
Node* GraphAssembler::NumberConstant(double value) { TNode<Number> GraphAssembler::NumberConstant(double value) {
return AddClonedNode(jsgraph()->Constant(value)); return TNode<Number>::UncheckedCast(
AddClonedNode(jsgraph()->Constant(value)));
} }
Node* GraphAssembler::ExternalConstant(ExternalReference ref) { Node* GraphAssembler::ExternalConstant(ExternalReference ref) {
...@@ -393,15 +399,17 @@ Node* GraphAssembler::LoadFramePointer() { ...@@ -393,15 +399,17 @@ Node* GraphAssembler::LoadFramePointer() {
} }
#define SINGLETON_CONST_DEF(Name) \ #define SINGLETON_CONST_DEF(Name) \
Node* GraphAssembler::Name##Constant() { \ TNode<Object> GraphAssembler::Name##Constant() { \
return AddClonedNode(jsgraph()->Name##Constant()); \ return TNode<Object>::UncheckedCast( \
AddClonedNode(jsgraph()->Name##Constant())); \
} }
JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DEF) JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DEF)
#undef SINGLETON_CONST_DEF #undef SINGLETON_CONST_DEF
#define SINGLETON_CONST_TEST_DEF(Name) \ #define SINGLETON_CONST_TEST_DEF(Name) \
Node* GraphAssembler::Is##Name(Node* value) { \ TNode<Boolean> GraphAssembler::Is##Name(TNode<Object> value) { \
return ReferenceEqual(value, Name##Constant()); \ return TNode<Boolean>::UncheckedCast( \
ReferenceEqual(value, Name##Constant())); \
} }
JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_TEST_DEF) JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_TEST_DEF)
#undef SINGLETON_CONST_TEST_DEF #undef SINGLETON_CONST_TEST_DEF
...@@ -503,46 +511,54 @@ Node* GraphAssembler::StoreElement(ElementAccess const& access, Node* object, ...@@ -503,46 +511,54 @@ Node* GraphAssembler::StoreElement(ElementAccess const& access, Node* object,
index, value, effect(), control())); index, value, effect(), control()));
} }
Node* GraphAssembler::StringLength(Node* string) { TNode<Number> GraphAssembler::StringLength(TNode<String> string) {
return AddNode(graph()->NewNode(simplified()->StringLength(), string)); return AddNode<Number>(
graph()->NewNode(simplified()->StringLength(), string));
} }
Node* GraphAssembler::ReferenceEqual(Node* lhs, Node* rhs) { Node* GraphAssembler::ReferenceEqual(Node* lhs, Node* rhs) {
return AddNode(graph()->NewNode(simplified()->ReferenceEqual(), lhs, rhs)); return AddNode(graph()->NewNode(simplified()->ReferenceEqual(), lhs, rhs));
} }
Node* GraphAssembler::NumberMin(Node* lhs, Node* rhs) { TNode<Number> GraphAssembler::NumberMin(TNode<Number> lhs, TNode<Number> rhs) {
return AddNode(graph()->NewNode(simplified()->NumberMin(), lhs, rhs)); return AddNode<Number>(graph()->NewNode(simplified()->NumberMin(), lhs, rhs));
} }
Node* GraphAssembler::NumberMax(Node* lhs, Node* rhs) { TNode<Number> GraphAssembler::NumberMax(TNode<Number> lhs, TNode<Number> rhs) {
return AddNode(graph()->NewNode(simplified()->NumberMax(), lhs, rhs)); return AddNode<Number>(graph()->NewNode(simplified()->NumberMax(), lhs, rhs));
} }
Node* GraphAssembler::NumberAdd(Node* lhs, Node* rhs) { TNode<Number> GraphAssembler::NumberAdd(TNode<Number> lhs, TNode<Number> rhs) {
return AddNode(graph()->NewNode(simplified()->NumberAdd(), lhs, rhs)); return AddNode<Number>(graph()->NewNode(simplified()->NumberAdd(), lhs, rhs));
} }
Node* GraphAssembler::NumberSubtract(Node* lhs, Node* rhs) { TNode<Number> GraphAssembler::NumberSubtract(TNode<Number> lhs,
return AddNode(graph()->NewNode(simplified()->NumberSubtract(), lhs, rhs)); TNode<Number> rhs) {
return AddNode<Number>(
graph()->NewNode(simplified()->NumberSubtract(), lhs, rhs));
} }
Node* GraphAssembler::NumberLessThan(Node* lhs, Node* rhs) { TNode<Boolean> GraphAssembler::NumberLessThan(TNode<Number> lhs,
return AddNode(graph()->NewNode(simplified()->NumberLessThan(), lhs, rhs)); TNode<Number> rhs) {
return AddNode<Boolean>(
graph()->NewNode(simplified()->NumberLessThan(), lhs, rhs));
} }
Node* GraphAssembler::NumberLessThanOrEqual(Node* lhs, Node* rhs) { TNode<Boolean> GraphAssembler::NumberLessThanOrEqual(TNode<Number> lhs,
return AddNode( TNode<Number> rhs) {
return AddNode<Boolean>(
graph()->NewNode(simplified()->NumberLessThanOrEqual(), lhs, rhs)); graph()->NewNode(simplified()->NumberLessThanOrEqual(), lhs, rhs));
} }
Node* GraphAssembler::StringSubstring(Node* string, Node* from, Node* to) { TNode<String> GraphAssembler::StringSubstring(Node* string, Node* from,
return AddNode(graph()->NewNode(simplified()->StringSubstring(), string, from, Node* to) {
to, effect(), control())); return AddNode<String>(graph()->NewNode(
simplified()->StringSubstring(), string, from, to, effect(), control()));
} }
Node* GraphAssembler::ObjectIsCallable(Node* value) { TNode<Boolean> GraphAssembler::ObjectIsCallable(Node* value) {
return AddNode(graph()->NewNode(simplified()->ObjectIsCallable(), value)); return AddNode<Boolean>(
graph()->NewNode(simplified()->ObjectIsCallable(), value));
} }
Node* GraphAssembler::CheckIf(Node* cond, DeoptimizeReason reason) { Node* GraphAssembler::CheckIf(Node* cond, DeoptimizeReason reason) {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_GRAPH_ASSEMBLER_H_ #ifndef V8_COMPILER_GRAPH_ASSEMBLER_H_
#define V8_COMPILER_GRAPH_ASSEMBLER_H_ #define V8_COMPILER_GRAPH_ASSEMBLER_H_
#include "src/codegen/tnode.h"
#include "src/compiler/feedback-source.h" #include "src/compiler/feedback-source.h"
#include "src/compiler/js-graph.h" #include "src/compiler/js-graph.h"
#include "src/compiler/node.h" #include "src/compiler/node.h"
...@@ -15,6 +16,12 @@ namespace internal { ...@@ -15,6 +16,12 @@ namespace internal {
class JSGraph; class JSGraph;
class Graph; class Graph;
class Oddball;
// TODO(jgruber): Currently this is too permissive, but at least it lets us
// document which functions expect JS booleans. If a real Boolean type becomes
// possible in the future, use that instead.
using Boolean = Oddball;
namespace compiler { namespace compiler {
...@@ -212,17 +219,18 @@ class V8_EXPORT_PRIVATE GraphAssembler { ...@@ -212,17 +219,18 @@ class V8_EXPORT_PRIVATE GraphAssembler {
Node* Float64Constant(double value); Node* Float64Constant(double value);
Node* Projection(int index, Node* value); Node* Projection(int index, Node* value);
Node* HeapConstant(Handle<HeapObject> object); Node* HeapConstant(Handle<HeapObject> object);
Node* NumberConstant(double value); TNode<Number> NumberConstant(double value);
Node* CEntryStubConstant(int result_size); Node* CEntryStubConstant(int result_size);
Node* ExternalConstant(ExternalReference ref); Node* ExternalConstant(ExternalReference ref);
Node* LoadFramePointer(); Node* LoadFramePointer();
#define SINGLETON_CONST_DECL(Name) Node* Name##Constant(); #define SINGLETON_CONST_DECL(Name) TNode<Object> Name##Constant();
JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DECL) JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DECL)
#undef SINGLETON_CONST_DECL #undef SINGLETON_CONST_DECL
#define SINGLETON_CONST_TEST_DECL(Name) Node* Is##Name(Node* value); #define SINGLETON_CONST_TEST_DECL(Name) \
TNode<Boolean> Is##Name(TNode<Object> value);
JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_TEST_DECL) JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_TEST_DECL)
#undef SINGLETON_CONST_TEST_DECL #undef SINGLETON_CONST_TEST_DECL
...@@ -259,16 +267,16 @@ class V8_EXPORT_PRIVATE GraphAssembler { ...@@ -259,16 +267,16 @@ class V8_EXPORT_PRIVATE GraphAssembler {
Node* StoreField(FieldAccess const&, Node* object, Node* value); Node* StoreField(FieldAccess const&, Node* object, Node* value);
Node* StoreElement(ElementAccess const&, Node* object, Node* index, Node* StoreElement(ElementAccess const&, Node* object, Node* index,
Node* value); Node* value);
Node* StringLength(Node* string); TNode<Number> StringLength(TNode<String> string);
Node* ReferenceEqual(Node* lhs, Node* rhs); Node* ReferenceEqual(Node* lhs, Node* rhs);
Node* NumberMin(Node* lhs, Node* rhs); TNode<Number> NumberMin(TNode<Number> lhs, TNode<Number> rhs);
Node* NumberMax(Node* lhs, Node* rhs); TNode<Number> NumberMax(TNode<Number> lhs, TNode<Number> rhs);
Node* NumberLessThan(Node* lhs, Node* rhs); TNode<Boolean> NumberLessThan(TNode<Number> lhs, TNode<Number> rhs);
Node* NumberLessThanOrEqual(Node* lhs, Node* rhs); TNode<Boolean> NumberLessThanOrEqual(TNode<Number> lhs, TNode<Number> rhs);
Node* NumberAdd(Node* lhs, Node* rhs); TNode<Number> NumberAdd(TNode<Number> lhs, TNode<Number> rhs);
Node* NumberSubtract(Node* lhs, Node* rhs); TNode<Number> NumberSubtract(TNode<Number> lhs, TNode<Number> rhs);
Node* StringSubstring(Node* string, Node* from, Node* to); TNode<String> StringSubstring(Node* string, Node* from, Node* to);
Node* ObjectIsCallable(Node* value); TNode<Boolean> ObjectIsCallable(Node* value);
Node* CheckIf(Node* cond, DeoptimizeReason reason); Node* CheckIf(Node* cond, DeoptimizeReason reason);
Node* NumberIsFloat64Hole(Node* value); Node* NumberIsFloat64Hole(Node* value);
...@@ -350,6 +358,11 @@ class V8_EXPORT_PRIVATE GraphAssembler { ...@@ -350,6 +358,11 @@ class V8_EXPORT_PRIVATE GraphAssembler {
// and control. // and control.
Node* AddNode(Node* node); Node* AddNode(Node* node);
template <typename T>
TNode<T> AddNode(Node* node) {
return TNode<T>::UncheckedCast(AddNode(node));
}
// Finalizes the {block} being processed by the assembler, returning the // Finalizes the {block} being processed by the assembler, returning the
// finalized block (which may be different from the original block). // finalized block (which may be different from the original block).
BasicBlock* FinalizeCurrentBlock(BasicBlock* block); BasicBlock* FinalizeCurrentBlock(BasicBlock* block);
......
...@@ -64,9 +64,14 @@ class V8_EXPORT_PRIVATE Graph final : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -64,9 +64,14 @@ class V8_EXPORT_PRIVATE Graph final : public NON_EXPORTED_BASE(ZoneObject) {
bool incomplete = false); bool incomplete = false);
// Factory template for nodes with static input counts. // Factory template for nodes with static input counts.
template <typename... Nodes> // Note: Template magic below is used to ensure this method is only considered
Node* NewNode(const Operator* op, Nodes*... nodes) { // for argument types convertible to Node* during overload resoluation.
std::array<Node*, sizeof...(nodes)> nodes_arr{{nodes...}}; template <typename... Nodes,
typename = typename std::enable_if_t<
base::all(std::is_convertible<Nodes, Node*>::value...)>>
Node* NewNode(const Operator* op, Nodes... nodes) {
std::array<Node*, sizeof...(nodes)> nodes_arr{
{static_cast<Node*>(nodes)...}};
return NewNode(op, nodes_arr.size(), nodes_arr.data()); return NewNode(op, nodes_arr.size(), nodes_arr.data());
} }
......
...@@ -43,22 +43,6 @@ namespace { ...@@ -43,22 +43,6 @@ namespace {
// Shorter lambda declarations with less visual clutter. // Shorter lambda declarations with less visual clutter.
#define _ [&]() // NOLINT(whitespace/braces) #define _ [&]() // NOLINT(whitespace/braces)
// STNode<T> is a shorter alias of SloppyTNode<T> for improved readability.
// TODO(jgruber): Switch to TNode once fewer explicit casts are necessary, i.e.
// once more underlying operations return typed nodes.
template <class T>
using STNode = SloppyTNode<T>;
template <class T>
constexpr Node* ToNodePtr(STNode<T> tnode) {
return static_cast<Node*>(tnode);
}
template <class T>
constexpr Node* ToNodePtr(TNode<T> tnode) {
return static_cast<Node*>(tnode);
}
template <class T> template <class T>
constexpr TNode<T> ToTNode(Node* node) { constexpr TNode<T> ToTNode(Node* node) {
return TNode<T>::UncheckedCast(node); return TNode<T>::UncheckedCast(node);
...@@ -68,8 +52,10 @@ constexpr TNode<T> ToTNode(Node* node) { ...@@ -68,8 +52,10 @@ constexpr TNode<T> ToTNode(Node* node) {
class JSCallReducerAssembler : public GraphAssembler { class JSCallReducerAssembler : public GraphAssembler {
public: public:
JSCallReducerAssembler(JSGraph* jsgraph, Zone* zone, STNode<Object> node) JSCallReducerAssembler(JSGraph* jsgraph, Zone* zone, Node* node)
: GraphAssembler(jsgraph, zone), node_(node), if_exception_nodes_(zone) { : GraphAssembler(jsgraph, zone),
node_(ToTNode<Object>(node)),
if_exception_nodes_(zone) {
InitializeEffectControl(NodeProperties::GetEffectInput(node), InitializeEffectControl(NodeProperties::GetEffectInput(node),
NodeProperties::GetControlInput(node)); NodeProperties::GetControlInput(node));
...@@ -97,14 +83,11 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -97,14 +83,11 @@ class JSCallReducerAssembler : public GraphAssembler {
// Returns {value, effect, control}. // Returns {value, effect, control}.
std::tuple<Node*, Node*, Node*> MergeExceptionalPaths(); std::tuple<Node*, Node*, Node*> MergeExceptionalPaths();
Node* node_ptr() const { return ToNodePtr(node_); } Node* node_ptr() const { return static_cast<Node*>(node_); }
protected: protected:
using NodeGenerator = std::function<Node*()>; using NodeGenerator0 = std::function<TNode<Object>()>;
using NodeGenerator1 = std::function<Node*(Node*)>; using VoidGenerator0 = std::function<void()>;
using VoidGenerator = std::function<void()>;
using VoidGenerator1 = std::function<void(Node*)>;
using VoidGenerator2 = std::function<void(Node*, Node*)>;
// TODO(jgruber): Currently IfBuilder0 and IfBuilder1 are implemented as // TODO(jgruber): Currently IfBuilder0 and IfBuilder1 are implemented as
// separate classes. If, in the future, we encounter additional use cases that // separate classes. If, in the future, we encounter additional use cases that
...@@ -112,7 +95,7 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -112,7 +95,7 @@ class JSCallReducerAssembler : public GraphAssembler {
// implementation. // implementation.
class IfBuilder0 { class IfBuilder0 {
public: public:
IfBuilder0(GraphAssembler* gasm, STNode<Object> cond, bool negate_cond) IfBuilder0(GraphAssembler* gasm, TNode<Boolean> cond, bool negate_cond)
: gasm_(gasm), cond_(cond), negate_cond_(negate_cond) {} : gasm_(gasm), cond_(cond), negate_cond_(negate_cond) {}
V8_WARN_UNUSED_RESULT IfBuilder0& ExpectTrue() { V8_WARN_UNUSED_RESULT IfBuilder0& ExpectTrue() {
...@@ -127,11 +110,11 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -127,11 +110,11 @@ class JSCallReducerAssembler : public GraphAssembler {
return *this; return *this;
} }
V8_WARN_UNUSED_RESULT IfBuilder0& Then(const VoidGenerator& body) { V8_WARN_UNUSED_RESULT IfBuilder0& Then(const VoidGenerator0& body) {
then_body_ = body; then_body_ = body;
return *this; return *this;
} }
V8_WARN_UNUSED_RESULT IfBuilder0& Else(const VoidGenerator& body) { V8_WARN_UNUSED_RESULT IfBuilder0& Else(const VoidGenerator0& body) {
else_body_ = body; else_body_ = body;
return *this; return *this;
} }
...@@ -163,19 +146,22 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -163,19 +146,22 @@ class JSCallReducerAssembler : public GraphAssembler {
private: private:
GraphAssembler* const gasm_; GraphAssembler* const gasm_;
const STNode<Object> cond_; const TNode<Boolean> cond_;
const bool negate_cond_; const bool negate_cond_;
BranchHint hint_ = BranchHint::kNone; BranchHint hint_ = BranchHint::kNone;
VoidGenerator then_body_; VoidGenerator0 then_body_;
VoidGenerator else_body_; VoidGenerator0 else_body_;
}; };
IfBuilder0 If(STNode<Object> cond) { return {this, cond, false}; } IfBuilder0 If(TNode<Boolean> cond) { return {this, cond, false}; }
IfBuilder0 IfNot(STNode<Object> cond) { return {this, cond, true}; } IfBuilder0 IfNot(TNode<Boolean> cond) { return {this, cond, true}; }
template <typename T>
class IfBuilder1 { class IfBuilder1 {
using If1BodyFunction = std::function<TNode<T>()>;
public: public:
IfBuilder1(GraphAssembler* gasm, STNode<Object> cond) IfBuilder1(GraphAssembler* gasm, TNode<Boolean> cond)
: gasm_(gasm), cond_(cond) {} : gasm_(gasm), cond_(cond) {}
V8_WARN_UNUSED_RESULT IfBuilder1& ExpectTrue() { V8_WARN_UNUSED_RESULT IfBuilder1& ExpectTrue() {
...@@ -190,16 +176,16 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -190,16 +176,16 @@ class JSCallReducerAssembler : public GraphAssembler {
return *this; return *this;
} }
V8_WARN_UNUSED_RESULT IfBuilder1& Then(const NodeGenerator& body) { V8_WARN_UNUSED_RESULT IfBuilder1& Then(const If1BodyFunction& body) {
then_body_ = body; then_body_ = body;
return *this; return *this;
} }
V8_WARN_UNUSED_RESULT IfBuilder1& Else(const NodeGenerator& body) { V8_WARN_UNUSED_RESULT IfBuilder1& Else(const If1BodyFunction& body) {
else_body_ = body; else_body_ = body;
return *this; return *this;
} }
V8_WARN_UNUSED_RESULT TNode<Object> Value() { V8_WARN_UNUSED_RESULT TNode<T> Value() {
DCHECK(then_body_); DCHECK(then_body_);
DCHECK(else_body_); DCHECK(else_body_);
auto if_true = (hint_ == BranchHint::kFalse) ? gasm_->MakeDeferredLabel() auto if_true = (hint_ == BranchHint::kFalse) ? gasm_->MakeDeferredLabel()
...@@ -210,15 +196,15 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -210,15 +196,15 @@ class JSCallReducerAssembler : public GraphAssembler {
gasm_->Branch(cond_, &if_true, &if_false); gasm_->Branch(cond_, &if_true, &if_false);
gasm_->Bind(&if_true); gasm_->Bind(&if_true);
Node* then_result = then_body_(); TNode<T> then_result = then_body_();
gasm_->Goto(&merge, then_result); gasm_->Goto(&merge, then_result);
gasm_->Bind(&if_false); gasm_->Bind(&if_false);
Node* else_result = else_body_(); TNode<T> else_result = else_body_();
gasm_->Goto(&merge, else_result); gasm_->Goto(&merge, else_result);
gasm_->Bind(&merge); gasm_->Bind(&merge);
return ToTNode<Object>(merge.PhiAt(0)); return ToTNode<T>(merge.PhiAt(0));
} }
private: private:
...@@ -226,37 +212,40 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -226,37 +212,40 @@ class JSCallReducerAssembler : public GraphAssembler {
MachineRepresentation::kTagged; MachineRepresentation::kTagged;
GraphAssembler* const gasm_; GraphAssembler* const gasm_;
const STNode<Object> cond_; const TNode<Boolean> cond_;
BranchHint hint_ = BranchHint::kNone; BranchHint hint_ = BranchHint::kNone;
NodeGenerator then_body_; If1BodyFunction then_body_;
NodeGenerator else_body_; If1BodyFunction else_body_;
}; };
IfBuilder1 SelectIf(STNode<Object> cond) { return {this, cond}; } template <typename T>
IfBuilder1<T> SelectIf(TNode<Boolean> cond) {
return {this, cond};
}
// Simplified operators. // Simplified operators.
TNode<Number> SpeculativeToNumber( TNode<Number> SpeculativeToNumber(
STNode<Object> value, TNode<Object> value,
NumberOperationHint hint = NumberOperationHint::kNumberOrOddball); NumberOperationHint hint = NumberOperationHint::kNumberOrOddball);
TNode<Smi> CheckSmi(STNode<Object> value); TNode<Smi> CheckSmi(TNode<Object> value);
TNode<String> CheckString(STNode<Object> value); TNode<String> CheckString(TNode<Object> value);
TNode<Number> CheckBounds(TNode<Number> value, TNode<Number> limit); TNode<Number> CheckBounds(TNode<Number> value, TNode<Number> limit);
// Common operators. // Common operators.
TNode<Smi> TypeGuardUnsignedSmall(STNode<Object> value); TNode<Smi> TypeGuardUnsignedSmall(TNode<Object> value);
TNode<Object> TypeGuardNonInternal(STNode<Object> value); TNode<Object> TypeGuardNonInternal(TNode<Object> value);
// Javascript operators. // Javascript operators.
TNode<Object> JSCall3(STNode<Object> function, STNode<Object> this_arg, TNode<Object> JSCall3(TNode<Object> function, TNode<Object> this_arg,
STNode<Object> arg0, STNode<Object> arg1, TNode<Object> arg0, TNode<Object> arg1,
STNode<Object> arg2, TNode<Object> frame_state); TNode<Object> arg2, Node* frame_state);
TNode<Object> JSCall4(STNode<Object> function, STNode<Object> this_arg, TNode<Object> JSCall4(TNode<Object> function, TNode<Object> this_arg,
STNode<Object> arg0, STNode<Object> arg1, TNode<Object> arg0, TNode<Object> arg1,
STNode<Object> arg2, STNode<Object> arg3, TNode<Object> arg2, TNode<Object> arg3,
TNode<Object> frame_state); Node* frame_state);
TNode<Object> JSCallRuntime2(Runtime::FunctionId function_id, TNode<Object> JSCallRuntime2(Runtime::FunctionId function_id,
STNode<Object> arg0, STNode<Object> arg1, TNode<Object> arg0, TNode<Object> arg1,
TNode<Object> frame_state); Node* frame_state);
void MaybeInsertMapChecks(MapInference* inference, void MaybeInsertMapChecks(MapInference* inference,
bool has_stability_dependency) { bool has_stability_dependency) {
...@@ -275,8 +264,8 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -275,8 +264,8 @@ class JSCallReducerAssembler : public GraphAssembler {
// would be good. Note also that this only handles the very basic case (not // would be good. Note also that this only handles the very basic case (not
// involving custom handlers) so far and will probably have to be extended in // involving custom handlers) so far and will probably have to be extended in
// the future. // the future.
TNode<Object> MayThrow(const NodeGenerator& body) { TNode<Object> MayThrow(const NodeGenerator0& body) {
TNode<Object> result = ToTNode<Object>(body()); TNode<Object> result = body();
if (has_external_exception_handler()) { if (has_external_exception_handler()) {
Node* e = effect(); Node* e = effect();
...@@ -294,16 +283,20 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -294,16 +283,20 @@ class JSCallReducerAssembler : public GraphAssembler {
return result; return result;
} }
using ConditionFunction1 = std::function<TNode<Boolean>(TNode<Number>)>;
using StepFunction1 = std::function<TNode<Number>(TNode<Number>)>;
class ForBuilder0 { class ForBuilder0 {
using For0BodyFunction = std::function<void(TNode<Number>)>;
public: public:
ForBuilder0(GraphAssembler* gasm, STNode<Object> initial_value, ForBuilder0(GraphAssembler* gasm, TNode<Number> initial_value,
const NodeGenerator1& cond, const NodeGenerator1& step) const ConditionFunction1& cond, const StepFunction1& step)
: gasm_(gasm), : gasm_(gasm),
initial_value_(initial_value), initial_value_(initial_value),
cond_(cond), cond_(cond),
step_(step) {} step_(step) {}
void Do(const VoidGenerator1& body) { void Do(const For0BodyFunction& body) {
auto loop_header = gasm_->MakeLoopLabel(kPhiRepresentation); auto loop_header = gasm_->MakeLoopLabel(kPhiRepresentation);
auto loop_body = gasm_->MakeLabel(); auto loop_body = gasm_->MakeLabel();
auto loop_exit = gasm_->MakeLabel(); auto loop_exit = gasm_->MakeLabel();
...@@ -312,7 +305,7 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -312,7 +305,7 @@ class JSCallReducerAssembler : public GraphAssembler {
gasm_->Bind(&loop_header); gasm_->Bind(&loop_header);
Node* loop_header_control = gasm_->control(); // For LoopExit below. Node* loop_header_control = gasm_->control(); // For LoopExit below.
STNode<Object> i = loop_header.PhiAt(0); TNode<Number> i = ToTNode<Number>(loop_header.PhiAt(0));
gasm_->BranchWithHint(cond_(i), &loop_body, &loop_exit, gasm_->BranchWithHint(cond_(i), &loop_body, &loop_exit,
BranchHint::kTrue); BranchHint::kTrue);
...@@ -333,44 +326,49 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -333,44 +326,49 @@ class JSCallReducerAssembler : public GraphAssembler {
MachineRepresentation::kTagged; MachineRepresentation::kTagged;
GraphAssembler* const gasm_; GraphAssembler* const gasm_;
const STNode<Object> initial_value_; const TNode<Number> initial_value_;
const NodeGenerator1 cond_; const ConditionFunction1 cond_;
const NodeGenerator1 step_; const StepFunction1 step_;
}; };
ForBuilder0 ForSmiZeroUntil(STNode<Smi> excluded_limit) { ForBuilder0 ForSmiZeroUntil(TNode<Number> excluded_limit) {
STNode<Smi> initial_value = ZeroConstant(); TNode<Number> initial_value = ToTNode<Number>(ZeroConstant());
auto cond = [=](Node* i) { return NumberLessThan(i, excluded_limit); }; auto cond = [=](TNode<Number> i) {
auto step = [=](Node* i) { return NumberAdd(i, OneConstant()); }; return NumberLessThan(i, excluded_limit);
};
auto step = [=](TNode<Number> i) {
return NumberAdd(i, ToTNode<Number>(OneConstant()));
};
return {this, initial_value, cond, step}; return {this, initial_value, cond, step};
} }
ForBuilder0 Forever(STNode<Object> initial_value, ForBuilder0 Forever(TNode<Number> initial_value, const StepFunction1& step) {
const NodeGenerator1& step) { TNode<Boolean> true_constant =
STNode<BoolT> true_constant = jsgraph()->BooleanConstant(true); ToTNode<Boolean>(jsgraph()->BooleanConstant(true));
return {this, initial_value, [=](Node*) { return true_constant; }, step}; return {this, initial_value, [=](TNode<Number>) { return true_constant; },
step};
} }
using For1Body = std::function<void(Node*, Node**)>; using For1BodyFunction = std::function<void(TNode<Number>, TNode<Object>*)>;
class ForBuilder1 { class ForBuilder1 {
public: public:
ForBuilder1(GraphAssembler* gasm, STNode<Object> initial_value, ForBuilder1(GraphAssembler* gasm, TNode<Number> initial_value,
const NodeGenerator1& cond, const NodeGenerator1& step, const ConditionFunction1& cond, const StepFunction1& step,
STNode<Object> initial_arg0) TNode<Object> initial_arg0)
: gasm_(gasm), : gasm_(gasm),
initial_value_(initial_value), initial_value_(initial_value),
cond_(cond), cond_(cond),
step_(step), step_(step),
initial_arg0_(initial_arg0) {} initial_arg0_(initial_arg0) {}
V8_WARN_UNUSED_RESULT ForBuilder1& Do(const For1Body& body) { V8_WARN_UNUSED_RESULT ForBuilder1& Do(const For1BodyFunction& body) {
body_ = body; body_ = body;
return *this; return *this;
} }
TNode<Object> Value() { TNode<Object> Value() {
DCHECK(body_); DCHECK(body_);
Node* arg0 = ToNodePtr(initial_arg0_); TNode<Object> arg0 = initial_arg0_;
auto loop_header = auto loop_header =
gasm_->MakeLoopLabel(kPhiRepresentation, kPhiRepresentation); gasm_->MakeLoopLabel(kPhiRepresentation, kPhiRepresentation);
...@@ -381,8 +379,8 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -381,8 +379,8 @@ class JSCallReducerAssembler : public GraphAssembler {
gasm_->Bind(&loop_header); gasm_->Bind(&loop_header);
Node* loop_header_control = gasm_->control(); // For LoopExit below. Node* loop_header_control = gasm_->control(); // For LoopExit below.
STNode<Object> i = loop_header.PhiAt(0); TNode<Number> i = ToTNode<Number>(loop_header.PhiAt(0));
arg0 = loop_header.PhiAt(1); arg0 = ToTNode<Object>(loop_header.PhiAt(1));
gasm_->BranchWithHint(cond_(i), &loop_body, &loop_exit, BranchHint::kTrue, gasm_->BranchWithHint(cond_(i), &loop_body, &loop_exit, BranchHint::kTrue,
arg0); arg0);
...@@ -405,15 +403,15 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -405,15 +403,15 @@ class JSCallReducerAssembler : public GraphAssembler {
MachineRepresentation::kTagged; MachineRepresentation::kTagged;
GraphAssembler* const gasm_; GraphAssembler* const gasm_;
const STNode<Object> initial_value_; const TNode<Number> initial_value_;
const NodeGenerator1 cond_; const ConditionFunction1 cond_;
const NodeGenerator1 step_; const StepFunction1 step_;
For1Body body_; For1BodyFunction body_;
const STNode<Object> initial_arg0_; const TNode<Object> initial_arg0_;
}; };
ForBuilder1 For1(STNode<Object> initial_value, const NodeGenerator1& cond, ForBuilder1 For1(TNode<Number> initial_value, const ConditionFunction1& cond,
const NodeGenerator1& step, STNode<Object> initial_arg0) { const StepFunction1& step, TNode<Object> initial_arg0) {
return {this, initial_value, cond, step, initial_arg0}; return {this, initial_value, cond, step, initial_arg0};
} }
...@@ -422,7 +420,7 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -422,7 +420,7 @@ class JSCallReducerAssembler : public GraphAssembler {
return p.feedback(); return p.feedback();
} }
TNode<Object> ValueInput(int index) { TNode<Object> ValueInput(int index) const {
return ToTNode<Object>(NodeProperties::GetValueInput(node_, index)); return ToTNode<Object>(NodeProperties::GetValueInput(node_, index));
} }
...@@ -438,18 +436,18 @@ class JSCallReducerAssembler : public GraphAssembler { ...@@ -438,18 +436,18 @@ class JSCallReducerAssembler : public GraphAssembler {
: UndefinedConstant()); : UndefinedConstant());
} }
TNode<Context> ContextInput() { TNode<Context> ContextInput() const {
return ToTNode<Context>(NodeProperties::GetContextInput(node_)); return ToTNode<Context>(NodeProperties::GetContextInput(node_));
} }
TNode<Object> FrameStateInput() { Node* FrameStateInput() const {
return ToTNode<Object>(NodeProperties::GetFrameStateInput(node_)); return NodeProperties::GetFrameStateInput(node_);
} }
JSOperatorBuilder* javascript() const { return jsgraph()->javascript(); } JSOperatorBuilder* javascript() const { return jsgraph()->javascript(); }
private: private:
const STNode<Object> node_; const TNode<Object> node_;
bool has_external_exception_handler_; bool has_external_exception_handler_;
Node* external_exception_handler_; Node* external_exception_handler_;
...@@ -463,10 +461,9 @@ enum class ArrayReduceDirection { kLeft, kRight }; ...@@ -463,10 +461,9 @@ enum class ArrayReduceDirection { kLeft, kRight };
class IteratingArrayBuiltinReducerAssembler : public JSCallReducerAssembler { class IteratingArrayBuiltinReducerAssembler : public JSCallReducerAssembler {
public: public:
IteratingArrayBuiltinReducerAssembler(JSGraph* jsgraph, Zone* zone, IteratingArrayBuiltinReducerAssembler(JSGraph* jsgraph, Zone* zone,
STNode<Object> node) Node* node)
: JSCallReducerAssembler(jsgraph, zone, node) {} : JSCallReducerAssembler(jsgraph, zone, node) {}
// TODO(jgruber): Move common args to the constructor.
TNode<Object> ReduceArrayPrototypeForEach( TNode<Object> ReduceArrayPrototypeForEach(
MapInference* inference, const bool has_stability_dependency, MapInference* inference, const bool has_stability_dependency,
ElementsKind kind, const SharedFunctionInfoRef& shared); ElementsKind kind, const SharedFunctionInfoRef& shared);
...@@ -476,14 +473,14 @@ class IteratingArrayBuiltinReducerAssembler : public JSCallReducerAssembler { ...@@ -476,14 +473,14 @@ class IteratingArrayBuiltinReducerAssembler : public JSCallReducerAssembler {
ArrayReduceDirection direction, ArrayReduceDirection direction,
const SharedFunctionInfoRef& shared); const SharedFunctionInfoRef& shared);
void ThrowIfNotCallable(TNode<Object> maybe_callable, void ThrowIfNotCallable(TNode<Object> maybe_callable, Node* frame_state) {
TNode<Object> frame_state) {
IfNot(ObjectIsCallable(maybe_callable)) IfNot(ObjectIsCallable(maybe_callable))
.Then(_ { .Then(_ {
JSCallRuntime2(Runtime::kThrowTypeError, JSCallRuntime2(Runtime::kThrowTypeError,
NumberConstant(static_cast<double>( NumberConstant(static_cast<double>(
MessageTemplate::kCalledNonCallable)), MessageTemplate::kCalledNonCallable)),
maybe_callable, frame_state); maybe_callable, frame_state);
Unreachable(); // The runtime call throws unconditionally. Unreachable(); // The runtime call throws unconditionally.
}) })
.ExpectTrue() .ExpectTrue()
...@@ -504,96 +501,88 @@ class IteratingArrayBuiltinReducerAssembler : public JSCallReducerAssembler { ...@@ -504,96 +501,88 @@ class IteratingArrayBuiltinReducerAssembler : public JSCallReducerAssembler {
// Reload the elements pointer before calling the callback, since the // Reload the elements pointer before calling the callback, since the
// previous callback might have resized the array causing the elements // previous callback might have resized the array causing the elements
// buffer to be re-allocated. // buffer to be re-allocated.
STNode<Object> elements = TNode<Object> elements =
LoadField(AccessBuilder::ForJSObjectElements(), o); ToTNode<Object>(LoadField(AccessBuilder::ForJSObjectElements(), o));
TNode<Object> value = ToTNode<Object>(LoadElement( TNode<Object> value = ToTNode<Object>(LoadElement(
AccessBuilder::ForFixedArrayElement(kind, LoadSensitivity::kCritical), AccessBuilder::ForFixedArrayElement(kind, LoadSensitivity::kCritical),
elements, index)); elements, index));
return std::make_pair(index, value); return std::make_pair(index, value);
} }
TNode<BoolT> HoleCheck(ElementsKind kind, TNode<Object> v) { TNode<Boolean> HoleCheck(ElementsKind kind, TNode<Object> v) {
return ToTNode<BoolT>(IsDoubleElementsKind(kind) ? NumberIsFloat64Hole(v) return ToTNode<Boolean>(IsDoubleElementsKind(kind) ? NumberIsFloat64Hole(v)
: IsTheHole(v)); : IsTheHole(v));
} }
}; };
TNode<Number> JSCallReducerAssembler::SpeculativeToNumber( TNode<Number> JSCallReducerAssembler::SpeculativeToNumber(
STNode<Object> value, NumberOperationHint hint) { TNode<Object> value, NumberOperationHint hint) {
return ToTNode<Number>(AddNode( return AddNode<Number>(
graph()->NewNode(simplified()->SpeculativeToNumber(hint, feedback()), graph()->NewNode(simplified()->SpeculativeToNumber(hint, feedback()),
ToNodePtr(value), effect(), control()))); value, effect(), control()));
} }
TNode<Smi> JSCallReducerAssembler::CheckSmi(STNode<Object> value) { TNode<Smi> JSCallReducerAssembler::CheckSmi(TNode<Object> value) {
return ToTNode<Smi>( return AddNode<Smi>(graph()->NewNode(simplified()->CheckSmi(feedback()),
AddNode(graph()->NewNode(simplified()->CheckSmi(feedback()), value, effect(), control()));
ToNodePtr(value), effect(), control())));
} }
TNode<String> JSCallReducerAssembler::CheckString(STNode<Object> value) { TNode<String> JSCallReducerAssembler::CheckString(TNode<Object> value) {
return ToTNode<String>( return AddNode<String>(graph()->NewNode(simplified()->CheckString(feedback()),
AddNode(graph()->NewNode(simplified()->CheckString(feedback()), value, effect(), control()));
ToNodePtr(value), effect(), control())));
} }
TNode<Number> JSCallReducerAssembler::CheckBounds(TNode<Number> value, TNode<Number> JSCallReducerAssembler::CheckBounds(TNode<Number> value,
TNode<Number> limit) { TNode<Number> limit) {
return ToTNode<Number>(AddNode( return AddNode<Number>(graph()->NewNode(simplified()->CheckBounds(feedback()),
graph()->NewNode(simplified()->CheckBounds(feedback()), ToNodePtr(value), value, limit, effect(), control()));
ToNodePtr(limit), effect(), control())));
} }
TNode<Smi> JSCallReducerAssembler::TypeGuardUnsignedSmall( TNode<Smi> JSCallReducerAssembler::TypeGuardUnsignedSmall(TNode<Object> value) {
STNode<Object> value) {
return ToTNode<Smi>(TypeGuard(Type::UnsignedSmall(), value)); return ToTNode<Smi>(TypeGuard(Type::UnsignedSmall(), value));
} }
TNode<Object> JSCallReducerAssembler::TypeGuardNonInternal( TNode<Object> JSCallReducerAssembler::TypeGuardNonInternal(
STNode<Object> value) { TNode<Object> value) {
return ToTNode<Object>(TypeGuard(Type::NonInternal(), value)); return ToTNode<Object>(TypeGuard(Type::NonInternal(), value));
} }
TNode<Object> JSCallReducerAssembler::JSCall3( TNode<Object> JSCallReducerAssembler::JSCall3(
STNode<Object> function, STNode<Object> this_arg, STNode<Object> arg0, TNode<Object> function, TNode<Object> this_arg, TNode<Object> arg0,
STNode<Object> arg1, STNode<Object> arg2, TNode<Object> frame_state) { TNode<Object> arg1, TNode<Object> arg2, Node* frame_state) {
CallParameters const& p = CallParametersOf(node_ptr()->op()); CallParameters const& p = CallParametersOf(node_ptr()->op());
return MayThrow(_ { return MayThrow(_ {
return ToTNode<Object>(AddNode(graph()->NewNode( return AddNode<Object>(graph()->NewNode(
javascript()->Call(5, p.frequency(), p.feedback(), javascript()->Call(5, p.frequency(), p.feedback(),
ConvertReceiverMode::kAny, p.speculation_mode(), ConvertReceiverMode::kAny, p.speculation_mode(),
CallFeedbackRelation::kUnrelated), CallFeedbackRelation::kUnrelated),
ToNodePtr(function), ToNodePtr(this_arg), ToNodePtr(arg0), function, this_arg, arg0, arg1, arg2, ContextInput(), frame_state,
ToNodePtr(arg1), ToNodePtr(arg2), ToNodePtr(ContextInput()), effect(), control()));
ToNodePtr(frame_state), effect(), control())));
}); });
} }
TNode<Object> JSCallReducerAssembler::JSCall4( TNode<Object> JSCallReducerAssembler::JSCall4(
STNode<Object> function, STNode<Object> this_arg, STNode<Object> arg0, TNode<Object> function, TNode<Object> this_arg, TNode<Object> arg0,
STNode<Object> arg1, STNode<Object> arg2, STNode<Object> arg3, TNode<Object> arg1, TNode<Object> arg2, TNode<Object> arg3,
TNode<Object> frame_state) { Node* frame_state) {
CallParameters const& p = CallParametersOf(node_ptr()->op()); CallParameters const& p = CallParametersOf(node_ptr()->op());
return MayThrow(_ { return MayThrow(_ {
return ToTNode<Object>(AddNode(graph()->NewNode( return AddNode<Object>(graph()->NewNode(
javascript()->Call(6, p.frequency(), p.feedback(), javascript()->Call(6, p.frequency(), p.feedback(),
ConvertReceiverMode::kAny, p.speculation_mode(), ConvertReceiverMode::kAny, p.speculation_mode(),
CallFeedbackRelation::kUnrelated), CallFeedbackRelation::kUnrelated),
ToNodePtr(function), ToNodePtr(this_arg), ToNodePtr(arg0), function, this_arg, arg0, arg1, arg2, arg3, ContextInput(), frame_state,
ToNodePtr(arg1), ToNodePtr(arg2), ToNodePtr(arg3), effect(), control()));
ToNodePtr(ContextInput()), ToNodePtr(frame_state), effect(),
control())));
}); });
} }
TNode<Object> JSCallReducerAssembler::JSCallRuntime2( TNode<Object> JSCallReducerAssembler::JSCallRuntime2(
Runtime::FunctionId function_id, STNode<Object> arg0, STNode<Object> arg1, Runtime::FunctionId function_id, TNode<Object> arg0, TNode<Object> arg1,
TNode<Object> frame_state) { Node* frame_state) {
return MayThrow(_ { return MayThrow(_ {
return ToTNode<Object>(AddNode(graph()->NewNode( return AddNode<Object>(
javascript()->CallRuntime(function_id, 2), ToNodePtr(arg0), graph()->NewNode(javascript()->CallRuntime(function_id, 2), arg0, arg1,
ToNodePtr(arg1), ToNodePtr(ContextInput()), ToNodePtr(frame_state), ContextInput(), frame_state, effect(), control()));
effect(), control())));
}); });
} }
...@@ -629,90 +618,86 @@ JSCallReducerAssembler::MergeExceptionalPaths() { ...@@ -629,90 +618,86 @@ JSCallReducerAssembler::MergeExceptionalPaths() {
} }
TNode<Object> JSCallReducerAssembler::ReduceMathUnary(const Operator* op) { TNode<Object> JSCallReducerAssembler::ReduceMathUnary(const Operator* op) {
STNode<Object> input = ValueInput(2); TNode<Object> input = ValueInput(2);
STNode<Number> input_as_number = SpeculativeToNumber(input); TNode<Number> input_as_number = SpeculativeToNumber(input);
return ToTNode<Object>(graph()->NewNode(op, ToNodePtr(input_as_number))); return ToTNode<Object>(graph()->NewNode(op, input_as_number));
} }
TNode<Object> JSCallReducerAssembler::ReduceMathBinary(const Operator* op) { TNode<Object> JSCallReducerAssembler::ReduceMathBinary(const Operator* op) {
STNode<Object> left = ValueInput(2); TNode<Object> left = ValueInput(2);
STNode<Object> right = ValueInputOrNaN(3); TNode<Object> right = ValueInputOrNaN(3);
STNode<Number> left_number = SpeculativeToNumber(left); TNode<Number> left_number = SpeculativeToNumber(left);
STNode<Number> right_number = SpeculativeToNumber(right); TNode<Number> right_number = SpeculativeToNumber(right);
return ToTNode<Object>( return ToTNode<Object>(graph()->NewNode(op, left_number, right_number));
graph()->NewNode(op, ToNodePtr(left_number), ToNodePtr(right_number)));
} }
TNode<String> JSCallReducerAssembler::ReduceStringPrototypeSubstring() { TNode<String> JSCallReducerAssembler::ReduceStringPrototypeSubstring() {
STNode<Object> receiver = ValueInput(1); TNode<Object> receiver = ValueInput(1);
STNode<Object> start = ValueInput(2); TNode<Object> start = ValueInput(2);
STNode<Object> end = ValueInputOrUndefined(3); TNode<Object> end = ValueInputOrUndefined(3);
STNode<String> receiver_string = CheckString(receiver); TNode<String> receiver_string = CheckString(receiver);
STNode<Smi> start_smi = CheckSmi(start); TNode<Number> start_smi = CheckSmi(start);
STNode<Smi> length = StringLength(receiver_string); TNode<Number> length = StringLength(receiver_string);
STNode<Smi> end_smi = TNode<Number> end_smi = SelectIf<Number>(IsUndefined(end))
STNode<Smi>::UncheckedCast(SelectIf(IsUndefined(end))
.Then(_ { return length; }) .Then(_ { return length; })
.Else(_ { return CheckSmi(end); }) .Else(_ { return CheckSmi(end); })
.ExpectFalse() .ExpectFalse()
.Value()); .Value();
STNode<Number> zero = ZeroConstant(); TNode<Number> zero = TNode<Number>::UncheckedCast(ZeroConstant());
STNode<Number> finalStart = NumberMin(NumberMax(start_smi, zero), length); TNode<Number> finalStart = NumberMin(NumberMax(start_smi, zero), length);
STNode<Number> finalEnd = NumberMin(NumberMax(end_smi, zero), length); TNode<Number> finalEnd = NumberMin(NumberMax(end_smi, zero), length);
STNode<Number> from = NumberMin(finalStart, finalEnd); TNode<Number> from = NumberMin(finalStart, finalEnd);
STNode<Number> to = NumberMax(finalStart, finalEnd); TNode<Number> to = NumberMax(finalStart, finalEnd);
return ToTNode<String>(StringSubstring(receiver_string, from, to)); return StringSubstring(receiver_string, from, to);
} }
TNode<String> JSCallReducerAssembler::ReduceStringPrototypeSlice() { TNode<String> JSCallReducerAssembler::ReduceStringPrototypeSlice() {
STNode<Object> receiver = ValueInput(1); TNode<Object> receiver = ValueInput(1);
STNode<Object> start = ValueInput(2); TNode<Object> start = ValueInput(2);
STNode<Object> end = ValueInputOrUndefined(3); TNode<Object> end = ValueInputOrUndefined(3);
STNode<String> receiver_string = CheckString(receiver); TNode<String> receiver_string = CheckString(receiver);
STNode<Smi> start_smi = CheckSmi(start); TNode<Number> start_smi = CheckSmi(start);
STNode<Smi> length = StringLength(receiver_string); TNode<Number> length = StringLength(receiver_string);
STNode<Smi> end_smi = TNode<Number> end_smi = SelectIf<Number>(IsUndefined(end))
STNode<Smi>::UncheckedCast(SelectIf(IsUndefined(end))
.Then(_ { return length; }) .Then(_ { return length; })
.Else(_ { return CheckSmi(end); }) .Else(_ { return CheckSmi(end); })
.ExpectFalse() .ExpectFalse()
.Value()); .Value();
STNode<Number> zero = ZeroConstant(); TNode<Number> zero = TNode<Number>::UncheckedCast(ZeroConstant());
STNode<Object> from_untyped = TNode<Number> from_untyped =
SelectIf(NumberLessThan(start_smi, zero)) SelectIf<Number>(NumberLessThan(start_smi, zero))
.Then(_ { return NumberMax(NumberAdd(length, start_smi), zero); }) .Then(_ { return NumberMax(NumberAdd(length, start_smi), zero); })
.Else(_ { return NumberMin(start_smi, length); }) .Else(_ { return NumberMin(start_smi, length); })
.ExpectFalse() .ExpectFalse()
.Value(); .Value();
// {from} is always in non-negative Smi range, but our typer cannot figure // {from} is always in non-negative Smi range, but our typer cannot figure
// that out yet. // that out yet.
STNode<Smi> from = TypeGuardUnsignedSmall(from_untyped); TNode<Smi> from = TypeGuardUnsignedSmall(from_untyped);
STNode<Number> to_untyped = STNode<Number>::UncheckedCast( TNode<Number> to_untyped =
SelectIf(NumberLessThan(end_smi, zero)) SelectIf<Number>(NumberLessThan(end_smi, zero))
.Then(_ { return NumberMax(NumberAdd(length, end_smi), zero); }) .Then(_ { return NumberMax(NumberAdd(length, end_smi), zero); })
.Else(_ { return NumberMin(end_smi, length); }) .Else(_ { return NumberMin(end_smi, length); })
.ExpectFalse() .ExpectFalse()
.Value()); .Value();
// {to} is always in non-negative Smi range, but our typer cannot figure that // {to} is always in non-negative Smi range, but our typer cannot figure that
// out yet. // out yet.
STNode<Smi> to = TypeGuardUnsignedSmall(to_untyped); TNode<Smi> to = TypeGuardUnsignedSmall(to_untyped);
return ToTNode<String>( return SelectIf<String>(NumberLessThan(from, to))
(SelectIf(NumberLessThan(from, to))
.Then(_ { return StringSubstring(receiver_string, from, to); }) .Then(_ { return StringSubstring(receiver_string, from, to); })
.Else(_ { return EmptyStringConstant(); }) .Else(_ { return ToTNode<String>(EmptyStringConstant()); })
.ExpectTrue() .ExpectTrue()
.Value())); .Value();
} }
namespace { namespace {
...@@ -722,33 +707,33 @@ struct ForEachFrameStateParams { ...@@ -722,33 +707,33 @@ struct ForEachFrameStateParams {
SharedFunctionInfoRef shared; SharedFunctionInfoRef shared;
TNode<Context> context; TNode<Context> context;
TNode<Object> target; TNode<Object> target;
TNode<Object> outer_frame_state; Node* outer_frame_state;
TNode<Object> receiver; TNode<Object> receiver;
TNode<Object> callback; TNode<Object> callback;
TNode<Object> this_arg; TNode<Object> this_arg;
TNode<Object> original_length; TNode<Object> original_length;
}; };
TNode<Object> ForEachLoopLazyFrameState(const ForEachFrameStateParams& params, Node* ForEachLoopLazyFrameState(const ForEachFrameStateParams& params,
TNode<Object> k) { TNode<Object> k) {
Builtins::Name builtin = Builtins::kArrayForEachLoopLazyDeoptContinuation; Builtins::Name builtin = Builtins::kArrayForEachLoopLazyDeoptContinuation;
Node* checkpoint_params[] = {params.receiver, params.callback, Node* checkpoint_params[] = {params.receiver, params.callback,
params.this_arg, k, params.original_length}; params.this_arg, k, params.original_length};
return ToTNode<Object>(CreateJavaScriptBuiltinContinuationFrameState( return CreateJavaScriptBuiltinContinuationFrameState(
params.jsgraph, params.shared, builtin, params.target, params.context, params.jsgraph, params.shared, builtin, params.target, params.context,
checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
ContinuationFrameStateMode::LAZY)); ContinuationFrameStateMode::LAZY);
} }
TNode<Object> ForEachLoopEagerFrameState(const ForEachFrameStateParams& params, Node* ForEachLoopEagerFrameState(const ForEachFrameStateParams& params,
TNode<Object> k) { TNode<Object> k) {
Builtins::Name builtin = Builtins::kArrayForEachLoopEagerDeoptContinuation; Builtins::Name builtin = Builtins::kArrayForEachLoopEagerDeoptContinuation;
Node* checkpoint_params[] = {params.receiver, params.callback, Node* checkpoint_params[] = {params.receiver, params.callback,
params.this_arg, k, params.original_length}; params.this_arg, k, params.original_length};
return ToTNode<Object>(CreateJavaScriptBuiltinContinuationFrameState( return CreateJavaScriptBuiltinContinuationFrameState(
params.jsgraph, params.shared, builtin, params.target, params.context, params.jsgraph, params.shared, builtin, params.target, params.context,
checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
ContinuationFrameStateMode::EAGER)); ContinuationFrameStateMode::EAGER);
} }
} // namespace } // namespace
...@@ -759,15 +744,15 @@ IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeForEach( ...@@ -759,15 +744,15 @@ IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeForEach(
ElementsKind kind, const SharedFunctionInfoRef& shared) { ElementsKind kind, const SharedFunctionInfoRef& shared) {
DCHECK(FLAG_turbo_inline_array_builtins); DCHECK(FLAG_turbo_inline_array_builtins);
TNode<Object> outer_frame_state = FrameStateInput(); Node* outer_frame_state = FrameStateInput();
TNode<Context> context = ContextInput(); TNode<Context> context = ContextInput();
TNode<Object> target = ValueInput(0); TNode<Object> target = ValueInput(0);
TNode<Object> receiver = ValueInput(1); TNode<Object> receiver = ValueInput(1);
TNode<Object> fncallback = ValueInputOrUndefined(2); TNode<Object> fncallback = ValueInputOrUndefined(2);
TNode<Object> this_arg = ValueInputOrUndefined(3); TNode<Object> this_arg = ValueInputOrUndefined(3);
STNode<Smi> original_length = TNode<Number> original_length = ToTNode<Number>(
LoadField(AccessBuilder::ForJSArrayLength(kind), receiver); LoadField(AccessBuilder::ForJSArrayLength(kind), receiver));
ForEachFrameStateParams frame_state_params{ ForEachFrameStateParams frame_state_params{
jsgraph(), shared, context, target, outer_frame_state, jsgraph(), shared, context, target, outer_frame_state,
...@@ -777,15 +762,14 @@ IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeForEach( ...@@ -777,15 +762,14 @@ IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeForEach(
fncallback, ForEachLoopLazyFrameState(frame_state_params, fncallback, ForEachLoopLazyFrameState(frame_state_params,
ToTNode<Object>(ZeroConstant()))); ToTNode<Object>(ZeroConstant())));
ForSmiZeroUntil(original_length).Do([&](Node* k) { ForSmiZeroUntil(original_length).Do([&](TNode<Number> k) {
TNode<Number> k_number = ToTNode<Number>(k); Checkpoint(ForEachLoopEagerFrameState(frame_state_params, k));
Checkpoint(ForEachLoopEagerFrameState(frame_state_params, k_number));
// Deopt if the map has changed during the iteration. // Deopt if the map has changed during the iteration.
MaybeInsertMapChecks(inference, has_stability_dependency); MaybeInsertMapChecks(inference, has_stability_dependency);
TNode<Object> element; TNode<Object> element;
std::tie(k_number, element) = SafeLoadElement(kind, receiver, k_number); std::tie(k, element) = SafeLoadElement(kind, receiver, k);
auto continue_label = MakeLabel(); auto continue_label = MakeLabel();
if (IsHoleyElementsKind(kind)) { if (IsHoleyElementsKind(kind)) {
...@@ -801,15 +785,15 @@ IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeForEach( ...@@ -801,15 +785,15 @@ IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeForEach(
element = TypeGuardNonInternal(element); element = TypeGuardNonInternal(element);
} }
TNode<Number> next_k = ToTNode<Number>(NumberAdd(k, OneConstant())); TNode<Number> next_k = NumberAdd(k, ToTNode<Number>(OneConstant()));
JSCall3(fncallback, this_arg, element, k_number, receiver, JSCall3(fncallback, this_arg, element, k, receiver,
ForEachLoopLazyFrameState(frame_state_params, next_k)); ForEachLoopLazyFrameState(frame_state_params, next_k));
Goto(&continue_label); Goto(&continue_label);
Bind(&continue_label); Bind(&continue_label);
}); });
return ToTNode<Object>(UndefinedConstant()); return UndefinedConstant();
} }
namespace { namespace {
...@@ -820,59 +804,56 @@ struct ReduceFrameStateParams { ...@@ -820,59 +804,56 @@ struct ReduceFrameStateParams {
ArrayReduceDirection direction; ArrayReduceDirection direction;
TNode<Context> context; TNode<Context> context;
TNode<Object> target; TNode<Object> target;
TNode<Object> outer_frame_state; Node* outer_frame_state;
}; };
TNode<Object> ReducePreLoopLazyFrameState(const ReduceFrameStateParams& params, Node* ReducePreLoopLazyFrameState(const ReduceFrameStateParams& params,
TNode<Object> receiver, TNode<Object> receiver,
TNode<Object> callback, TNode<Object> callback, TNode<Object> k,
TNode<Object> k, TNode<Number> original_length) {
TNode<Smi> original_length) {
Builtins::Name builtin = Builtins::Name builtin =
(params.direction == ArrayReduceDirection::kLeft) (params.direction == ArrayReduceDirection::kLeft)
? Builtins::kArrayReduceLoopLazyDeoptContinuation ? Builtins::kArrayReduceLoopLazyDeoptContinuation
: Builtins::kArrayReduceRightLoopLazyDeoptContinuation; : Builtins::kArrayReduceRightLoopLazyDeoptContinuation;
Node* checkpoint_params[] = {receiver, callback, k, original_length}; Node* checkpoint_params[] = {receiver, callback, k, original_length};
return ToTNode<Object>(CreateJavaScriptBuiltinContinuationFrameState( return CreateJavaScriptBuiltinContinuationFrameState(
params.jsgraph, params.shared, builtin, params.target, params.context, params.jsgraph, params.shared, builtin, params.target, params.context,
checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
ContinuationFrameStateMode::LAZY)); ContinuationFrameStateMode::LAZY);
} }
TNode<Object> ReducePreLoopEagerFrameState(const ReduceFrameStateParams& params, Node* ReducePreLoopEagerFrameState(const ReduceFrameStateParams& params,
TNode<Object> receiver, TNode<Object> receiver,
TNode<Object> callback, TNode<Object> callback,
TNode<Smi> original_length) { TNode<Number> original_length) {
Builtins::Name builtin = Builtins::Name builtin =
(params.direction == ArrayReduceDirection::kLeft) (params.direction == ArrayReduceDirection::kLeft)
? Builtins::kArrayReducePreLoopEagerDeoptContinuation ? Builtins::kArrayReducePreLoopEagerDeoptContinuation
: Builtins::kArrayReduceRightPreLoopEagerDeoptContinuation; : Builtins::kArrayReduceRightPreLoopEagerDeoptContinuation;
Node* checkpoint_params[] = {receiver, callback, original_length}; Node* checkpoint_params[] = {receiver, callback, original_length};
return ToTNode<Object>(CreateJavaScriptBuiltinContinuationFrameState( return CreateJavaScriptBuiltinContinuationFrameState(
params.jsgraph, params.shared, builtin, params.target, params.context, params.jsgraph, params.shared, builtin, params.target, params.context,
checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
ContinuationFrameStateMode::EAGER)); ContinuationFrameStateMode::EAGER);
} }
TNode<Object> ReduceLoopLazyFrameState(const ReduceFrameStateParams& params, Node* ReduceLoopLazyFrameState(const ReduceFrameStateParams& params,
TNode<Object> receiver, TNode<Object> receiver, TNode<Object> callback,
TNode<Object> callback, TNode<Object> k, TNode<Object> k, TNode<Number> original_length) {
TNode<Smi> original_length) {
Builtins::Name builtin = Builtins::Name builtin =
(params.direction == ArrayReduceDirection::kLeft) (params.direction == ArrayReduceDirection::kLeft)
? Builtins::kArrayReduceLoopLazyDeoptContinuation ? Builtins::kArrayReduceLoopLazyDeoptContinuation
: Builtins::kArrayReduceRightLoopLazyDeoptContinuation; : Builtins::kArrayReduceRightLoopLazyDeoptContinuation;
Node* checkpoint_params[] = {receiver, callback, k, original_length}; Node* checkpoint_params[] = {receiver, callback, k, original_length};
return ToTNode<Object>(CreateJavaScriptBuiltinContinuationFrameState( return CreateJavaScriptBuiltinContinuationFrameState(
params.jsgraph, params.shared, builtin, params.target, params.context, params.jsgraph, params.shared, builtin, params.target, params.context,
checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
ContinuationFrameStateMode::LAZY)); ContinuationFrameStateMode::LAZY);
} }
TNode<Object> ReduceLoopEagerFrameState(const ReduceFrameStateParams& params, Node* ReduceLoopEagerFrameState(const ReduceFrameStateParams& params,
TNode<Object> receiver, TNode<Object> receiver, TNode<Object> callback,
TNode<Object> callback, TNode<Object> k, TNode<Object> k, TNode<Number> original_length,
TNode<Smi> original_length,
TNode<Object> accumulator) { TNode<Object> accumulator) {
Builtins::Name builtin = Builtins::Name builtin =
(params.direction == ArrayReduceDirection::kLeft) (params.direction == ArrayReduceDirection::kLeft)
...@@ -880,10 +861,10 @@ TNode<Object> ReduceLoopEagerFrameState(const ReduceFrameStateParams& params, ...@@ -880,10 +861,10 @@ TNode<Object> ReduceLoopEagerFrameState(const ReduceFrameStateParams& params,
: Builtins::kArrayReduceRightLoopEagerDeoptContinuation; : Builtins::kArrayReduceRightLoopEagerDeoptContinuation;
Node* checkpoint_params[] = {receiver, callback, k, original_length, Node* checkpoint_params[] = {receiver, callback, k, original_length,
accumulator}; accumulator};
return ToTNode<Object>(CreateJavaScriptBuiltinContinuationFrameState( return CreateJavaScriptBuiltinContinuationFrameState(
params.jsgraph, params.shared, builtin, params.target, params.context, params.jsgraph, params.shared, builtin, params.target, params.context,
checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
ContinuationFrameStateMode::EAGER)); ContinuationFrameStateMode::EAGER);
} }
} // namespace } // namespace
...@@ -894,7 +875,7 @@ TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce( ...@@ -894,7 +875,7 @@ TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce(
const SharedFunctionInfoRef& shared) { const SharedFunctionInfoRef& shared) {
DCHECK(FLAG_turbo_inline_array_builtins); DCHECK(FLAG_turbo_inline_array_builtins);
TNode<Object> outer_frame_state = FrameStateInput(); Node* outer_frame_state = FrameStateInput();
TNode<Context> context = ContextInput(); TNode<Context> context = ContextInput();
TNode<Object> target = ValueInput(0); TNode<Object> target = ValueInput(0);
TNode<Object> receiver = ValueInput(1); TNode<Object> receiver = ValueInput(1);
...@@ -903,21 +884,23 @@ TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce( ...@@ -903,21 +884,23 @@ TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce(
ReduceFrameStateParams frame_state_params{ ReduceFrameStateParams frame_state_params{
jsgraph(), shared, direction, context, target, outer_frame_state}; jsgraph(), shared, direction, context, target, outer_frame_state};
STNode<Smi> original_length = TNode<Number> original_length = ToTNode<Number>(
LoadField(AccessBuilder::ForJSArrayLength(kind), receiver); LoadField(AccessBuilder::ForJSArrayLength(kind), receiver));
// Set up variable behavior depending on the reduction kind (left/right). // Set up variable behavior depending on the reduction kind (left/right).
TNode<Number> k; TNode<Number> k;
NodeGenerator1 step; StepFunction1 step;
NodeGenerator1 cond; ConditionFunction1 cond;
TNode<Number> zero = ToTNode<Number>(ZeroConstant());
TNode<Number> one = ToTNode<Number>(OneConstant());
if (direction == ArrayReduceDirection::kLeft) { if (direction == ArrayReduceDirection::kLeft) {
k = ToTNode<Number>(ZeroConstant()); k = zero;
step = [&](Node* i) { return NumberAdd(i, OneConstant()); }; step = [&](TNode<Number> i) { return NumberAdd(i, one); };
cond = [&](Node* i) { return NumberLessThan(i, original_length); }; cond = [&](TNode<Number> i) { return NumberLessThan(i, original_length); };
} else { } else {
k = ToTNode<Number>(NumberSubtract(original_length, OneConstant())); k = NumberSubtract(original_length, one);
step = [&](Node* i) { return NumberSubtract(i, OneConstant()); }; step = [&](TNode<Number> i) { return NumberSubtract(i, one); };
cond = [&](Node* i) { return NumberLessThanOrEqual(ZeroConstant(), i); }; cond = [&](TNode<Number> i) { return NumberLessThanOrEqual(zero, i); };
} }
ThrowIfNotCallable( ThrowIfNotCallable(
...@@ -936,14 +919,13 @@ TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce( ...@@ -936,14 +919,13 @@ TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce(
// throw the TypeError here from optimized code. // throw the TypeError here from optimized code.
auto found_initial_element = MakeLabel(MachineRepresentation::kTagged, auto found_initial_element = MakeLabel(MachineRepresentation::kTagged,
MachineRepresentation::kTagged); MachineRepresentation::kTagged);
Forever(k, step).Do([&](Node* k) { Forever(k, step).Do([&](TNode<Number> k) {
Checkpoint(ReducePreLoopEagerFrameState(frame_state_params, receiver, Checkpoint(ReducePreLoopEagerFrameState(frame_state_params, receiver,
fncallback, original_length)); fncallback, original_length));
CheckIf(cond(k), DeoptimizeReason::kNoInitialElement); CheckIf(cond(k), DeoptimizeReason::kNoInitialElement);
TNode<Object> element; TNode<Object> element;
std::tie(k, element) = std::tie(k, element) = SafeLoadElement(kind, receiver, k);
SafeLoadElement(kind, receiver, ToTNode<Number>(k));
GotoIfNot(HoleCheck(kind, element), &found_initial_element, k, element); GotoIfNot(HoleCheck(kind, element), &found_initial_element, k, element);
}); });
...@@ -953,24 +935,23 @@ TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce( ...@@ -953,24 +935,23 @@ TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce(
// TODO(jgruber): This manual fiddling with blocks could be avoided by // TODO(jgruber): This manual fiddling with blocks could be avoided by
// implementing a `break` mechanic for loop builders. // implementing a `break` mechanic for loop builders.
Bind(&found_initial_element); Bind(&found_initial_element);
k = ToTNode<Number>(step(found_initial_element.PhiAt(0))); k = step(ToTNode<Number>(found_initial_element.PhiAt(0)));
accumulator = ToTNode<Object>(found_initial_element.PhiAt(1)); accumulator = ToTNode<Object>(found_initial_element.PhiAt(1));
accumulator = TypeGuardNonInternal(accumulator); accumulator = TypeGuardNonInternal(accumulator);
} }
TNode<Object> result = TNode<Object> result =
For1(k, cond, step, accumulator) For1(k, cond, step, accumulator)
.Do([&](Node* k, Node** accumulator) { .Do([&](TNode<Number> k, TNode<Object>* accumulator) {
Checkpoint(ReduceLoopEagerFrameState( Checkpoint(ReduceLoopEagerFrameState(frame_state_params, receiver,
frame_state_params, receiver, fncallback, ToTNode<Object>(k), fncallback, k, original_length,
original_length, ToTNode<Object>(*accumulator))); *accumulator));
// Deopt if the map has changed during the iteration. // Deopt if the map has changed during the iteration.
MaybeInsertMapChecks(inference, has_stability_dependency); MaybeInsertMapChecks(inference, has_stability_dependency);
TNode<Object> element; TNode<Object> element;
std::tie(k, element) = std::tie(k, element) = SafeLoadElement(kind, receiver, k);
SafeLoadElement(kind, receiver, ToTNode<Number>(k));
auto continue_label = MakeLabel(MachineRepresentation::kTagged); auto continue_label = MakeLabel(MachineRepresentation::kTagged);
if (IsHoleyElementsKind(kind)) { if (IsHoleyElementsKind(kind)) {
...@@ -986,16 +967,15 @@ TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce( ...@@ -986,16 +967,15 @@ TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce(
element = TypeGuardNonInternal(element); element = TypeGuardNonInternal(element);
} }
TNode<Object> next_accumulator = TNode<Object> next_accumulator = JSCall4(
JSCall4(fncallback, UndefinedConstant(), *accumulator, element, fncallback, UndefinedConstant(), *accumulator, element, k,
k, receiver, receiver,
ReduceLoopLazyFrameState(frame_state_params, receiver, ReduceLoopLazyFrameState(frame_state_params, receiver,
fncallback, ToTNode<Object>(k), fncallback, k, original_length));
original_length));
Goto(&continue_label, next_accumulator); Goto(&continue_label, next_accumulator);
Bind(&continue_label); Bind(&continue_label);
*accumulator = continue_label.PhiAt(0); *accumulator = ToTNode<Object>(continue_label.PhiAt(0));
}) })
.Value(); .Value();
...@@ -2051,7 +2031,8 @@ class IteratingArrayBuiltinHelper { ...@@ -2051,7 +2031,8 @@ class IteratingArrayBuiltinHelper {
IteratingArrayBuiltinHelper(Node* node, JSHeapBroker* broker, IteratingArrayBuiltinHelper(Node* node, JSHeapBroker* broker,
JSGraph* jsgraph, JSGraph* jsgraph,
CompilationDependencies* dependencies) CompilationDependencies* dependencies)
: receiver_(NodeProperties::GetValueInput(node, 1)), : disallow_heap_access_(FLAG_concurrent_inlining),
receiver_(NodeProperties::GetValueInput(node, 1)),
effect_(NodeProperties::GetEffectInput(node)), effect_(NodeProperties::GetEffectInput(node)),
control_(NodeProperties::GetControlInput(node)), control_(NodeProperties::GetControlInput(node)),
inference_(broker, receiver_, effect_) { inference_(broker, receiver_, effect_) {
...@@ -2087,6 +2068,7 @@ class IteratingArrayBuiltinHelper { ...@@ -2087,6 +2068,7 @@ class IteratingArrayBuiltinHelper {
ElementsKind elements_kind() const { return elements_kind_; } ElementsKind elements_kind() const { return elements_kind_; }
private: private:
DisallowHeapAccessIf disallow_heap_access_;
bool can_reduce_ = false; bool can_reduce_ = false;
bool has_stability_dependency_ = false; bool has_stability_dependency_ = false;
Node* receiver_; Node* receiver_;
...@@ -2100,26 +2082,24 @@ class IteratingArrayBuiltinHelper { ...@@ -2100,26 +2082,24 @@ class IteratingArrayBuiltinHelper {
Reduction JSCallReducer::ReduceArrayForEach( Reduction JSCallReducer::ReduceArrayForEach(
Node* node, const SharedFunctionInfoRef& shared) { Node* node, const SharedFunctionInfoRef& shared) {
DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
if (!h.can_reduce()) return h.inference()->NoChange(); if (!h.can_reduce()) return h.inference()->NoChange();
IteratingArrayBuiltinReducerAssembler a(jsgraph(), temp_zone(), node); IteratingArrayBuiltinReducerAssembler a(jsgraph(), temp_zone(), node);
a.InitializeEffectControl(h.effect(), h.control()); a.InitializeEffectControl(h.effect(), h.control());
STNode<Object> subgraph = a.ReduceArrayPrototypeForEach( TNode<Object> subgraph = a.ReduceArrayPrototypeForEach(
h.inference(), h.has_stability_dependency(), h.elements_kind(), shared); h.inference(), h.has_stability_dependency(), h.elements_kind(), shared);
return ReplaceWithSubgraph(&a, subgraph); return ReplaceWithSubgraph(&a, subgraph);
} }
Reduction JSCallReducer::ReduceArrayReduce( Reduction JSCallReducer::ReduceArrayReduce(
Node* node, const SharedFunctionInfoRef& shared) { Node* node, const SharedFunctionInfoRef& shared) {
DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
if (!h.can_reduce()) return h.inference()->NoChange(); if (!h.can_reduce()) return h.inference()->NoChange();
IteratingArrayBuiltinReducerAssembler a(jsgraph(), temp_zone(), node); IteratingArrayBuiltinReducerAssembler a(jsgraph(), temp_zone(), node);
a.InitializeEffectControl(h.effect(), h.control()); a.InitializeEffectControl(h.effect(), h.control());
STNode<Object> subgraph = a.ReduceArrayPrototypeReduce( TNode<Object> subgraph = a.ReduceArrayPrototypeReduce(
h.inference(), h.has_stability_dependency(), h.elements_kind(), h.inference(), h.has_stability_dependency(), h.elements_kind(),
ArrayReduceDirection::kLeft, shared); ArrayReduceDirection::kLeft, shared);
return ReplaceWithSubgraph(&a, subgraph); return ReplaceWithSubgraph(&a, subgraph);
...@@ -2127,13 +2107,12 @@ Reduction JSCallReducer::ReduceArrayReduce( ...@@ -2127,13 +2107,12 @@ Reduction JSCallReducer::ReduceArrayReduce(
Reduction JSCallReducer::ReduceArrayReduceRight( Reduction JSCallReducer::ReduceArrayReduceRight(
Node* node, const SharedFunctionInfoRef& shared) { Node* node, const SharedFunctionInfoRef& shared) {
DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
if (!h.can_reduce()) return h.inference()->NoChange(); if (!h.can_reduce()) return h.inference()->NoChange();
IteratingArrayBuiltinReducerAssembler a(jsgraph(), temp_zone(), node); IteratingArrayBuiltinReducerAssembler a(jsgraph(), temp_zone(), node);
a.InitializeEffectControl(h.effect(), h.control()); a.InitializeEffectControl(h.effect(), h.control());
STNode<Object> subgraph = a.ReduceArrayPrototypeReduce( TNode<Object> subgraph = a.ReduceArrayPrototypeReduce(
h.inference(), h.has_stability_dependency(), h.elements_kind(), h.inference(), h.has_stability_dependency(), h.elements_kind(),
ArrayReduceDirection::kRight, shared); ArrayReduceDirection::kRight, shared);
return ReplaceWithSubgraph(&a, subgraph); return ReplaceWithSubgraph(&a, subgraph);
......
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