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) {
NativeContextStats& native_context_stats = task_state->native_context_stats;
double time_ms;
size_t marked_bytes = 0;
Isolate* isolate = heap_->isolate();
if (FLAG_trace_concurrent_marking) {
heap_->isolate()->PrintWithTimestamp(
"Starting concurrent marking task %d\n", task_id);
isolate->PrintWithTimestamp("Starting concurrent marking task %d\n",
task_id);
}
bool ephemeron_marked = false;
......@@ -439,10 +440,10 @@ void ConcurrentMarking::Run(int task_id, TaskState* task_state) {
addr == new_large_object) {
marking_worklists.PushOnHold(object);
} else {
Map map = object.synchronized_map();
Map map = object.synchronized_map(isolate);
if (is_per_context_mode) {
Address context;
if (native_context_inferrer.Infer(map, object, &context)) {
if (native_context_inferrer.Infer(isolate, map, object, &context)) {
marking_worklists.SwitchToContext(context);
}
}
......
......@@ -1803,6 +1803,7 @@ size_t MarkCompactCollector::ProcessMarkingWorklist(size_t bytes_to_process) {
HeapObject object;
size_t bytes_processed = 0;
bool is_per_context_mode = marking_worklists()->IsPerContextMode();
Isolate* isolate = heap()->isolate();
while (marking_worklists()->Pop(&object) ||
marking_worklists()->PopOnHold(&object)) {
// 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) {
kTrackNewlyDiscoveredObjects) {
AddNewlyDiscovered(object);
}
Map map = object.map();
Map map = object.map(isolate);
if (is_per_context_mode) {
Address context;
if (native_context_inferrer_.Infer(map, object, &context)) {
if (native_context_inferrer_.Infer(isolate, map, object, &context)) {
marking_worklists()->SwitchToContext(context);
}
}
......
......@@ -124,6 +124,8 @@ class V8_EXPORT_PRIVATE MarkingWorklistsHolder {
// A thread-local view of the marking worklists.
class V8_EXPORT_PRIVATE MarkingWorklists {
public:
static const Address kSharedContext = 0;
MarkingWorklists(int task_id, MarkingWorklistsHolder* holder);
void Push(HeapObject object) {
......@@ -179,7 +181,6 @@ class V8_EXPORT_PRIVATE MarkingWorklists {
bool IsPerContextMode() { return is_per_context_mode_; }
private:
const Address kSharedContext = 0;
bool PopContext(HeapObject* object);
Address SwitchToContextSlow(Address context);
MarkingWorklist* shared_;
......
......@@ -14,7 +14,7 @@
namespace v8 {
namespace internal {
bool NativeContextInferrer::Infer(Map map, HeapObject object,
bool NativeContextInferrer::Infer(Isolate* isolate, Map map, HeapObject object,
Address* native_context) {
switch (map.visitor_id()) {
case kVisitContext:
......@@ -24,14 +24,15 @@ bool NativeContextInferrer::Infer(Map map, HeapObject object,
*native_context = object.ptr();
return true;
case kVisitJSFunction:
return InferForJSFunction(map, JSFunction::cast(object), native_context);
return InferForJSFunction(JSFunction::cast(object), native_context);
case kVisitJSApiObject:
case kVisitJSArrayBuffer:
case kVisitJSObject:
case kVisitJSObjectFast:
case kVisitJSTypedArray:
case kVisitJSWeakCollection:
return InferForJSObject(map, JSObject::cast(object), native_context);
return InferForJSObject(isolate, map, JSObject::cast(object),
native_context);
default:
return false;
}
......
......@@ -8,6 +8,7 @@
#include "src/execution/isolate.h"
#include "src/heap/factory-inl.h"
#include "src/heap/factory.h"
#include "src/heap/marking-worklist.h"
#include "src/objects/js-promise.h"
namespace v8 {
......@@ -76,7 +77,7 @@ Handle<JSPromise> MemoryMeasurement::EnqueueRequest(
return promise;
}
bool NativeContextInferrer::InferForJSFunction(Map map, JSFunction function,
bool NativeContextInferrer::InferForJSFunction(JSFunction function,
Address* native_context) {
if (function.has_context()) {
*native_context = function.context().native_context().ptr();
......@@ -85,16 +86,28 @@ bool NativeContextInferrer::InferForJSFunction(Map map, JSFunction function,
return false;
}
bool NativeContextInferrer::InferForJSObject(Map map, JSObject object,
bool NativeContextInferrer::InferForJSObject(Isolate* isolate, Map map,
JSObject object,
Address* native_context) {
if (map.instance_type() == JS_GLOBAL_OBJECT_TYPE) {
Object maybe_context =
JSGlobalObject::cast(object).native_context_unchecked();
JSGlobalObject::cast(object).native_context_unchecked(isolate);
if (maybe_context.IsNativeContext()) {
*native_context = maybe_context.ptr();
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;
}
......
......@@ -29,12 +29,17 @@ class V8_EXPORT_PRIVATE MemoryMeasurement {
// Infers the native context for some of the heap objects.
class V8_EXPORT_PRIVATE NativeContextInferrer {
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:
bool InferForJSFunction(Map map, JSFunction function,
Address* native_context);
bool InferForJSObject(Map map, JSObject object, Address* native_context);
bool InferForJSFunction(JSFunction function, Address* native_context);
bool InferForJSObject(Isolate* isolate, Map map, JSObject object,
Address* native_context);
};
// Maintains mapping from native contexts to their sizes.
......
......@@ -765,6 +765,17 @@ DEF_GETTER(Map, GetConstructor, Object) {
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) {
Object constructor = GetConstructor(isolate);
if (constructor.IsJSFunction(isolate)) {
......
......@@ -564,6 +564,10 @@ class Map : public HeapObject {
DECL_GETTER(GetFunctionTemplateInfo, FunctionTemplateInfo)
inline void SetConstructor(Object constructor,
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
// leads to this map. The field overlaps with the constructor (see above).
DECL_GETTER(GetBackPointer, HeapObject)
......
......@@ -28,8 +28,8 @@ TEST(NativeContextInferrerGlobalObject) {
Handle<JSGlobalObject> global =
handle(native_context->global_object(), isolate);
NativeContextInferrer inferrer;
Address inferred_context;
CHECK(inferrer.Infer(global->map(), *global, &inferred_context));
Address inferred_context = 0;
CHECK(inferrer.Infer(isolate, global->map(), *global, &inferred_context));
CHECK_EQ(native_context->ptr(), inferred_context);
}
......@@ -42,8 +42,22 @@ TEST(NativeContextInferrerJSFunction) {
Handle<Object> object = Utils::OpenHandle(*result);
Handle<HeapObject> function = Handle<HeapObject>::cast(object);
NativeContextInferrer inferrer;
Address inferred_context;
CHECK(inferrer.Infer(function->map(), *function, &inferred_context));
Address inferred_context = 0;
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);
}
......
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