[turbofan] Use the heap broker in JSContextSpecialization.

No longer access the heap directly, as policed by Disallow*
scopes in JSContextSpecialization::Reduce.

Bug: v8:7790
Change-Id: I40f1c500b04b96152421fd5de631747ba386bca1
Reviewed-on: https://chromium-review.googlesource.com/1101322
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53759}
This commit is contained in:
Georg Neis 2018-06-15 12:51:56 +02:00 committed by Commit Bot
parent c032039bf0
commit 9480117e41
8 changed files with 149 additions and 39 deletions

View File

@ -17,6 +17,11 @@ namespace internal {
namespace compiler { namespace compiler {
Reduction JSContextSpecialization::Reduce(Node* node) { Reduction JSContextSpecialization::Reduce(Node* node) {
DisallowHeapAllocation no_heap_allocation;
DisallowHandleAllocation no_handle_allocation;
DisallowHandleDereference no_handle_dereference;
DisallowCodeDependencyChange no_dependency_change;
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kParameter: case IrOpcode::kParameter:
return ReduceParameter(node); return ReduceParameter(node);
@ -99,12 +104,14 @@ bool IsContextParameter(Node* node) {
// context (which we want to read from or store to), try to return a // context (which we want to read from or store to), try to return a
// specialization context. If successful, update {distance} to whatever // specialization context. If successful, update {distance} to whatever
// distance remains from the specialization context. // distance remains from the specialization context.
MaybeHandle<Context> GetSpecializationContext(Node* node, size_t* distance, base::Optional<ContextHeapReference> GetSpecializationContext(
Maybe<OuterContext> maybe_outer) { const JSHeapBroker* broker, Node* node, size_t* distance,
Maybe<OuterContext> maybe_outer) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kHeapConstant: { case IrOpcode::kHeapConstant: {
Handle<Object> object = HeapConstantOf(node->op()); HeapReference object =
if (object->IsContext()) return Handle<Context>::cast(object); broker->HeapReferenceForObject(HeapConstantOf(node->op()));
if (object.IsContext()) return object.AsContext();
break; break;
} }
case IrOpcode::kParameter: { case IrOpcode::kParameter: {
@ -112,14 +119,14 @@ MaybeHandle<Context> GetSpecializationContext(Node* node, size_t* distance,
if (maybe_outer.To(&outer) && IsContextParameter(node) && if (maybe_outer.To(&outer) && IsContextParameter(node) &&
*distance >= outer.distance) { *distance >= outer.distance) {
*distance -= outer.distance; *distance -= outer.distance;
return outer.context; return broker->HeapReferenceForObject(outer.context).AsContext();
} }
break; break;
} }
default: default:
break; break;
} }
return MaybeHandle<Context>(); return base::Optional<ContextHeapReference>();
} }
} // anonymous namespace } // anonymous namespace
@ -133,39 +140,57 @@ Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
// First walk up the context chain in the graph as far as possible. // First walk up the context chain in the graph as far as possible.
Node* context = NodeProperties::GetOuterContext(node, &depth); Node* context = NodeProperties::GetOuterContext(node, &depth);
Handle<Context> concrete; base::Optional<ContextHeapReference> maybe_concrete =
if (!GetSpecializationContext(context, &depth, outer()).ToHandle(&concrete)) { GetSpecializationContext(js_heap_broker(), context, &depth, outer());
if (!maybe_concrete.has_value()) {
// We do not have a concrete context object, so we can only partially reduce // We do not have a concrete context object, so we can only partially reduce
// the load by folding-in the outer context node. // the load by folding-in the outer context node.
return SimplifyJSLoadContext(node, context, depth); return SimplifyJSLoadContext(node, context, depth);
} }
// Now walk up the concrete context chain for the remaining depth. // Now walk up the concrete context chain for the remaining depth.
ContextHeapReference concrete = maybe_concrete.value();
for (; depth > 0; --depth) { for (; depth > 0; --depth) {
concrete = handle(concrete->previous(), isolate()); concrete = concrete.previous(js_heap_broker()).value();
} }
if (!access.immutable()) { if (!access.immutable()) {
// We found the requested context object but since the context slot is // We found the requested context object but since the context slot is
// mutable we can only partially reduce the load. // mutable we can only partially reduce the load.
return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth); return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete.object()),
depth);
} }
// Even though the context slot is immutable, the context might have escaped // This will hold the final value, if we can figure it out.
// before the function to which it belongs has initialized the slot. base::Optional<ObjectReference> maybe_value;
// We must be conservative and check if the value in the slot is currently
// the hole or undefined. Only if it is neither of these, can we be sure that maybe_value =
// it won't change anymore. concrete.get(js_heap_broker(), static_cast<int>(access.index()));
Handle<Object> value(concrete->get(static_cast<int>(access.index())), if (maybe_value.has_value() && !maybe_value->IsSmi()) {
isolate()); // Even though the context slot is immutable, the context might have escaped
if (value->IsUndefined(isolate()) || value->IsTheHole(isolate())) { // before the function to which it belongs has initialized the slot.
return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth); // We must be conservative and check if the value in the slot is currently
// the hole or undefined. Only if it is neither of these, can we be sure
// that it won't change anymore.
HeapReferenceType type =
maybe_value->AsHeapReference().type(js_heap_broker());
if (type.oddball_type() == HeapReferenceType::kAny ||
type.oddball_type() == HeapReferenceType::kUndefined ||
type.oddball_type() == HeapReferenceType::kHole) {
maybe_value.reset();
}
}
if (!maybe_value.has_value()) {
return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete.object()),
depth);
} }
// Success. The context load can be replaced with the constant. // Success. The context load can be replaced with the constant.
// TODO(titzer): record the specialization for sharing code across multiple // TODO(titzer): record the specialization for sharing code across
// contexts that have the same value in the corresponding context slot. // multiple contexts that have the same value in the corresponding context
Node* constant = jsgraph_->Constant(value); // slot.
Node* constant = jsgraph_->Constant(maybe_value->object());
ReplaceWithValue(node, constant); ReplaceWithValue(node, constant);
return Replace(constant); return Replace(constant);
} }
@ -181,19 +206,22 @@ Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
// or hit a node that does not have a CreateXYZContext operator. // or hit a node that does not have a CreateXYZContext operator.
Node* context = NodeProperties::GetOuterContext(node, &depth); Node* context = NodeProperties::GetOuterContext(node, &depth);
Handle<Context> concrete; base::Optional<ContextHeapReference> maybe_concrete =
if (!GetSpecializationContext(context, &depth, outer()).ToHandle(&concrete)) { GetSpecializationContext(js_heap_broker(), context, &depth, outer());
if (!maybe_concrete.has_value()) {
// We do not have a concrete context object, so we can only partially reduce // We do not have a concrete context object, so we can only partially reduce
// the load by folding-in the outer context node. // the load by folding-in the outer context node.
return SimplifyJSStoreContext(node, context, depth); return SimplifyJSStoreContext(node, context, depth);
} }
// Now walk up the concrete context chain for the remaining depth. // Now walk up the concrete context chain for the remaining depth.
ContextHeapReference concrete = maybe_concrete.value();
for (; depth > 0; --depth) { for (; depth > 0; --depth) {
concrete = handle(concrete->previous(), isolate()); concrete = concrete.previous(js_heap_broker()).value();
} }
return SimplifyJSStoreContext(node, jsgraph()->Constant(concrete), depth); return SimplifyJSStoreContext(node, jsgraph()->Constant(concrete.object()),
depth);
} }

