[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/+/1997133 Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Commit-Queue: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#65736}
This commit is contained in:
parent
ae00aa9e4e
commit
37ccf35bea
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user