Index: src/compiler/typer.cc |
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc |
index 2430d40e00a5df787f9f1a0b4f737144af17e2ea..b3ea7ffa03fac4dc7ad1bfaa9568adab3bad11aa 100644 |
--- a/src/compiler/typer.cc |
+++ b/src/compiler/typer.cc |
@@ -7,6 +7,7 @@ |
#include "src/base/flags.h" |
#include "src/base/lazy-instance.h" |
#include "src/bootstrapper.h" |
+#include "src/compilation-dependencies.h" |
#include "src/compiler/common-operator.h" |
#include "src/compiler/graph-reducer.h" |
#include "src/compiler/js-operator.h" |
@@ -37,9 +38,13 @@ class Typer::Decorator final : public GraphDecorator { |
}; |
-Typer::Typer(Isolate* isolate, Graph* graph, Type::FunctionType* function_type) |
+Typer::Typer(Isolate* isolate, Graph* graph, Flags flags, |
+ CompilationDependencies* dependencies, |
+ Type::FunctionType* function_type) |
: isolate_(isolate), |
graph_(graph), |
+ flags_(flags), |
+ dependencies_(dependencies), |
function_type_(function_type), |
decorator_(nullptr), |
cache_(kCache.Get()) { |
@@ -204,6 +209,10 @@ class Typer::Visitor : public Reducer { |
Zone* zone() { return typer_->zone(); } |
Isolate* isolate() { return typer_->isolate(); } |
Graph* graph() { return typer_->graph(); } |
+ Typer::Flags flags() const { return typer_->flags(); } |
+ CompilationDependencies* dependencies() const { |
+ return typer_->dependencies(); |
+ } |
void SetWeakened(NodeId node_id) { weakened_nodes_.insert(node_id); } |
bool IsWeakened(NodeId node_id) { |
@@ -252,6 +261,8 @@ class Typer::Visitor : public Reducer { |
static Type* JSLoadPropertyTyper(Type*, Type*, Typer*); |
static Type* JSCallFunctionTyper(Type*, Typer*); |
+ static Type* ReferenceEqualTyper(Type*, Type*, Typer*); |
+ |
Reduction UpdateType(Node* node, Type* current) { |
if (NodeProperties::IsTyped(node)) { |
// Widen the type of a previously typed node. |
@@ -1575,8 +1586,17 @@ Type* Typer::Visitor::TypePlainPrimitiveToNumber(Node* node) { |
} |
+// static |
+Type* Typer::Visitor::ReferenceEqualTyper(Type* lhs, Type* rhs, Typer* t) { |
+ if (lhs->IsConstant() && rhs->Is(lhs)) { |
+ return t->singleton_true_; |
+ } |
+ return Type::Boolean(); |
+} |
+ |
+ |
Type* Typer::Visitor::TypeReferenceEqual(Node* node) { |
- return Type::Boolean(zone()); |
+ return TypeBinaryOp(node, ReferenceEqualTyper); |
} |
@@ -1666,8 +1686,53 @@ Type* Typer::Visitor::TypeChangeBitToBool(Node* node) { |
Type* Typer::Visitor::TypeAllocate(Node* node) { return Type::TaggedPointer(); } |
+namespace { |
+ |
+MaybeHandle<Map> GetStableMapFromObjectType(Type* object_type) { |
+ if (object_type->IsConstant() && |
+ object_type->AsConstant()->Value()->IsHeapObject()) { |
+ Handle<Map> object_map( |
+ Handle<HeapObject>::cast(object_type->AsConstant()->Value())->map()); |
+ if (object_map->is_stable()) return object_map; |
+ } else if (object_type->IsClass()) { |
+ Handle<Map> object_map = object_type->AsClass()->Map(); |
+ if (object_map->is_stable()) return object_map; |
+ } |
+ return MaybeHandle<Map>(); |
+} |
+ |
+} // namespace |
+ |
+ |
Type* Typer::Visitor::TypeLoadField(Node* node) { |
- return FieldAccessOf(node->op()).type; |
+ FieldAccess const& access = FieldAccessOf(node->op()); |
+ if (access.base_is_tagged == kTaggedBase && |
+ access.offset == HeapObject::kMapOffset) { |
+ // The type of LoadField[Map](o) is Constant(map) if map is stable and |
+ // either |
+ // (a) o has type Constant(object) and map == object->map, or |
+ // (b) o has type Class(map), |
+ // and either |
+ // (1) map cannot transition further, or |
+ // (2) deoptimization is enabled and we can add a code dependency on the |
+ // stability of map (to guard the Constant type information). |
+ Type* const object = Operand(node, 0); |
+ if (object->Is(Type::None())) return Type::None(); |
+ Handle<Map> object_map; |
+ if (GetStableMapFromObjectType(object).ToHandle(&object_map)) { |
+ if (object_map->CanTransition()) { |
+ if (flags() & kDeoptimizationEnabled) { |
+ dependencies()->AssumeMapStable(object_map); |
+ } else { |
+ return access.type; |
+ } |
+ } |
+ Type* object_map_type = Type::Constant(object_map, zone()); |
+ DCHECK(object_map_type->Is(access.type)); |
+ return object_map_type; |
+ } |
+ } |
+ return access.type; |
} |