Commit 32d7ec1a authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

[heap] Handle partially initialized objects in NativeContextInferrer

Since GC can now happen during deserialization, object fields may
contain the Smi sentinel value instead of pointers. This adds the
required guards to methods of NativeContextInferrer

Bug: chromium:1136801
Change-Id: I7338f31bf6ee34b8dee8431b8250d2cc2978e0c2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2461241
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70425}
parent ceeee0c7
......@@ -20,13 +20,13 @@ bool NativeContextInferrer::Infer(Isolate* isolate, Map map, HeapObject object,
Address* native_context) {
switch (map.visitor_id()) {
case kVisitContext:
*native_context = Context::cast(object).native_context().ptr();
return true;
return InferForContext(isolate, Context::cast(object), native_context);
case kVisitNativeContext:
*native_context = object.ptr();
return true;
case kVisitJSFunction:
return InferForJSFunction(JSFunction::cast(object), native_context);
return InferForJSFunction(isolate, JSFunction::cast(object),
native_context);
case kVisitJSApiObject:
case kVisitJSArrayBuffer:
case kVisitJSObject:
......
......@@ -337,15 +337,37 @@ std::unique_ptr<v8::MeasureMemoryDelegate> MemoryMeasurement::DefaultDelegate(
mode);
}
bool NativeContextInferrer::InferForJSFunction(JSFunction function,
Address* native_context) {
if (function.has_context()) {
*native_context = function.context().native_context().ptr();
bool NativeContextInferrer::InferForContext(Isolate* isolate, Context context,
Address* native_context) {
Map context_map = context.synchronized_map();
Object maybe_native_context =
TaggedField<Object, Map::kConstructorOrBackPointerOrNativeContextOffset>::
Acquire_Load(isolate, context_map);
if (maybe_native_context.IsNativeContext()) {
*native_context = maybe_native_context.ptr();
return true;
}
return false;
}
bool NativeContextInferrer::InferForJSFunction(Isolate* isolate,
JSFunction function,
Address* native_context) {
Object maybe_context =
TaggedField<Object, JSFunction::kContextOffset>::Acquire_Load(isolate,
function);
// The context may be a smi during deserialization.
if (maybe_context.IsSmi()) {
DCHECK_EQ(maybe_context, Deserializer::uninitialized_field_value());
return false;
}
if (!maybe_context.IsContext()) {
// The function does not have a context.
return false;
}
return InferForContext(isolate, Context::cast(maybe_context), native_context);
}
bool NativeContextInferrer::InferForJSObject(Isolate* isolate, Map map,
JSObject object,
Address* native_context) {
......@@ -361,7 +383,7 @@ bool NativeContextInferrer::InferForJSObject(Isolate* isolate, Map map,
const int kMaxSteps = 3;
Object maybe_constructor = map.TryGetConstructor(isolate, kMaxSteps);
if (maybe_constructor.IsJSFunction()) {
return InferForJSFunction(JSFunction::cast(maybe_constructor),
return InferForJSFunction(isolate, JSFunction::cast(maybe_constructor),
native_context);
}
return false;
......
......@@ -73,7 +73,10 @@ class V8_EXPORT_PRIVATE NativeContextInferrer {
Address* native_context);
private:
bool InferForJSFunction(JSFunction function, Address* native_context);
bool InferForContext(Isolate* isolate, Context context,
Address* native_context);
bool InferForJSFunction(Isolate* isolate, JSFunction function,
Address* native_context);
bool InferForJSObject(Isolate* isolate, Map map, JSObject object,
Address* native_context);
};
......
......@@ -91,7 +91,6 @@ TEST(NativeContextStatsArrayBuffers) {
*i_array_buffer, 10);
CHECK_EQ(1010, stats.Get(native_context->ptr()));
}
namespace {
class TestResource : public v8::String::ExternalStringResource {
......@@ -229,6 +228,64 @@ TEST(LazyMemoryMeasurement) {
CHECK(!platform.TaskPosted());
}
TEST(PartiallyInitializedJSFunction) {
LocalContext env;
Isolate* isolate = CcTest::i_isolate();
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<JSFunction> js_function =
factory->NewFunctionForTest(factory->NewStringFromAsciiChecked("test"));
Handle<Context> context = handle(js_function->context(), isolate);
// 1. Start simulating deserializaiton.
isolate->RegisterDeserializerStarted();
// 2. Set the context field to the uninitialized sentintel.
TaggedField<Object, JSFunction::kContextOffset>::store(
*js_function, Deserializer::uninitialized_field_value());
// 3. Request memory meaurement and run all tasks. GC that runs as part
// of the measurement should not crash.
CcTest::isolate()->MeasureMemory(
std::make_unique<MockMeasureMemoryDelegate>(),
v8::MeasureMemoryExecution::kEager);
while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(),
CcTest::isolate())) {
}
// 4. Restore the value and complete deserialization.
TaggedField<Object, JSFunction::kContextOffset>::store(*js_function,
*context);
isolate->RegisterDeserializerFinished();
}
TEST(PartiallyInitializedContext) {
LocalContext env;
Isolate* isolate = CcTest::i_isolate();
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<ScopeInfo> scope_info =
ReadOnlyRoots(isolate).global_this_binding_scope_info_handle();
Handle<Context> context = factory->NewScriptContext(
GetNativeContext(isolate, env.local()), scope_info);
Handle<Map> map = handle(context->map(), isolate);
Handle<NativeContext> native_context = handle(map->native_context(), isolate);
// 1. Start simulating deserializaiton.
isolate->RegisterDeserializerStarted();
// 2. Set the native context field to the uninitialized sentintel.
TaggedField<Object, Map::kConstructorOrBackPointerOrNativeContextOffset>::
store(*map, Deserializer::uninitialized_field_value());
// 3. Request memory meaurement and run all tasks. GC that runs as part
// of the measurement should not crash.
CcTest::isolate()->MeasureMemory(
std::make_unique<MockMeasureMemoryDelegate>(),
v8::MeasureMemoryExecution::kEager);
while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(),
CcTest::isolate())) {
}
// 4. Restore the value and complete deserialization.
TaggedField<Object, Map::kConstructorOrBackPointerOrNativeContextOffset>::
store(*map, *native_context);
isolate->RegisterDeserializerFinished();
}
} // namespace heap
} // namespace internal
} // namespace v8
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