Commit ce45b00e authored by yangguo's avatar yangguo Committed by Commit bot

Serializer: correctly deal with internal references.

Internal references are absolute addresses into the instruction
stream. Turn them into relative addresses when serializing and
back when deserializing to keep them valid.

R=bmeurer@chromium.org

Review URL: https://codereview.chromium.org/976623002

Cr-Commit-Position: refs/heads/master@{#27020}
parent cb4540db
......@@ -184,12 +184,24 @@ void RelocInfo::set_target_object(Object* target,
}
Address RelocInfo::target_reference() {
Address RelocInfo::target_external_reference() {
DCHECK(rmode_ == EXTERNAL_REFERENCE);
return Assembler::target_address_at(pc_, host_);
}
Address RelocInfo::target_internal_reference() {
DCHECK(rmode_ == INTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
void RelocInfo::set_target_internal_reference(Address target) {
DCHECK(rmode_ == INTERNAL_REFERENCE);
Memory::Address_at(pc_) = target;
}
Address RelocInfo::target_runtime_entry(Assembler* origin) {
DCHECK(IsRuntimeEntry(rmode_));
return target_address();
......
......@@ -733,12 +733,24 @@ void RelocInfo::set_target_object(Object* target,
}
Address RelocInfo::target_reference() {
Address RelocInfo::target_external_reference() {
DCHECK(rmode_ == EXTERNAL_REFERENCE);
return Assembler::target_address_at(pc_, host_);
}
Address RelocInfo::target_internal_reference() {
DCHECK(rmode_ == INTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
void RelocInfo::set_target_internal_reference(Address target) {
DCHECK(rmode_ == INTERNAL_REFERENCE);
Memory::Address_at(pc_) = target;
}
Address RelocInfo::target_runtime_entry(Assembler* origin) {
DCHECK(IsRuntimeEntry(rmode_));
return target_address();
......
......@@ -861,8 +861,9 @@ void RelocInfo::Print(Isolate* isolate, std::ostream& os) { // NOLINT
os << " (" << Brief(target_object()) << ")";
} else if (rmode_ == EXTERNAL_REFERENCE) {
ExternalReferenceEncoder ref_encoder(isolate);
os << " (" << ref_encoder.NameOfAddress(target_reference()) << ") ("
<< static_cast<const void*>(target_reference()) << ")";
os << " (" << ref_encoder.NameOfAddress(target_external_reference())
<< ") (" << static_cast<const void*>(target_external_reference())
<< ")";
} else if (IsCodeTarget(rmode_)) {
Code* code = Code::GetCodeFromTargetAddress(target_address());
os << " (" << Code::Kind2String(code->kind()) << ") ("
......
......@@ -578,9 +578,14 @@ class RelocInfo {
// place, ready to be patched with the target.
INLINE(int target_address_size());
// Read the reference in the instruction this relocation
// applies to; can only be called if rmode_ is EXTERNAL_REFERENCE.
INLINE(Address target_external_reference());
// Read/modify the reference in the instruction this relocation
// applies to; can only be called if rmode_ is external_reference
INLINE(Address target_reference());
// applies to; can only be called if rmode_ is INTERNAL_REFERENCE.
INLINE(Address target_internal_reference());
INLINE(void set_target_internal_reference(Address target));
// Read/modify the address of a call instruction. This is used to relocate
// the break points where straight-line code is patched with a call
......
......@@ -522,6 +522,9 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
}
}
// Do not use Crankshaft if the code is intended to be serialized.
if (!isolate()->use_crankshaft()) return SetLastStatus(FAILED);
if (FLAG_trace_opt) {
OFStream os(stdout);
os << "[compiling method " << Brief(*info()->closure())
......@@ -947,7 +950,6 @@ MaybeHandle<Code> Compiler::GetLazyCode(Handle<JSFunction> function) {
PostponeInterruptsScope postpone(isolate);
info.SetOptimizing(BailoutId::None(), handle(function->shared()->code()));
info.MarkAsContextSpecializing();
if (GetOptimizedCodeNow(&info)) {
DCHECK(function->shared()->is_compiled());
......@@ -967,7 +969,7 @@ MaybeHandle<Code> Compiler::GetLazyCode(Handle<JSFunction> function) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCodeCommon(&info),
Code);
if (FLAG_always_opt && isolate->use_crankshaft()) {
if (FLAG_always_opt) {
Handle<Code> opt_code;
if (Compiler::GetOptimizedCode(
function, result,
......@@ -1488,7 +1490,6 @@ MaybeHandle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function,
Isolate* isolate = info->isolate();
DCHECK(AllowCompilation::IsAllowed(isolate));
VMState<COMPILER> state(isolate);
DCHECK(isolate->use_crankshaft());
DCHECK(!isolate->has_pending_exception());
PostponeInterruptsScope postpone(isolate);
......
......@@ -186,7 +186,7 @@ static int DecodeIt(Isolate* isolate, std::ostream* os,
out.AddFormatted(" ;; object: %s", obj_name.get());
} else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
const char* reference_name =
ref_encoder.NameOfAddress(relocinfo.target_reference());
ref_encoder.NameOfAddress(relocinfo.target_external_reference());
out.AddFormatted(" ;; external reference (%s)", reference_name);
} else if (RelocInfo::IsCodeTarget(rmode)) {
out.AddFormatted(" ;; code:");
......
......@@ -154,12 +154,24 @@ void RelocInfo::set_target_object(Object* target,
}
Address RelocInfo::target_reference() {
Address RelocInfo::target_external_reference() {
DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
Address RelocInfo::target_internal_reference() {
DCHECK(rmode_ == INTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
void RelocInfo::set_target_internal_reference(Address target) {
DCHECK(rmode_ == INTERNAL_REFERENCE);
Memory::Address_at(pc_) = target;
}
Address RelocInfo::target_runtime_entry(Assembler* origin) {
DCHECK(IsRuntimeEntry(rmode_));
return reinterpret_cast<Address>(*reinterpret_cast<int32_t*>(pc_));
......
......@@ -229,12 +229,24 @@ void RelocInfo::set_target_object(Object* target,
}
Address RelocInfo::target_reference() {
Address RelocInfo::target_external_reference() {
DCHECK(rmode_ == EXTERNAL_REFERENCE);
return Assembler::target_address_at(pc_, host_);
}
Address RelocInfo::target_internal_reference() {
DCHECK(rmode_ == INTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
void RelocInfo::set_target_internal_reference(Address target) {
DCHECK(rmode_ == INTERNAL_REFERENCE);
Memory::Address_at(pc_) = target;
}
Address RelocInfo::target_runtime_entry(Assembler* origin) {
DCHECK(IsRuntimeEntry(rmode_));
return target_address();
......
......@@ -223,12 +223,24 @@ void RelocInfo::set_target_object(Object* target,
}
Address RelocInfo::target_reference() {
Address RelocInfo::target_external_reference() {
DCHECK(rmode_ == EXTERNAL_REFERENCE);
return Assembler::target_address_at(pc_, host_);
}
Address RelocInfo::target_internal_reference() {
DCHECK(rmode_ == INTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
void RelocInfo::set_target_internal_reference(Address target) {
DCHECK(rmode_ == INTERNAL_REFERENCE);
Memory::Address_at(pc_) = target;
}
Address RelocInfo::target_runtime_entry(Assembler* origin) {
DCHECK(IsRuntimeEntry(rmode_));
return target_address();
......
......@@ -10754,7 +10754,7 @@ void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
Address p = rinfo->target_reference();
Address p = rinfo->target_external_reference();
VisitExternalReference(&p);
}
......
......@@ -154,12 +154,24 @@ void RelocInfo::set_target_object(Object* target,
}
Address RelocInfo::target_reference() {
Address RelocInfo::target_external_reference() {
DCHECK(rmode_ == EXTERNAL_REFERENCE);
return Assembler::target_address_at(pc_, host_);
}
Address RelocInfo::target_internal_reference() {
DCHECK(rmode_ == INTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
void RelocInfo::set_target_internal_reference(Address target) {
DCHECK(rmode_ == INTERNAL_REFERENCE);
Memory::Address_at(pc_) = target;
}
Address RelocInfo::target_runtime_entry(Assembler* origin) {
DCHECK(IsRuntimeEntry(rmode_));
return target_address();
......
......@@ -898,23 +898,20 @@ void Deserializer::ReadObject(int space_number, Object** write_back) {
DCHECK(space_number != CODE_SPACE);
}
#endif
#if V8_TARGET_ARCH_PPC
// If we're on a platform that uses function descriptors
// these jump tables make use of RelocInfo::INTERNAL_REFERENCE.
// As the V8 serialization code doesn't handle that relocation type
// we use this to fix up code that has function descriptors.
if (space_number == CODE_SPACE) {
Code* code = reinterpret_cast<Code*>(HeapObject::FromAddress(address));
for (RelocIterator it(code); !it.done(); it.next()) {
RelocInfo::Mode rmode = it.rinfo()->rmode();
if (RelocInfo::IsInternalReference(rmode) ||
RelocInfo::IsInternalReferenceEncoded(rmode)) {
Assembler::RelocateInternalReference(it.rinfo()->pc(), 0,
code->instruction_start(), rmode);
}
if (obj->IsCode()) {
// Turn internal references encoded as offsets back to absolute addresses.
Code* code = Code::cast(obj);
Address entry = code->entry();
int mode_mask = RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE);
for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
intptr_t offset =
reinterpret_cast<intptr_t>(rinfo->target_internal_reference());
DCHECK(0 <= offset && offset <= code->instruction_size());
rinfo->set_target_internal_reference(entry + offset);
}
}
#endif
}
......@@ -1970,7 +1967,7 @@ void Serializer::ObjectSerializer::VisitExternalReference(RelocInfo* rinfo) {
HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
sink_->Put(kExternalReference + how_to_code + kStartOfObject, "ExternalRef");
sink_->PutInt(skip, "SkipB4ExternalRef");
Address target = rinfo->target_reference();
Address target = rinfo->target_external_reference();
sink_->PutInt(serializer_->EncodeExternalReference(target), "reference id");
bytes_processed_so_far_ += rinfo->target_address_size();
}
......@@ -2047,17 +2044,26 @@ void Serializer::ObjectSerializer::VisitExternalOneByteString(
Address Serializer::ObjectSerializer::PrepareCode() {
// To make snapshots reproducible, we make a copy of the code object
// and wipe all pointers in the copy, which we then serialize.
Code* code = serializer_->CopyCode(Code::cast(object_));
Code* original = Code::cast(object_);
Code* code = serializer_->CopyCode(original);
// Code age headers are not serializable.
code->MakeYoung(serializer_->isolate());
int mode_mask =
RelocInfo::kCodeTargetMask |
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
Address entry = original->entry();
int mode_mask = RelocInfo::kCodeTargetMask |
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE);
for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
if (!(FLAG_enable_ool_constant_pool && it.rinfo()->IsInConstantPool())) {
it.rinfo()->WipeOut();
RelocInfo* rinfo = it.rinfo();
if (RelocInfo::IsInternalReference(rinfo->rmode())) {
// Convert internal references to relative offsets.
Address target = rinfo->target_internal_reference();
intptr_t offset = target - entry;
DCHECK(0 <= offset && offset <= original->instruction_size());
rinfo->set_target_internal_reference(reinterpret_cast<Address>(offset));
} else if (!(FLAG_enable_ool_constant_pool && rinfo->IsInConstantPool())) {
rinfo->WipeOut();
}
}
// We need to wipe out the header fields *after* wiping out the
......
......@@ -366,12 +366,24 @@ Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
}
Address RelocInfo::target_reference() {
Address RelocInfo::target_external_reference() {
DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
Address RelocInfo::target_internal_reference() {
DCHECK(rmode_ == INTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
void RelocInfo::set_target_internal_reference(Address target) {
DCHECK(rmode_ == INTERNAL_REFERENCE);
Memory::Address_at(pc_) = target;
}
void RelocInfo::set_target_object(Object* target,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
......
......@@ -155,12 +155,24 @@ void RelocInfo::set_target_object(Object* target,
}
Address RelocInfo::target_reference() {
Address RelocInfo::target_external_reference() {
DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
Address RelocInfo::target_internal_reference() {
DCHECK(rmode_ == INTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
void RelocInfo::set_target_internal_reference(Address target) {
DCHECK(rmode_ == INTERNAL_REFERENCE);
Memory::Address_at(pc_) = target;
}
Address RelocInfo::target_runtime_entry(Assembler* origin) {
DCHECK(IsRuntimeEntry(rmode_));
return reinterpret_cast<Address>(*reinterpret_cast<int32_t*>(pc_));
......
......@@ -706,6 +706,9 @@ UNINITIALIZED_DEPENDENT_TEST(CustomContextDeserialization,
TEST(PerIsolateSnapshotBlobs) {
const char* flag = "--turbo-filter=\"\"";
FlagList::SetFlagsFromString(flag, StrLength(flag));
const char* source1 = "function f() { return 42; }";
const char* source2 =
"function f() { return g() * 2; }"
......@@ -1496,3 +1499,52 @@ TEST(SerializeWithHarmonyScoping) {
}
isolate2->Dispose();
}
TEST(SerializeInternalReference) {
// Disable experimental natives that are loaded after deserialization.
FLAG_turbo_deoptimization = false;
FLAG_context_specialization = false;
FLAG_always_opt = true;
const char* flag = "--turbo-filter=foo";
FlagList::SetFlagsFromString(flag, StrLength(flag));
const char* source =
"var foo = (function(stdlib, foreign, heap) {"
" function foo(i) {"
" i = i|0;"
" var j = 0;"
" switch (i) {"
" case 0:"
" case 1: j = 1; break;"
" case 2:"
" case 3: j = 2; break;"
" case 4:"
" case 5: j = 3; break;"
" default: j = 0; break;"
" }"
" return j|0;"
" }"
" return { foo: foo };"
"})(this, {}, undefined).foo;"
"foo(1);";
v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source);
CHECK(data.data);
v8::Isolate::CreateParams params;
params.snapshot_blob = &data;
v8::Isolate* isolate = v8::Isolate::New(params);
{
v8::Isolate::Scope i_scope(isolate);
v8::HandleScope h_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
delete[] data.data; // We can dispose of the snapshot blob now.
v8::Context::Scope c_scope(context);
v8::Handle<v8::Function> foo =
v8::Handle<v8::Function>::Cast(CompileRun("foo"));
CHECK(v8::Utils::OpenHandle(*foo)->code()->is_turbofanned());
CHECK_EQ(3, CompileRun("foo(4)")->ToInt32(isolate)->Int32Value());
}
isolate->Dispose();
}
......@@ -101,6 +101,8 @@
'debug-stepin-builtin': [PASS, NO_VARIANTS],
'debug-stepin-constructor': [PASS, NO_VARIANTS],
'debug-stepin-function-call': [PASS, NO_VARIANTS],
'debug-stepin-positions': [PASS, NO_VARIANTS],
'debug-stepin-property-function-call': [PASS, NO_VARIANTS],
'debug-stepnext-do-while': [PASS, NO_VARIANTS],
'debug-stepout-scope-part1': [PASS, NO_VARIANTS],
'debug-stepout-scope-part2': [PASS, NO_VARIANTS],
......
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