[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: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/master@{#70425}
This commit is contained in:
parent
ceeee0c78d
commit
32d7ec1af4
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user