diff --git a/src/heap/memory-measurement-inl.h b/src/heap/memory-measurement-inl.h index 905623e744..f6c75b6ca6 100644 --- a/src/heap/memory-measurement-inl.h +++ b/src/heap/memory-measurement-inl.h @@ -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: diff --git a/src/heap/memory-measurement.cc b/src/heap/memory-measurement.cc index 4b8f13e6bb..5f79439b05 100644 --- a/src/heap/memory-measurement.cc +++ b/src/heap/memory-measurement.cc @@ -337,15 +337,37 @@ std::unique_ptr 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:: + 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::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; diff --git a/src/heap/memory-measurement.h b/src/heap/memory-measurement.h index e71bdc1cfe..cf72c57abd 100644 --- a/src/heap/memory-measurement.h +++ b/src/heap/memory-measurement.h @@ -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); }; diff --git a/test/cctest/heap/test-memory-measurement.cc b/test/cctest/heap/test-memory-measurement.cc index 861337e38f..d72c70725b 100644 --- a/test/cctest/heap/test-memory-measurement.cc +++ b/test/cctest/heap/test-memory-measurement.cc @@ -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 js_function = + factory->NewFunctionForTest(factory->NewStringFromAsciiChecked("test")); + Handle context = handle(js_function->context(), isolate); + + // 1. Start simulating deserializaiton. + isolate->RegisterDeserializerStarted(); + // 2. Set the context field to the uninitialized sentintel. + TaggedField::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(), + v8::MeasureMemoryExecution::kEager); + while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(), + CcTest::isolate())) { + } + // 4. Restore the value and complete deserialization. + TaggedField::store(*js_function, + *context); + isolate->RegisterDeserializerFinished(); +} + +TEST(PartiallyInitializedContext) { + LocalContext env; + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + HandleScope scope(isolate); + Handle scope_info = + ReadOnlyRoots(isolate).global_this_binding_scope_info_handle(); + Handle context = factory->NewScriptContext( + GetNativeContext(isolate, env.local()), scope_info); + Handle map = handle(context->map(), isolate); + Handle native_context = handle(map->native_context(), isolate); + // 1. Start simulating deserializaiton. + isolate->RegisterDeserializerStarted(); + // 2. Set the native context field to the uninitialized sentintel. + TaggedField:: + 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(), + v8::MeasureMemoryExecution::kEager); + while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(), + CcTest::isolate())) { + } + // 4. Restore the value and complete deserialization. + TaggedField:: + store(*map, *native_context); + isolate->RegisterDeserializerFinished(); +} + } // namespace heap } // namespace internal } // namespace v8