View File

@ -33,12 +33,14 @@ struct OuterContext {
class JSContextSpecialization final : public AdvancedReducer { class JSContextSpecialization final : public AdvancedReducer {
public: public:
JSContextSpecialization(Editor* editor, JSGraph* jsgraph, JSContextSpecialization(Editor* editor, JSGraph* jsgraph,
JSHeapBroker* js_heap_broker,
Maybe<OuterContext> outer, Maybe<OuterContext> outer,
MaybeHandle<JSFunction> closure) MaybeHandle<JSFunction> closure)
: AdvancedReducer(editor), : AdvancedReducer(editor),
jsgraph_(jsgraph), jsgraph_(jsgraph),
outer_(outer), outer_(outer),
closure_(closure) {} closure_(closure),
js_heap_broker_(js_heap_broker) {}
const char* reducer_name() const override { const char* reducer_name() const override {
return "JSContextSpecialization"; return "JSContextSpecialization";
@ -60,10 +62,12 @@ class JSContextSpecialization final : public AdvancedReducer {
JSGraph* jsgraph() const { return jsgraph_; } JSGraph* jsgraph() const { return jsgraph_; }
Maybe<OuterContext> outer() const { return outer_; } Maybe<OuterContext> outer() const { return outer_; }
MaybeHandle<JSFunction> closure() const { return closure_; } MaybeHandle<JSFunction> closure() const { return closure_; }
const JSHeapBroker* js_heap_broker() const { return js_heap_broker_; }
JSGraph* const jsgraph_; JSGraph* const jsgraph_;
Maybe<OuterContext> outer_; Maybe<OuterContext> outer_;
MaybeHandle<JSFunction> closure_; MaybeHandle<JSFunction> closure_;
const JSHeapBroker* const js_heap_broker_;
DISALLOW_COPY_AND_ASSIGN(JSContextSpecialization); DISALLOW_COPY_AND_ASSIGN(JSContextSpecialization);
}; };

View File

@ -47,6 +47,7 @@ Node* JSGraph::CEntryStubConstant(int result_size, SaveFPRegsMode save_doubles,
} }
Node* JSGraph::Constant(Handle<Object> value) { Node* JSGraph::Constant(Handle<Object> value) {
AllowHandleDereference handle_dereference;
// Dereference the handle to determine if a number constant or other // Dereference the handle to determine if a number constant or other
// canonicalized node can be used. // canonicalized node can be used.
if (value->IsNumber()) { if (value->IsNumber()) {

View File

@ -9,12 +9,46 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
bool ObjectReference::IsSmi() const {
AllowHandleDereference allow_handle_dereference;
return object_->IsSmi();
}
int ObjectReference::AsSmi() const {
AllowHandleDereference allow_handle_dereference;
return Smi::cast(*object_)->value();
}
HeapReference ObjectReference::AsHeapReference() const {
AllowHandleDereference allow_handle_dereference;
return HeapReference(Handle<HeapObject>::cast(object_));
}
base::Optional<ContextHeapReference> ContextHeapReference::previous(
const JSHeapBroker* broker) const {
AllowHandleAllocation handle_allocation;
AllowHandleDereference handle_dereference;
Context* previous = Handle<Context>::cast(object())->previous();
if (previous == nullptr) return base::Optional<ContextHeapReference>();
return broker->HeapReferenceForObject(handle(previous, broker->isolate()))
.AsContext();
}
base::Optional<ObjectReference> ContextHeapReference::get(
const JSHeapBroker* broker, int index) const {
AllowHandleAllocation handle_allocation;
AllowHandleDereference handle_dereference;
Handle<Object> value(Handle<Context>::cast(object())->get(index),
broker->isolate());
return ObjectReference(value);
}
JSHeapBroker::JSHeapBroker(Isolate* isolate) : isolate_(isolate) {} JSHeapBroker::JSHeapBroker(Isolate* isolate) : isolate_(isolate) {}
HeapReferenceType JSHeapBroker::HeapReferenceTypeFromMap(Map* map) const { HeapReferenceType JSHeapBroker::HeapReferenceTypeFromMap(Map* map) const {
AllowHandleDereference allow_handle_dereference; AllowHandleDereference allow_handle_dereference;
Heap* heap = isolate_->heap(); Heap* heap = isolate_->heap();
HeapReferenceType::OddballType oddball_type = HeapReferenceType::kUnknown; HeapReferenceType::OddballType oddball_type = HeapReferenceType::kNone;
if (map->instance_type() == ODDBALL_TYPE) { if (map->instance_type() == ODDBALL_TYPE) {
if (map == heap->undefined_map()) { if (map == heap->undefined_map()) {
oddball_type = HeapReferenceType::kUndefined; oddball_type = HeapReferenceType::kUndefined;
@ -25,6 +59,7 @@ HeapReferenceType JSHeapBroker::HeapReferenceTypeFromMap(Map* map) const {
} else if (map == heap->the_hole_map()) { } else if (map == heap->the_hole_map()) {
oddball_type = HeapReferenceType::kHole; oddball_type = HeapReferenceType::kHole;
} else { } else {
oddball_type = HeapReferenceType::kOther;
DCHECK(map == heap->uninitialized_map() || DCHECK(map == heap->uninitialized_map() ||
map == heap->termination_exception_map() || map == heap->termination_exception_map() ||
map == heap->arguments_marker_map() || map == heap->arguments_marker_map() ||

View File

@ -16,16 +16,26 @@ namespace compiler {
class HeapReferenceType { class HeapReferenceType {
public: public:
enum OddballType : uint8_t { kUnknown, kBoolean, kUndefined, kNull, kHole }; enum OddballType : uint8_t {
kNone, // Not an Oddball.
kBoolean, // True or False.
kUndefined,
kNull,
kHole,
kOther, // Oddball, but none of the above.
kAny // Any Oddball.
};
enum Flag : uint8_t { kUndetectable = 1 << 0, kCallable = 1 << 1 }; enum Flag : uint8_t { kUndetectable = 1 << 0, kCallable = 1 << 1 };
typedef base::Flags<Flag> Flags; typedef base::Flags<Flag> Flags;
HeapReferenceType(InstanceType instance_type, Flags flags, HeapReferenceType(InstanceType instance_type, Flags flags,
OddballType oddball_type = kUnknown) OddballType oddball_type)
: instance_type_(instance_type), : instance_type_(instance_type),
oddball_type_(oddball_type), oddball_type_(oddball_type),
flags_(flags) {} flags_(flags) {
DCHECK_EQ(instance_type == ODDBALL_TYPE, oddball_type != kNone);
}
OddballType oddball_type() const { return oddball_type_; } OddballType oddball_type() const { return oddball_type_; }
InstanceType instance_type() const { return instance_type_; } InstanceType instance_type() const { return instance_type_; }
@ -41,6 +51,7 @@ class HeapReferenceType {
}; };
#define HEAP_BROKER_DATA_LIST(V) \ #define HEAP_BROKER_DATA_LIST(V) \
V(Context) \
V(JSFunction) \ V(JSFunction) \
V(Number) V(Number)
@ -54,6 +65,20 @@ HEAP_BROKER_DATA_LIST(FORWARD_DECL)
#undef FORWARD_DECL #undef FORWARD_DECL
class JSHeapBroker; class JSHeapBroker;
class HeapReference;
class ObjectReference {
public:
explicit ObjectReference(Handle<Object> object) : object_(object) {}
Handle<Object> object() const { return object_; }
bool IsSmi() const;
int AsSmi() const;
HeapReference AsHeapReference() const;
private:
Handle<Object> object_;
};
class HeapReference { class HeapReference {
public: public:
@ -72,7 +97,7 @@ class HeapReference {
private: private:
friend class JSHeapBroker; friend class JSHeapBroker;
Handle<HeapObject> const object_; Handle<HeapObject> object_;
}; };
class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) { class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) {
@ -87,12 +112,13 @@ class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) {
static base::Optional<int> TryGetSmi(Handle<Object> object); static base::Optional<int> TryGetSmi(Handle<Object> object);
Isolate* isolate() const { return isolate_; }
private: private:
friend class HeapReference; friend class HeapReference;
HeapReferenceType HeapReferenceTypeFromMap(Map* map) const; HeapReferenceType HeapReferenceTypeFromMap(Map* map) const;
Isolate* const isolate_; Isolate* const isolate_;
Isolate* isolate() const { return isolate_; }
}; };
class JSFunctionHeapReference : public HeapReference { class JSFunctionHeapReference : public HeapReference {
@ -110,6 +136,16 @@ class NumberHeapReference : public HeapReference {
double value() const; double value() const;
}; };
class ContextHeapReference : public HeapReference {
public:
explicit ContextHeapReference(Handle<HeapObject> object)
: HeapReference(object) {}
base::Optional<ContextHeapReference> previous(
const JSHeapBroker* broker) const;
base::Optional<ObjectReference> get(const JSHeapBroker* broker,
int index) const;
};
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8

View File

@ -1163,7 +1163,7 @@ struct InliningPhase {
: JSCallReducer::kNoFlags, : JSCallReducer::kNoFlags,
data->native_context(), data->info()->dependencies()); data->native_context(), data->info()->dependencies());
JSContextSpecialization context_specialization( JSContextSpecialization context_specialization(
&graph_reducer, data->jsgraph(), &graph_reducer, data->jsgraph(), data->js_heap_broker(),
ChooseSpecializationContext(isolate, data->info()), ChooseSpecializationContext(isolate, data->info()),
data->info()->is_function_context_specializing() data->info()->is_function_context_specializing()
? data->info()->closure() ? data->info()->closure()

View File

@ -162,7 +162,7 @@ Type::bitset BitsetType::Lub(HeapReferenceType const& type) {
return kSymbol; return kSymbol;
case BIGINT_TYPE: case BIGINT_TYPE:
return kBigInt; return kBigInt;
case ODDBALL_TYPE: { case ODDBALL_TYPE:
switch (type.oddball_type()) { switch (type.oddball_type()) {
case HeapReferenceType::kHole: case HeapReferenceType::kHole:
return kHole; return kHole;
@ -172,11 +172,14 @@ Type::bitset BitsetType::Lub(HeapReferenceType const& type) {
return kNull; return kNull;
case HeapReferenceType::kUndefined: case HeapReferenceType::kUndefined:
return kUndefined; return kUndefined;
case HeapReferenceType::kUnknown: case HeapReferenceType::kOther:
// TODO(neis): We should add a kOtherOddball type.
return kOtherInternal; return kOtherInternal;
case HeapReferenceType::kAny:
return kOddball | kOtherInternal;
default:
UNREACHABLE();
} }
UNREACHABLE();
}
case HEAP_NUMBER_TYPE: case HEAP_NUMBER_TYPE:
return kNumber; return kNumber;
case JS_OBJECT_TYPE: case JS_OBJECT_TYPE:

View File

@ -30,7 +30,9 @@ class ContextSpecializationTester : public HandleAndZoneScope {
jsgraph_(main_isolate(), graph(), common(), &javascript_, &simplified_, jsgraph_(main_isolate(), graph(), common(), &javascript_, &simplified_,
&machine_), &machine_),
reducer_(main_zone(), graph()), reducer_(main_zone(), graph()),
spec_(&reducer_, jsgraph(), context, MaybeHandle<JSFunction>()) {} js_heap_broker_(main_isolate()),
spec_(&reducer_, jsgraph(), &js_heap_broker_, context,
MaybeHandle<JSFunction>()) {}
JSContextSpecialization* spec() { return &spec_; } JSContextSpecialization* spec() { return &spec_; }
Factory* factory() { return main_isolate()->factory(); } Factory* factory() { return main_isolate()->factory(); }
@ -55,6 +57,7 @@ class ContextSpecializationTester : public HandleAndZoneScope {
SimplifiedOperatorBuilder simplified_; SimplifiedOperatorBuilder simplified_;
JSGraph jsgraph_; JSGraph jsgraph_;
GraphReducer reducer_; GraphReducer reducer_;
JSHeapBroker js_heap_broker_;
JSContextSpecialization spec_; JSContextSpecialization spec_;
}; };