Commit d915b8d6 authored by Matheus Marchini's avatar Matheus Marchini Committed by Commit Bot

[snapshot] Fix copy-IET integration with Code Cache

R=bmeurer@chromium.org, jgruber@chromium.org, yangguo@chromium.org

Bug: v8:9122
Change-Id: I6336d2fc0249269a749d99dcae7c172b2ccaac75
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1570582Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60937}
parent 2d00edf7
...@@ -187,6 +187,18 @@ void CodeSerializer::SerializeObject(HeapObject obj) { ...@@ -187,6 +187,18 @@ void CodeSerializer::SerializeObject(HeapObject obj) {
return; return;
} }
// NOTE(mmarchini): If we try to serialize an InterpreterData our process
// will crash since it stores a code object. Instead, we serialize the
// bytecode array stored within the InterpreterData, which is the important
// information. On deserialization we'll create our code objects again, if
// --interpreted-frames-native-stack is on. See v8:9122 for more context
#ifndef V8_TARGET_ARCH_ARM
if (V8_UNLIKELY(FLAG_interpreted_frames_native_stack) &&
obj->IsInterpreterData()) {
obj = InterpreterData::cast(obj)->bytecode_array();
}
#endif // V8_TARGET_ARCH_ARM
if (obj->IsBytecodeArray()) { if (obj->IsBytecodeArray()) {
// Clear the stack frame cache if present // Clear the stack frame cache if present
BytecodeArray::cast(obj)->ClearFrameCacheFromSourcePositionTable(); BytecodeArray::cast(obj)->ClearFrameCacheFromSourcePositionTable();
...@@ -210,6 +222,48 @@ void CodeSerializer::SerializeGeneric(HeapObject heap_object) { ...@@ -210,6 +222,48 @@ void CodeSerializer::SerializeGeneric(HeapObject heap_object) {
serializer.Serialize(); serializer.Serialize();
} }
#ifndef V8_TARGET_ARCH_ARM
// NOTE(mmarchini): when FLAG_interpreted_frames_native_stack is on, we want to
// create duplicates of InterpreterEntryTrampoline for the deserialized
// functions, otherwise we'll call the builtin IET for those functions (which
// is not what a user of this flag wants).
void CreateInterpreterDataForDeserializedCode(Isolate* isolate,
Handle<SharedFunctionInfo> sfi,
bool log_code_creation) {
Script script = Script::cast(sfi->script());
Handle<Script> script_handle(script, isolate);
String name = ReadOnlyRoots(isolate).empty_string();
if (script->name()->IsString()) name = String::cast(script->name());
Handle<String> name_handle(name, isolate);
SharedFunctionInfo::ScriptIterator iter(isolate, script);
for (SharedFunctionInfo info = iter.Next(); !info.is_null();
info = iter.Next()) {
if (!info->HasBytecodeArray()) continue;
Handle<Code> code = isolate->factory()->CopyCode(Handle<Code>::cast(
isolate->factory()->interpreter_entry_trampoline_for_profiling()));
Handle<InterpreterData> interpreter_data =
Handle<InterpreterData>::cast(isolate->factory()->NewStruct(
INTERPRETER_DATA_TYPE, AllocationType::kOld));
interpreter_data->set_bytecode_array(info->GetBytecodeArray());
interpreter_data->set_interpreter_trampoline(*code);
info->set_interpreter_data(*interpreter_data);
if (!log_code_creation) continue;
Handle<AbstractCode> abstract_code = Handle<AbstractCode>::cast(code);
int line_num = script->GetLineNumber(info->StartPosition()) + 1;
int column_num = script->GetColumnNumber(info->StartPosition()) + 1;
PROFILE(isolate,
CodeCreateEvent(CodeEventListener::INTERPRETED_FUNCTION_TAG,
*abstract_code, info, *name_handle, line_num,
column_num));
}
}
#endif // V8_TARGET_ARCH_ARM
MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
Isolate* isolate, ScriptData* cached_data, Handle<String> source, Isolate* isolate, ScriptData* cached_data, Handle<String> source,
ScriptOriginOptions origin_options) { ScriptOriginOptions origin_options) {
...@@ -253,6 +307,13 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( ...@@ -253,6 +307,13 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
isolate->logger()->is_listening_to_code_events() || isolate->logger()->is_listening_to_code_events() ||
isolate->is_profiling() || isolate->is_profiling() ||
isolate->code_event_dispatcher()->IsListeningToCodeEvents(); isolate->code_event_dispatcher()->IsListeningToCodeEvents();
#ifndef V8_TARGET_ARCH_ARM
if (V8_UNLIKELY(FLAG_interpreted_frames_native_stack))
CreateInterpreterDataForDeserializedCode(isolate, result,
log_code_creation);
#endif // V8_TARGET_ARCH_ARM
if (log_code_creation || FLAG_log_function_events) { if (log_code_creation || FLAG_log_function_events) {
String name = ReadOnlyRoots(isolate).empty_string(); String name = ReadOnlyRoots(isolate).empty_string();
Script script = Script::cast(result->script()); Script script = Script::cast(result->script());
......
...@@ -567,7 +567,9 @@ ...@@ -567,7 +567,9 @@
# allocation. Fix logging to work without feedback vectors and enable these # allocation. Fix logging to work without feedback vectors and enable these
# tests in lite_mode. # tests in lite_mode.
'test-log/ExternalCodeEventListenerWithInterpretedFramesNativeStack': [SKIP], 'test-log/ExternalCodeEventListenerWithInterpretedFramesNativeStack': [SKIP],
'test-log/LogInterpretedFramesNativeStack': [SKIP] 'test-log/LogInterpretedFramesNativeStack': [SKIP],
'test-log/LogInterpretedFramesNativeStackWithSerialization': [SKIP],
'test-serialize/CodeSerializerOnePlusOneWithInterpretedFramesNativeStack': [SKIP]
}], # lite_mode }], # lite_mode
############################################################################## ##############################################################################
...@@ -606,6 +608,8 @@ ...@@ -606,6 +608,8 @@
# --interpreted-frames-native-stack tests # --interpreted-frames-native-stack tests
'test-log/ExternalCodeEventListenerWithInterpretedFramesNativeStack': [SKIP], 'test-log/ExternalCodeEventListenerWithInterpretedFramesNativeStack': [SKIP],
'test-log/LogInterpretedFramesNativeStack': [SKIP], 'test-log/LogInterpretedFramesNativeStack': [SKIP],
'test-log/LogInterpretedFramesNativeStackWithSerialization': [SKIP],
'test-serialize/CodeSerializerOnePlusOneWithInterpretedFramesNativeStack': [SKIP],
# Crashes on native arm. # Crashes on native arm.
'test-macro-assembler-arm/ExtractLane': [PASS, ['arch == arm and not simulator_run', SKIP]], 'test-macro-assembler-arm/ExtractLane': [PASS, ['arch == arm and not simulator_run', SKIP]],
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <vector> #include <vector>
#include "src/api-inl.h" #include "src/api-inl.h"
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/compilation-cache.h"
#include "src/log-utils.h" #include "src/log-utils.h"
#include "src/log.h" #include "src/log.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
...@@ -660,6 +661,68 @@ UNINITIALIZED_TEST(LogInterpretedFramesNativeStack) { ...@@ -660,6 +661,68 @@ UNINITIALIZED_TEST(LogInterpretedFramesNativeStack) {
} }
isolate->Dispose(); isolate->Dispose();
} }
UNINITIALIZED_TEST(LogInterpretedFramesNativeStackWithSerialization) {
SETUP_FLAGS();
i::FLAG_interpreted_frames_native_stack = true;
i::FLAG_always_opt = false;
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::ScriptCompiler::CachedData* cache = nullptr;
bool has_cache = cache != nullptr;
// NOTE(mmarchini): Runs the test two times. The first time it will compile
// our script and will create a code cache for it. The second time we'll
// deserialize the cache and check if our function was logged correctly.
// We disallow compilation on the second run to ensure we're loading from
// cache.
do {
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
has_cache = cache != nullptr;
v8::ScriptCompiler::CompileOptions options =
has_cache ? v8::ScriptCompiler::kConsumeCodeCache
: v8::ScriptCompiler::kEagerCompile;
v8::HandleScope scope(isolate);
v8::Isolate::Scope isolate_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Local<v8::String> source = v8_str(
"function eyecatcher() { return a * a; } return eyecatcher();");
v8::Local<v8::String> arg_str = v8_str("a");
v8::ScriptOrigin origin(v8_str("filename"));
i::DisallowCompilation* no_compile_expected =
has_cache ? new i::DisallowCompilation(
reinterpret_cast<i::Isolate*>(isolate))
: nullptr;
v8::ScriptCompiler::Source script_source(source, origin, cache);
v8::Local<v8::Function> fun =
v8::ScriptCompiler::CompileFunctionInContext(
context, &script_source, 1, &arg_str, 0, nullptr, options)
.ToLocalChecked();
if (has_cache) {
logger.StopLogging();
CHECK(logger.ContainsLine({"InterpretedFunction", "eyecatcher"}));
}
v8::Local<v8::Value> arg = v8_num(3);
v8::Local<v8::Value> result =
fun->Call(context, v8::Undefined(isolate), 1, &arg).ToLocalChecked();
CHECK_EQ(9, result->Int32Value(context).FromJust());
cache = v8::ScriptCompiler::CreateCodeCacheForFunction(fun);
if (no_compile_expected != nullptr) delete no_compile_expected;
}
isolate->Dispose();
} while (!has_cache);
delete cache;
}
#endif // V8_TARGET_ARCH_ARM #endif // V8_TARGET_ARCH_ARM
UNINITIALIZED_TEST(ExternalCodeEventListener) { UNINITIALIZED_TEST(ExternalCodeEventListener) {
......
...@@ -1616,7 +1616,7 @@ static Handle<SharedFunctionInfo> CompileScriptAndProduceCache( ...@@ -1616,7 +1616,7 @@ static Handle<SharedFunctionInfo> CompileScriptAndProduceCache(
return sfi; return sfi;
} }
void TestCodeSerializerOnePlusOneImpl() { void TestCodeSerializerOnePlusOneImpl(bool verify_builtins_count = true) {
LocalContext context; LocalContext context;
Isolate* isolate = CcTest::i_isolate(); Isolate* isolate = CcTest::i_isolate();
isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
...@@ -1660,13 +1660,23 @@ void TestCodeSerializerOnePlusOneImpl() { ...@@ -1660,13 +1660,23 @@ void TestCodeSerializerOnePlusOneImpl() {
Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked(); Execution::Call(isolate, copy_fun, global, 0, nullptr).ToHandleChecked();
CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value()); CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value());
CHECK_EQ(builtins_count, CountBuiltins()); if (verify_builtins_count) CHECK_EQ(builtins_count, CountBuiltins());
delete cache; delete cache;
} }
TEST(CodeSerializerOnePlusOne) { TestCodeSerializerOnePlusOneImpl(); } TEST(CodeSerializerOnePlusOne) { TestCodeSerializerOnePlusOneImpl(); }
// See bug v8:9122
#ifndef V8_TARGET_ARCH_ARM
TEST(CodeSerializerOnePlusOneWithInterpretedFramesNativeStack) {
FLAG_interpreted_frames_native_stack = true;
// We pass false because this test will create IET copies (which are
// builtins).
TestCodeSerializerOnePlusOneImpl(false);
}
#endif
TEST(CodeSerializerOnePlusOneWithDebugger) { TEST(CodeSerializerOnePlusOneWithDebugger) {
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
static v8::debug::DebugDelegate dummy_delegate; static v8::debug::DebugDelegate dummy_delegate;
......
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