From ce45b00e4bd661e5c12a33a40565b29f1ea279e2 Mon Sep 17 00:00:00 2001 From: yangguo Date: Thu, 5 Mar 2015 05:46:31 -0800 Subject: [PATCH] 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} --- src/arm/assembler-arm-inl.h | 14 +++++++- src/arm64/assembler-arm64-inl.h | 14 +++++++- src/assembler.cc | 5 +-- src/assembler.h | 9 ++++-- src/compiler.cc | 7 ++-- src/disassembler.cc | 2 +- src/ia32/assembler-ia32-inl.h | 14 +++++++- src/mips/assembler-mips-inl.h | 14 +++++++- src/mips64/assembler-mips64-inl.h | 14 +++++++- src/objects.cc | 2 +- src/ppc/assembler-ppc-inl.h | 14 +++++++- src/serialize.cc | 54 +++++++++++++++++-------------- src/x64/assembler-x64-inl.h | 14 +++++++- src/x87/assembler-x87-inl.h | 14 +++++++- test/cctest/test-serialize.cc | 52 +++++++++++++++++++++++++++++ test/mjsunit/mjsunit.status | 2 ++ 16 files changed, 204 insertions(+), 41 deletions(-) diff --git a/src/arm/assembler-arm-inl.h b/src/arm/assembler-arm-inl.h index 876cd3d1b..0be6f921e 100644 --- a/src/arm/assembler-arm-inl.h +++ b/src/arm/assembler-arm-inl.h @@ -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(); diff --git a/src/arm64/assembler-arm64-inl.h b/src/arm64/assembler-arm64-inl.h index b13635f28..d9d919c43 100644 --- a/src/arm64/assembler-arm64-inl.h +++ b/src/arm64/assembler-arm64-inl.h @@ -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(); diff --git a/src/assembler.cc b/src/assembler.cc index 86d4b11ae..9ad8bc613 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -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(target_reference()) << ")"; + os << " (" << ref_encoder.NameOfAddress(target_external_reference()) + << ") (" << static_cast(target_external_reference()) + << ")"; } else if (IsCodeTarget(rmode_)) { Code* code = Code::GetCodeFromTargetAddress(target_address()); os << " (" << Code::Kind2String(code->kind()) << ") (" diff --git a/src/assembler.h b/src/assembler.h index 9e6311daf..b6351fae4 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -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 diff --git a/src/compiler.cc b/src/compiler.cc index 33254cdd2..9e7676cc0 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -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 Compiler::GetLazyCode(Handle 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 Compiler::GetLazyCode(Handle function) { ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCodeCommon(&info), Code); - if (FLAG_always_opt && isolate->use_crankshaft()) { + if (FLAG_always_opt) { Handle opt_code; if (Compiler::GetOptimizedCode( function, result, @@ -1488,7 +1490,6 @@ MaybeHandle Compiler::GetOptimizedCode(Handle function, Isolate* isolate = info->isolate(); DCHECK(AllowCompilation::IsAllowed(isolate)); VMState state(isolate); - DCHECK(isolate->use_crankshaft()); DCHECK(!isolate->has_pending_exception()); PostponeInterruptsScope postpone(isolate); diff --git a/src/disassembler.cc b/src/disassembler.cc index 36638f551..37e0c83f8 100644 --- a/src/disassembler.cc +++ b/src/disassembler.cc @@ -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:"); diff --git a/src/ia32/assembler-ia32-inl.h b/src/ia32/assembler-ia32-inl.h index c7ec6d991..521ab4fab 100644 --- a/src/ia32/assembler-ia32-inl.h +++ b/src/ia32/assembler-ia32-inl.h @@ -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
(*reinterpret_cast(pc_)); diff --git a/src/mips/assembler-mips-inl.h b/src/mips/assembler-mips-inl.h index 3e98222fc..f9812b994 100644 --- a/src/mips/assembler-mips-inl.h +++ b/src/mips/assembler-mips-inl.h @@ -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(); diff --git a/src/mips64/assembler-mips64-inl.h b/src/mips64/assembler-mips64-inl.h index f1e3e587e..ae427d6bf 100644 --- a/src/mips64/assembler-mips64-inl.h +++ b/src/mips64/assembler-mips64-inl.h @@ -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(); diff --git a/src/objects.cc b/src/objects.cc index 172cc2ae7..717a16a9c 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -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); } diff --git a/src/ppc/assembler-ppc-inl.h b/src/ppc/assembler-ppc-inl.h index ec8d61926..86bb6db43 100644 --- a/src/ppc/assembler-ppc-inl.h +++ b/src/ppc/assembler-ppc-inl.h @@ -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(); diff --git a/src/serialize.cc b/src/serialize.cc index 0b39d2564..78f1ace66 100644 --- a/src/serialize.cc +++ b/src/serialize.cc @@ -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(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(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
(offset)); + } else if (!(FLAG_enable_ool_constant_pool && rinfo->IsInConstantPool())) { + rinfo->WipeOut(); } } // We need to wipe out the header fields *after* wiping out the diff --git a/src/x64/assembler-x64-inl.h b/src/x64/assembler-x64-inl.h index 64c71cfae..e8f90c6ac 100644 --- a/src/x64/assembler-x64-inl.h +++ b/src/x64/assembler-x64-inl.h @@ -366,12 +366,24 @@ Handle 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) { diff --git a/src/x87/assembler-x87-inl.h b/src/x87/assembler-x87-inl.h index 6555ccdd8..95cc26e9c 100644 --- a/src/x87/assembler-x87-inl.h +++ b/src/x87/assembler-x87-inl.h @@ -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
(*reinterpret_cast(pc_)); diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc index 9b56a6947..21a27f534 100644 --- a/test/cctest/test-serialize.cc +++ b/test/cctest/test-serialize.cc @@ -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 context = v8::Context::New(isolate); + delete[] data.data; // We can dispose of the snapshot blob now. + v8::Context::Scope c_scope(context); + v8::Handle foo = + v8::Handle::Cast(CompileRun("foo")); + CHECK(v8::Utils::OpenHandle(*foo)->code()->is_turbofanned()); + CHECK_EQ(3, CompileRun("foo(4)")->ToInt32(isolate)->Int32Value()); + } + isolate->Dispose(); +} diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status index 101c7a0ee..2fa3d3bdc 100644 --- a/test/mjsunit/mjsunit.status +++ b/test/mjsunit/mjsunit.status @@ -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], -- 2.34.1