Commit 37ccf35b authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

[heap] More accurate native context inference

This adds inference for general JSObjects to NativeContextInferrer in
the case when the object is going to be attributed to the shard context.

Bug: chromium:973627
Change-Id: I393e8dd16a1f8b615fb2f8dceb52f543bae33554
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1997133Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65736}
parent ae00aa9e
...@@ -399,9 +399,10 @@ void ConcurrentMarking::Run(int task_id, TaskState* task_state) { ...@@ -399,9 +399,10 @@ void ConcurrentMarking::Run(int task_id, TaskState* task_state) {
NativeContextStats& native_context_stats = task_state->native_context_stats; NativeContextStats& native_context_stats = task_state->native_context_stats;
double time_ms; double time_ms;
size_t marked_bytes = 0; size_t marked_bytes = 0;
Isolate* isolate = heap_->isolate();
if (FLAG_trace_concurrent_marking) { if (FLAG_trace_concurrent_marking) {
heap_->isolate()->PrintWithTimestamp( isolate->PrintWithTimestamp("Starting concurrent marking task %d\n",
"Starting concurrent marking task %d\n", task_id); task_id);
} }
bool ephemeron_marked = false; bool ephemeron_marked = false;
...@@ -439,10 +440,10 @@ void ConcurrentMarking::Run(int task_id, TaskState* task_state) { ...@@ -439,10 +440,10 @@ void ConcurrentMarking::Run(int task_id, TaskState* task_state) {
addr == new_large_object) { addr == new_large_object) {
marking_worklists.PushOnHold(object); marking_worklists.PushOnHold(object);
} else { } else {
Map map = object.synchronized_map(); Map map = object.synchronized_map(isolate);
if (is_per_context_mode) { if (is_per_context_mode) {
Address context; Address context;
if (native_context_inferrer.Infer(map, object, &context)) { if (native_context_inferrer.Infer(isolate, map, object, &context)) {
marking_worklists.SwitchToContext(context); marking_worklists.SwitchToContext(context);
} }
} }
......
...@@ -1803,6 +1803,7 @@ size_t MarkCompactCollector::ProcessMarkingWorklist(size_t bytes_to_process) { ...@@ -1803,6 +1803,7 @@ size_t MarkCompactCollector::ProcessMarkingWorklist(size_t bytes_to_process) {
HeapObject object; HeapObject object;
size_t bytes_processed = 0; size_t bytes_processed = 0;
bool is_per_context_mode = marking_worklists()->IsPerContextMode(); bool is_per_context_mode = marking_worklists()->IsPerContextMode();
Isolate* isolate = heap()->isolate();
while (marking_worklists()->Pop(&object) || while (marking_worklists()->Pop(&object) ||
marking_worklists()->PopOnHold(&object)) { marking_worklists()->PopOnHold(&object)) {
// Left trimming may result in grey or black filler objects on the marking // Left trimming may result in grey or black filler objects on the marking
...@@ -1827,10 +1828,10 @@ size_t MarkCompactCollector::ProcessMarkingWorklist(size_t bytes_to_process) { ...@@ -1827,10 +1828,10 @@ size_t MarkCompactCollector::ProcessMarkingWorklist(size_t bytes_to_process) {
kTrackNewlyDiscoveredObjects) { kTrackNewlyDiscoveredObjects) {
AddNewlyDiscovered(object); AddNewlyDiscovered(object);
} }
Map map = object.map(); Map map = object.map(isolate);
if (is_per_context_mode) { if (is_per_context_mode) {
Address context; Address context;
if (native_context_inferrer_.Infer(map, object, &context)) { if (native_context_inferrer_.Infer(isolate, map, object, &context)) {
marking_worklists()->SwitchToContext(context); marking_worklists()->SwitchToContext(context);
} }
} }
......
...@@ -124,6 +124,8 @@ class V8_EXPORT_PRIVATE MarkingWorklistsHolder { ...@@ -124,6 +124,8 @@ class V8_EXPORT_PRIVATE MarkingWorklistsHolder {
// A thread-local view of the marking worklists. // A thread-local view of the marking worklists.
class V8_EXPORT_PRIVATE MarkingWorklists { class V8_EXPORT_PRIVATE MarkingWorklists {
public: public:
static const Address kSharedContext = 0;
MarkingWorklists(int task_id, MarkingWorklistsHolder* holder); MarkingWorklists(int task_id, MarkingWorklistsHolder* holder);
void Push(HeapObject object) { void Push(HeapObject object) {
...@@ -179,7 +181,6 @@ class V8_EXPORT_PRIVATE MarkingWorklists { ...@@ -179,7 +181,6 @@ class V8_EXPORT_PRIVATE MarkingWorklists {
bool IsPerContextMode() { return is_per_context_mode_; } bool IsPerContextMode() { return is_per_context_mode_; }
private: private:
const Address kSharedContext = 0;
bool PopContext(HeapObject* object); bool PopContext(HeapObject* object);
Address SwitchToContextSlow(Address context); Address SwitchToContextSlow(Address context);
MarkingWorklist* shared_; MarkingWorklist* shared_;
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
bool NativeContextInferrer::Infer(Map map, HeapObject object, bool NativeContextInferrer::Infer(Isolate* isolate, Map map, HeapObject object,
Address* native_context) { Address* native_context) {
switch (map.visitor_id()) { switch (map.visitor_id()) {
case kVisitContext: case kVisitContext:
...@@ -24,14 +24,15 @@ bool NativeContextInferrer::Infer(Map map, HeapObject object, ...@@ -24,14 +24,15 @@ bool NativeContextInferrer::Infer(Map map, HeapObject object,
*native_context = object.ptr(); *native_context = object.ptr();
return true; return true;
case kVisitJSFunction: case kVisitJSFunction:
return InferForJSFunction(map, JSFunction::cast(object), native_context); return InferForJSFunction(JSFunction::cast(object), native_context);
case kVisitJSApiObject: case kVisitJSApiObject:
case kVisitJSArrayBuffer: case kVisitJSArrayBuffer:
case kVisitJSObject: case kVisitJSObject:
case kVisitJSObjectFast: case kVisitJSObjectFast:
case kVisitJSTypedArray: case kVisitJSTypedArray:
case kVisitJSWeakCollection: case kVisitJSWeakCollection:
return InferForJSObject(map, JSObject::cast(object), native_context); return InferForJSObject(isolate, map, JSObject::cast(object),
native_context);
default: default:
return false; return false;
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/execution/isolate.h" #include "src/execution/isolate.h"
#include "src/heap/factory-inl.h" #include "src/heap/factory-inl.h"
#include "src/heap/factory.h" #include "src/heap/factory.h"
#include "src/heap/marking-worklist.h"
#include "src/objects/js-promise.h" #include "src/objects/js-promise.h"
namespace v8 { namespace v8 {
...@@ -76,7 +77,7 @@ Handle<JSPromise> MemoryMeasurement::EnqueueRequest( ...@@ -76,7 +77,7 @@ Handle<JSPromise> MemoryMeasurement::EnqueueRequest(
return promise; return promise;
} }
bool NativeContextInferrer::InferForJSFunction(Map map, JSFunction function, bool NativeContextInferrer::InferForJSFunction(JSFunction function,
Address* native_context) { Address* native_context) {
if (function.has_context()) { if (function.has_context()) {
*native_context = function.context().native_context().ptr(); *native_context = function.context().native_context().ptr();
...@@ -85,16 +86,28 @@ bool NativeContextInferrer::InferForJSFunction(Map map, JSFunction function, ...@@ -85,16 +86,28 @@ bool NativeContextInferrer::InferForJSFunction(Map map, JSFunction function,
return false; return false;
} }
bool NativeContextInferrer::InferForJSObject(Map map, JSObject object, bool NativeContextInferrer::InferForJSObject(Isolate* isolate, Map map,
JSObject object,
Address* native_context) { Address* native_context) {
if (map.instance_type() == JS_GLOBAL_OBJECT_TYPE) { if (map.instance_type() == JS_GLOBAL_OBJECT_TYPE) {
Object maybe_context = Object maybe_context =
JSGlobalObject::cast(object).native_context_unchecked(); JSGlobalObject::cast(object).native_context_unchecked(isolate);
if (maybe_context.IsNativeContext()) { if (maybe_context.IsNativeContext()) {
*native_context = maybe_context.ptr(); *native_context = maybe_context.ptr();
return true; return true;
} }
} }
if (*native_context == MarkingWorklists::kSharedContext) {
// This lookup is expensive, so perform it only if the object is currently
// attributed to the shared context.
// The maximum number of steps to perform when looking for the context.
const int kMaxSteps = 3;
Object maybe_constructor = map.TryGetConstructor(isolate, kMaxSteps);
if (maybe_constructor.IsJSFunction()) {
return InferForJSFunction(JSFunction::cast(maybe_constructor),
native_context);
}
}
return false; return false;
} }
......
...@@ -29,12 +29,17 @@ class V8_EXPORT_PRIVATE MemoryMeasurement { ...@@ -29,12 +29,17 @@ class V8_EXPORT_PRIVATE MemoryMeasurement {
// Infers the native context for some of the heap objects. // Infers the native context for some of the heap objects.
class V8_EXPORT_PRIVATE NativeContextInferrer { class V8_EXPORT_PRIVATE NativeContextInferrer {
public: public:
V8_INLINE bool Infer(Map map, HeapObject object, Address* native_context); // The native_context parameter is both the input and output parameter.
// It should be initialized to the context that will be used for the object
// if the inference is not successful. The function performs more work if the
// context is the shared context.
V8_INLINE bool Infer(Isolate* isolate, Map map, HeapObject object,
Address* native_context);
private: private:
bool InferForJSFunction(Map map, JSFunction function, bool InferForJSFunction(JSFunction function, Address* native_context);
bool InferForJSObject(Isolate* isolate, Map map, JSObject object,
Address* native_context); Address* native_context);
bool InferForJSObject(Map map, JSObject object, Address* native_context);
}; };
// Maintains mapping from native contexts to their sizes. // Maintains mapping from native contexts to their sizes.
......
...@@ -765,6 +765,17 @@ DEF_GETTER(Map, GetConstructor, Object) { ...@@ -765,6 +765,17 @@ DEF_GETTER(Map, GetConstructor, Object) {
return maybe_constructor; return maybe_constructor;
} }
Object Map::TryGetConstructor(Isolate* isolate, int max_steps) {
Object maybe_constructor = constructor_or_backpointer(isolate);
// Follow any back pointers.
while (maybe_constructor.IsMap(isolate)) {
if (max_steps-- == 0) return Smi::FromInt(0);
maybe_constructor =
Map::cast(maybe_constructor).constructor_or_backpointer(isolate);
}
return maybe_constructor;
}
DEF_GETTER(Map, GetFunctionTemplateInfo, FunctionTemplateInfo) { DEF_GETTER(Map, GetFunctionTemplateInfo, FunctionTemplateInfo) {
Object constructor = GetConstructor(isolate); Object constructor = GetConstructor(isolate);
if (constructor.IsJSFunction(isolate)) { if (constructor.IsJSFunction(isolate)) {
......
...@@ -564,6 +564,10 @@ class Map : public HeapObject { ...@@ -564,6 +564,10 @@ class Map : public HeapObject {
DECL_GETTER(GetFunctionTemplateInfo, FunctionTemplateInfo) DECL_GETTER(GetFunctionTemplateInfo, FunctionTemplateInfo)
inline void SetConstructor(Object constructor, inline void SetConstructor(Object constructor,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// Constructor getter that performs at most the given number of steps
// in the transition tree. Returns either the constructor or the map at
// which the walk has stopped.
inline Object TryGetConstructor(Isolate* isolate, int max_steps);
// [back pointer]: points back to the parent map from which a transition // [back pointer]: points back to the parent map from which a transition
// leads to this map. The field overlaps with the constructor (see above). // leads to this map. The field overlaps with the constructor (see above).
DECL_GETTER(GetBackPointer, HeapObject) DECL_GETTER(GetBackPointer, HeapObject)
......
...@@ -28,8 +28,8 @@ TEST(NativeContextInferrerGlobalObject) { ...@@ -28,8 +28,8 @@ TEST(NativeContextInferrerGlobalObject) {
Handle<JSGlobalObject> global = Handle<JSGlobalObject> global =
handle(native_context->global_object(), isolate); handle(native_context->global_object(), isolate);
NativeContextInferrer inferrer; NativeContextInferrer inferrer;
Address inferred_context; Address inferred_context = 0;
CHECK(inferrer.Infer(global->map(), *global, &inferred_context)); CHECK(inferrer.Infer(isolate, global->map(), *global, &inferred_context));
CHECK_EQ(native_context->ptr(), inferred_context); CHECK_EQ(native_context->ptr(), inferred_context);
} }
...@@ -42,8 +42,22 @@ TEST(NativeContextInferrerJSFunction) { ...@@ -42,8 +42,22 @@ TEST(NativeContextInferrerJSFunction) {
Handle<Object> object = Utils::OpenHandle(*result); Handle<Object> object = Utils::OpenHandle(*result);
Handle<HeapObject> function = Handle<HeapObject>::cast(object); Handle<HeapObject> function = Handle<HeapObject>::cast(object);
NativeContextInferrer inferrer; NativeContextInferrer inferrer;
Address inferred_context; Address inferred_context = 0;
CHECK(inferrer.Infer(function->map(), *function, &inferred_context)); CHECK(inferrer.Infer(isolate, function->map(), *function, &inferred_context));
CHECK_EQ(native_context->ptr(), inferred_context);
}
TEST(NativeContextInferrerJSObject) {
LocalContext env;
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Handle<NativeContext> native_context = GetNativeContext(isolate, env.local());
v8::Local<v8::Value> result = CompileRun("({a : 10})");
Handle<Object> object = Utils::OpenHandle(*result);
Handle<HeapObject> function = Handle<HeapObject>::cast(object);
NativeContextInferrer inferrer;
Address inferred_context = 0;
CHECK(inferrer.Infer(isolate, function->map(), *function, &inferred_context));
CHECK_EQ(native_context->ptr(), inferred_context); CHECK_EQ(native_context->ptr(), inferred_context);
} }
......
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