| Index: src/compiler/typer.cc
|
| diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
|
| index 73fe41d58291ff3dfbe0637b6dcc7c103b0041e9..5dfd4388c9a1dffedece85c52ce951ab38cf2e1d 100644
|
| --- a/src/compiler/typer.cc
|
| +++ b/src/compiler/typer.cc
|
| @@ -2,6 +2,7 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include "src/bootstrapper.h"
|
| #include "src/compiler/graph-inl.h"
|
| #include "src/compiler/js-operator.h"
|
| #include "src/compiler/node.h"
|
| @@ -14,7 +15,21 @@ namespace v8 {
|
| namespace internal {
|
| namespace compiler {
|
|
|
| -Typer::Typer(Zone* zone) : zone_(zone) {
|
| +
|
| +class Typer::Decorator : public GraphDecorator {
|
| + public:
|
| + explicit Decorator(Typer* typer) : typer_(typer) {}
|
| + virtual void Decorate(Node* node);
|
| +
|
| + private:
|
| + static bool AllInputsAreTyped(Node* node);
|
| + Typer* typer_;
|
| +};
|
| +
|
| +
|
| +Typer::Typer(Graph* graph, MaybeHandle<Context> context)
|
| + : graph_(graph), context_(context), decorator_(NULL) {
|
| + Zone* zone = this->zone();
|
| Type* number = Type::Number(zone);
|
| Type* signed32 = Type::Signed32(zone);
|
| Type* unsigned32 = Type::Unsigned32(zone);
|
| @@ -59,78 +74,84 @@ Typer::Typer(Zone* zone) : zone_(zone) {
|
| uint32_array_fun_ = Type::Function(uint32_array, arg1, arg2, arg3, zone);
|
| float32_array_fun_ = Type::Function(float32_array, arg1, arg2, arg3, zone);
|
| float64_array_fun_ = Type::Function(float64_array, arg1, arg2, arg3, zone);
|
| +
|
| + decorator_ = new (zone) Decorator(this);
|
| + graph_->AddDecorator(decorator_);
|
| +}
|
| +
|
| +
|
| +Typer::~Typer() {
|
| + if (decorator_) graph_->RemoveDecorator(decorator_);
|
| }
|
|
|
|
|
| class Typer::Visitor : public NullNodeVisitor {
|
| public:
|
| - Visitor(Typer* typer, MaybeHandle<Context> context)
|
| - : typer_(typer), context_(context) {}
|
| + explicit Visitor(Typer* typer) : typer_(typer) {}
|
|
|
| Bounds TypeNode(Node* node) {
|
| switch (node->opcode()) {
|
| #define DECLARE_CASE(x) case IrOpcode::k##x: return Type##x(node);
|
| + DECLARE_CASE(Start)
|
| VALUE_OP_LIST(DECLARE_CASE)
|
| #undef DECLARE_CASE
|
|
|
| #define DECLARE_CASE(x) case IrOpcode::k##x:
|
| - CONTROL_OP_LIST(DECLARE_CASE)
|
| + DECLARE_CASE(End)
|
| + INNER_CONTROL_OP_LIST(DECLARE_CASE)
|
| #undef DECLARE_CASE
|
| break;
|
| }
|
| - return Bounds(Type::None(zone()));
|
| + UNREACHABLE();
|
| + return Bounds();
|
| }
|
|
|
| Type* TypeConstant(Handle<Object> value);
|
|
|
| protected:
|
| #define DECLARE_METHOD(x) inline Bounds Type##x(Node* node);
|
| + DECLARE_METHOD(Start)
|
| VALUE_OP_LIST(DECLARE_METHOD)
|
| #undef DECLARE_METHOD
|
|
|
| - Bounds OperandType(Node* node, int i) {
|
| - return NodeProperties::GetBounds(NodeProperties::GetValueInput(node, i));
|
| + Bounds operand(Node* node, int i) {
|
| + Node* operand_node = NodeProperties::GetValueInput(node, i);
|
| + return GetBoundsOrNone(operand_node);
|
| }
|
|
|
| - Type* ContextType(Node* node) {
|
| - Bounds result =
|
| - NodeProperties::GetBounds(NodeProperties::GetContextInput(node));
|
| - DCHECK(result.upper->Is(Type::Internal()));
|
| - DCHECK(result.lower->Equals(result.upper));
|
| + Type* context_type(Node* node) {
|
| + Bounds result = GetBoundsOrNone(NodeProperties::GetContextInput(node));
|
| + DCHECK(result.upper->Maybe(Type::Internal()));
|
| return result.upper;
|
| }
|
|
|
| Zone* zone() { return typer_->zone(); }
|
| Isolate* isolate() { return typer_->isolate(); }
|
| - MaybeHandle<Context> context() { return context_; }
|
| + Graph* graph() { return typer_->graph(); }
|
| + MaybeHandle<Context> context() { return typer_->context(); }
|
|
|
| private:
|
| Typer* typer_;
|
| - MaybeHandle<Context> context_;
|
| +
|
| + Bounds GetBoundsOrNone(Node* node) {
|
| + return NodeProperties::IsTyped(node)
|
| + ? NodeProperties::GetBounds(node) : Bounds(Type::None(zone()));
|
| + }
|
| };
|
|
|
|
|
| class Typer::RunVisitor : public Typer::Visitor {
|
| public:
|
| - RunVisitor(Typer* typer, MaybeHandle<Context> context)
|
| - : Visitor(typer, context),
|
| + explicit RunVisitor(Typer* typer)
|
| + : Visitor(typer),
|
| phis(NodeSet::key_compare(), NodeSet::allocator_type(typer->zone())) {}
|
|
|
| - GenericGraphVisit::Control Pre(Node* node) {
|
| - return NodeProperties::IsControl(node)
|
| - && node->opcode() != IrOpcode::kEnd
|
| - && node->opcode() != IrOpcode::kMerge
|
| - && node->opcode() != IrOpcode::kReturn
|
| - ? GenericGraphVisit::SKIP : GenericGraphVisit::CONTINUE;
|
| - }
|
| -
|
| GenericGraphVisit::Control Post(Node* node) {
|
| - Bounds bounds = TypeNode(node);
|
| - if (node->opcode() == IrOpcode::kPhi) {
|
| - // Remember phis for least fixpoint iteration.
|
| - phis.insert(node);
|
| - } else {
|
| + if (OperatorProperties::HasValueOutput(node->op())) {
|
| + Bounds bounds = TypeNode(node);
|
| NodeProperties::SetBounds(node, bounds);
|
| + // Remember phis for least fixpoint iteration.
|
| + if (node->opcode() == IrOpcode::kPhi) phis.insert(node);
|
| }
|
| return GenericGraphVisit::CONTINUE;
|
| }
|
| @@ -141,17 +162,20 @@ class Typer::RunVisitor : public Typer::Visitor {
|
|
|
| class Typer::NarrowVisitor : public Typer::Visitor {
|
| public:
|
| - NarrowVisitor(Typer* typer, MaybeHandle<Context> context)
|
| - : Visitor(typer, context) {}
|
| + explicit NarrowVisitor(Typer* typer) : Visitor(typer) {}
|
|
|
| GenericGraphVisit::Control Pre(Node* node) {
|
| - Bounds previous = NodeProperties::GetBounds(node);
|
| - Bounds bounds = TypeNode(node);
|
| - NodeProperties::SetBounds(node, Bounds::Both(bounds, previous, zone()));
|
| - DCHECK(bounds.Narrows(previous));
|
| - // Stop when nothing changed (but allow reentry in case it does later).
|
| - return previous.Narrows(bounds)
|
| - ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
|
| + if (OperatorProperties::HasValueOutput(node->op())) {
|
| + Bounds previous = NodeProperties::GetBounds(node);
|
| + Bounds bounds = TypeNode(node);
|
| + NodeProperties::SetBounds(node, Bounds::Both(bounds, previous, zone()));
|
| + DCHECK(bounds.Narrows(previous));
|
| + // Stop when nothing changed (but allow re-entry in case it does later).
|
| + return previous.Narrows(bounds)
|
| + ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
|
| + } else {
|
| + return GenericGraphVisit::SKIP;
|
| + }
|
| }
|
|
|
| GenericGraphVisit::Control Post(Node* node) {
|
| @@ -162,18 +186,21 @@ class Typer::NarrowVisitor : public Typer::Visitor {
|
|
|
| class Typer::WidenVisitor : public Typer::Visitor {
|
| public:
|
| - WidenVisitor(Typer* typer, MaybeHandle<Context> context)
|
| - : Visitor(typer, context) {}
|
| + explicit WidenVisitor(Typer* typer) : Visitor(typer) {}
|
|
|
| GenericGraphVisit::Control Pre(Node* node) {
|
| - Bounds previous = NodeProperties::GetBounds(node);
|
| - Bounds bounds = TypeNode(node);
|
| - DCHECK(previous.lower->Is(bounds.lower));
|
| - DCHECK(previous.upper->Is(bounds.upper));
|
| - NodeProperties::SetBounds(node, bounds); // TODO(rossberg): Either?
|
| - // Stop when nothing changed (but allow reentry in case it does later).
|
| - return bounds.Narrows(previous)
|
| - ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
|
| + if (OperatorProperties::HasValueOutput(node->op())) {
|
| + Bounds previous = NodeProperties::GetBounds(node);
|
| + Bounds bounds = TypeNode(node);
|
| + DCHECK(previous.lower->Is(bounds.lower));
|
| + DCHECK(previous.upper->Is(bounds.upper));
|
| + NodeProperties::SetBounds(node, bounds); // TODO(rossberg): Either?
|
| + // Stop when nothing changed (but allow re-entry in case it does later).
|
| + return bounds.Narrows(previous)
|
| + ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
|
| + } else {
|
| + return GenericGraphVisit::SKIP;
|
| + }
|
| }
|
|
|
| GenericGraphVisit::Control Post(Node* node) {
|
| @@ -182,36 +209,63 @@ class Typer::WidenVisitor : public Typer::Visitor {
|
| };
|
|
|
|
|
| -void Typer::Run(Graph* graph, MaybeHandle<Context> context) {
|
| - RunVisitor typing(this, context);
|
| - graph->VisitNodeInputsFromEnd(&typing);
|
| +void Typer::Run() {
|
| + RunVisitor typing(this);
|
| + graph_->VisitNodeInputsFromEnd(&typing);
|
| // Find least fixpoint.
|
| - for (NodeSetIter i = typing.phis.begin(); i != typing.phis.end(); ++i) {
|
| - Widen(graph, *i, context);
|
| + WidenVisitor widen(this);
|
| + for (NodeSetIter it = typing.phis.begin(); it != typing.phis.end(); ++it) {
|
| + graph_->VisitNodeUsesFrom(*it, &widen);
|
| }
|
| }
|
|
|
|
|
| -void Typer::Narrow(Graph* graph, Node* start, MaybeHandle<Context> context) {
|
| - NarrowVisitor typing(this, context);
|
| - graph->VisitNodeUsesFrom(start, &typing);
|
| +void Typer::Narrow(Node* start) {
|
| + NarrowVisitor typing(this);
|
| + graph_->VisitNodeUsesFrom(start, &typing);
|
| +}
|
| +
|
| +
|
| +void Typer::Decorator::Decorate(Node* node) {
|
| + if (OperatorProperties::HasValueOutput(node->op())) {
|
| + // Only eagerly type-decorate nodes with known input types.
|
| + // Other cases will generally require a proper fixpoint iteration with Run.
|
| + bool is_typed = NodeProperties::IsTyped(node);
|
| + if (is_typed || AllInputsAreTyped(node)) {
|
| + Visitor typing(typer_);
|
| + Bounds bounds = typing.TypeNode(node);
|
| + if (is_typed) {
|
| + bounds =
|
| + Bounds::Both(bounds, NodeProperties::GetBounds(node), typer_->zone());
|
| + }
|
| + NodeProperties::SetBounds(node, bounds);
|
| + }
|
| + }
|
| }
|
|
|
|
|
| -void Typer::Widen(Graph* graph, Node* start, MaybeHandle<Context> context) {
|
| - WidenVisitor typing(this, context);
|
| - graph->VisitNodeUsesFrom(start, &typing);
|
| +bool Typer::Decorator::AllInputsAreTyped(Node* node) {
|
| + int input_count = OperatorProperties::GetValueInputCount(node->op());
|
| + for (int i = 0; i < input_count; ++i) {
|
| + if (!NodeProperties::IsTyped(NodeProperties::GetValueInput(node, i))) {
|
| + return false;
|
| + }
|
| + }
|
| + return OperatorProperties::GetContextInputCount(node->op()) == 0
|
| + || NodeProperties::IsTyped(NodeProperties::GetContextInput(node));
|
| }
|
|
|
|
|
| -void Typer::Init(Node* node) {
|
| - Visitor typing(this, MaybeHandle<Context>());
|
| - Bounds bounds = typing.TypeNode(node);
|
| - NodeProperties::SetBounds(node, bounds);
|
| +// -----------------------------------------------------------------------------
|
| +// Control operators.
|
| +
|
| +Bounds Typer::Visitor::TypeStart(Node* node) {
|
| + return Bounds(Type::Internal(zone()));
|
| }
|
|
|
|
|
| // Common operators.
|
| +
|
| Bounds Typer::Visitor::TypeParameter(Node* node) {
|
| return Bounds::Unbounded(zone());
|
| }
|
| @@ -254,39 +308,44 @@ Bounds Typer::Visitor::TypeExternalConstant(Node* node) {
|
|
|
| Bounds Typer::Visitor::TypePhi(Node* node) {
|
| int arity = OperatorProperties::GetValueInputCount(node->op());
|
| - Bounds bounds = OperandType(node, 0);
|
| + Bounds bounds = operand(node, 0);
|
| for (int i = 1; i < arity; ++i) {
|
| - bounds = Bounds::Either(bounds, OperandType(node, i), zone());
|
| + bounds = Bounds::Either(bounds, operand(node, i), zone());
|
| }
|
| return bounds;
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeEffectPhi(Node* node) {
|
| - return Bounds(Type::None(zone()));
|
| + UNREACHABLE();
|
| + return Bounds();
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeControlEffect(Node* node) {
|
| - return Bounds(Type::None(zone()));
|
| + UNREACHABLE();
|
| + return Bounds();
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeValueEffect(Node* node) {
|
| - return Bounds(Type::None(zone()));
|
| + UNREACHABLE();
|
| + return Bounds();
|
| }
|
|
|
|
|
| -Bounds Typer::Visitor::TypeFinish(Node* node) { return OperandType(node, 0); }
|
| +Bounds Typer::Visitor::TypeFinish(Node* node) {
|
| + return operand(node, 0);
|
| +}
|
|
|
|
|
| Bounds Typer::Visitor::TypeFrameState(Node* node) {
|
| - return Bounds(Type::None(zone()));
|
| + return Bounds::Unbounded(zone());
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeStateValues(Node* node) {
|
| - return Bounds(Type::None(zone()));
|
| + return Bounds::Unbounded(zone());
|
| }
|
|
|
|
|
| @@ -314,8 +373,8 @@ JS_COMPARE_BINOP_LIST(DEFINE_METHOD)
|
| // JS bitwise operators.
|
|
|
| Bounds Typer::Visitor::TypeJSBitwiseOr(Node* node) {
|
| - Bounds left = OperandType(node, 0);
|
| - Bounds right = OperandType(node, 1);
|
| + Bounds left = operand(node, 0);
|
| + Bounds right = operand(node, 1);
|
| Type* upper = Type::Union(left.upper, right.upper, zone());
|
| if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
|
| Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
|
| @@ -324,8 +383,8 @@ Bounds Typer::Visitor::TypeJSBitwiseOr(Node* node) {
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSBitwiseAnd(Node* node) {
|
| - Bounds left = OperandType(node, 0);
|
| - Bounds right = OperandType(node, 1);
|
| + Bounds left = operand(node, 0);
|
| + Bounds right = operand(node, 1);
|
| Type* upper = Type::Union(left.upper, right.upper, zone());
|
| if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
|
| Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
|
| @@ -356,8 +415,8 @@ Bounds Typer::Visitor::TypeJSShiftRightLogical(Node* node) {
|
| // JS arithmetic operators.
|
|
|
| Bounds Typer::Visitor::TypeJSAdd(Node* node) {
|
| - Bounds left = OperandType(node, 0);
|
| - Bounds right = OperandType(node, 1);
|
| + Bounds left = operand(node, 0);
|
| + Bounds right = operand(node, 1);
|
| Type* lower =
|
| left.lower->Is(Type::None()) || right.lower->Is(Type::None()) ?
|
| Type::None(zone()) :
|
| @@ -431,7 +490,7 @@ Bounds Typer::Visitor::TypeJSToName(Node* node) {
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSToObject(Node* node) {
|
| - return Bounds(Type::None(zone()), Type::Object(zone()));
|
| + return Bounds(Type::None(zone()), Type::Receiver(zone()));
|
| }
|
|
|
|
|
| @@ -443,8 +502,8 @@ Bounds Typer::Visitor::TypeJSCreate(Node* node) {
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSLoadProperty(Node* node) {
|
| - Bounds object = OperandType(node, 0);
|
| - Bounds name = OperandType(node, 1);
|
| + Bounds object = operand(node, 0);
|
| + Bounds name = operand(node, 1);
|
| Bounds result = Bounds::Unbounded(zone());
|
| // TODO(rossberg): Use range types and sized array types to filter undefined.
|
| if (object.lower->IsArray() && name.lower->Is(Type::Integral32())) {
|
| @@ -465,12 +524,14 @@ Bounds Typer::Visitor::TypeJSLoadNamed(Node* node) {
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSStoreProperty(Node* node) {
|
| - return Bounds(Type::None(zone()));
|
| + UNREACHABLE();
|
| + return Bounds();
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSStoreNamed(Node* node) {
|
| - return Bounds(Type::None(zone()));
|
| + UNREACHABLE();
|
| + return Bounds();
|
| }
|
|
|
|
|
| @@ -492,9 +553,11 @@ Bounds Typer::Visitor::TypeJSInstanceOf(Node* node) {
|
| // JS context operators.
|
|
|
| Bounds Typer::Visitor::TypeJSLoadContext(Node* node) {
|
| - Bounds outer = OperandType(node, 0);
|
| - DCHECK(outer.upper->Is(Type::Internal()));
|
| - DCHECK(outer.lower->Equals(outer.upper));
|
| + Bounds outer = operand(node, 0);
|
| + DCHECK(outer.upper->Maybe(Type::Internal()));
|
| + // TODO(rossberg): More precisely, instead of the above assertion, we should
|
| + // back-propagate the constraint that it has to be a subtype of Internal.
|
| +
|
| ContextAccess access = OpParameter<ContextAccess>(node);
|
| Type* context_type = outer.upper;
|
| MaybeHandle<Context> context;
|
| @@ -512,7 +575,7 @@ Bounds Typer::Visitor::TypeJSLoadContext(Node* node) {
|
| if (context_type->IsConstant()) {
|
| context = Handle<Context>::cast(context_type->AsConstant()->Value());
|
| }
|
| - } else {
|
| + } else if (!context.is_null()) {
|
| context = handle(context.ToHandleChecked()->previous(), isolate());
|
| }
|
| }
|
| @@ -528,43 +591,44 @@ Bounds Typer::Visitor::TypeJSLoadContext(Node* node) {
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSStoreContext(Node* node) {
|
| - return Bounds(Type::None(zone()));
|
| + UNREACHABLE();
|
| + return Bounds();
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSCreateFunctionContext(Node* node) {
|
| - Type* outer = ContextType(node);
|
| + Type* outer = context_type(node);
|
| return Bounds(Type::Context(outer, zone()));
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSCreateCatchContext(Node* node) {
|
| - Type* outer = ContextType(node);
|
| + Type* outer = context_type(node);
|
| return Bounds(Type::Context(outer, zone()));
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSCreateWithContext(Node* node) {
|
| - Type* outer = ContextType(node);
|
| + Type* outer = context_type(node);
|
| return Bounds(Type::Context(outer, zone()));
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSCreateBlockContext(Node* node) {
|
| - Type* outer = ContextType(node);
|
| + Type* outer = context_type(node);
|
| return Bounds(Type::Context(outer, zone()));
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSCreateModuleContext(Node* node) {
|
| // TODO(rossberg): this is probably incorrect
|
| - Type* outer = ContextType(node);
|
| + Type* outer = context_type(node);
|
| return Bounds(Type::Context(outer, zone()));
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSCreateGlobalContext(Node* node) {
|
| - Type* outer = ContextType(node);
|
| + Type* outer = context_type(node);
|
| return Bounds(Type::Context(outer, zone()));
|
| }
|
|
|
| @@ -582,7 +646,7 @@ Bounds Typer::Visitor::TypeJSCallConstruct(Node* node) {
|
|
|
|
|
| Bounds Typer::Visitor::TypeJSCallFunction(Node* node) {
|
| - Bounds fun = OperandType(node, 0);
|
| + Bounds fun = operand(node, 0);
|
| Type* lower = fun.lower->IsFunction()
|
| ? fun.lower->AsFunction()->Result() : Type::None(zone());
|
| Type* upper = fun.upper->IsFunction()
|
| @@ -649,7 +713,7 @@ Bounds Typer::Visitor::TypeNumberModulus(Node* node) {
|
|
|
|
|
| Bounds Typer::Visitor::TypeNumberToInt32(Node* node) {
|
| - Bounds arg = OperandType(node, 0);
|
| + Bounds arg = operand(node, 0);
|
| Type* s32 = Type::Signed32(zone());
|
| Type* lower = arg.lower->Is(s32) ? arg.lower : s32;
|
| Type* upper = arg.upper->Is(s32) ? arg.upper : s32;
|
| @@ -658,7 +722,7 @@ Bounds Typer::Visitor::TypeNumberToInt32(Node* node) {
|
|
|
|
|
| Bounds Typer::Visitor::TypeNumberToUint32(Node* node) {
|
| - Bounds arg = OperandType(node, 0);
|
| + Bounds arg = operand(node, 0);
|
| Type* u32 = Type::Unsigned32(zone());
|
| Type* lower = arg.lower->Is(u32) ? arg.lower : u32;
|
| Type* upper = arg.upper->Is(u32) ? arg.upper : u32;
|
| @@ -749,12 +813,14 @@ Bounds Typer::Visitor::TypeLoadElement(Node* node) {
|
|
|
|
|
| Bounds Typer::Visitor::TypeStoreField(Node* node) {
|
| - return Bounds(Type::None());
|
| + UNREACHABLE();
|
| + return Bounds();
|
| }
|
|
|
|
|
| Bounds Typer::Visitor::TypeStoreElement(Node* node) {
|
| - return Bounds(Type::None());
|
| + UNREACHABLE();
|
| + return Bounds();
|
| }
|
|
|
|
|
| @@ -771,7 +837,7 @@ MACHINE_OP_LIST(DEFINE_METHOD)
|
|
|
| Type* Typer::Visitor::TypeConstant(Handle<Object> value) {
|
| if (value->IsJSFunction() && JSFunction::cast(*value)->IsBuiltin() &&
|
| - !context().is_null()) {
|
| + !context().is_null() && !isolate()->bootstrapper()->IsActive()) {
|
| Handle<Context> native =
|
| handle(context().ToHandleChecked()->native_context(), isolate());
|
| if (*value == native->math_abs_fun()) {
|
| @@ -831,25 +897,6 @@ Type* Typer::Visitor::TypeConstant(Handle<Object> value) {
|
| return Type::Constant(value, zone());
|
| }
|
|
|
| -
|
| -namespace {
|
| -
|
| -class TyperDecorator : public GraphDecorator {
|
| - public:
|
| - explicit TyperDecorator(Typer* typer) : typer_(typer) {}
|
| - virtual void Decorate(Node* node) { typer_->Init(node); }
|
| -
|
| - private:
|
| - Typer* typer_;
|
| -};
|
| -
|
| -}
|
| -
|
| -
|
| -void Typer::DecorateGraph(Graph* graph) {
|
| - graph->AddDecorator(new (zone()) TyperDecorator(this));
|
| -}
|
| -
|
| }
|
| }
|
| } // namespace v8::internal::compiler
|
|
|