Serializer: correctly deal with internal references.
authoryangguo <yangguo@chromium.org>
Thu, 5 Mar 2015 13:46:31 +0000 (05:46 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 5 Mar 2015 13:46:46 +0000 (13:46 +0000)
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}

16 files changed:
src/arm/assembler-arm-inl.h
src/arm64/assembler-arm64-inl.h
src/assembler.cc
src/assembler.h
src/compiler.cc
src/disassembler.cc
src/ia32/assembler-ia32-inl.h
src/mips/assembler-mips-inl.h
src/mips64/assembler-mips64-inl.h
src/objects.cc
src/ppc/assembler-ppc-inl.h
src/serialize.cc
src/x64/assembler-x64-inl.h
src/x87/assembler-x87-inl.h
test/cctest/test-serialize.cc
test/mjsunit/mjsunit.status

index 876cd3d1bd04ce0aa99308603c1d81eb999a9a99..0be6f921e40684ccb584c05c76bc3a28bfb5a7c1 100644 (file)
@@ -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();
index b13635f28e3bdfff294f5abffe88ee0718141b7d..d9d919c438df89e61ac01dae4a995a6acfdeb0fe 100644 (file)
@@ -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();
index 86d4b11aeb5d113d5f1adce63e07f341a183de6a..9ad8bc613d232035246071ab5138cd58db416ead 100644 (file)
@@ -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()) << ")  ("
index 9e6311dafd049e69c0e79ac867ecbf438241ebb5..b6351fae44d20f71c02b20804d4b760a28421326 100644 (file)
@@ -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
index 33254cdd2c501c2a10deecc9fe01ac817e2e8632..9e7676cc0ee9e3fe01b59a3cd71f8207a13663ea 100644 (file)
@@ -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);
 
index 36638f551641a8d487f9b6914d6459082b0ebe90..37e0c83f80f7561de32658e22eb25dbd7823ae94 100644 (file)
@@ -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:");
index c7ec6d9918c2d371fe9c5cec43e2c8a0522401be..521ab4fab4e9f367c91496ff75fff4129b2299d4 100644 (file)
@@ -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_));
index 3e98222fc6394cc8d4aeb2cf68b305fc69777fd6..f9812b994037fd75e4a7a8006e8b63b7b21dd48c 100644 (file)
@@ -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();
index f1e3e587efb3b985d38f39c451b38883dac5527a..ae427d6bf313ac0c7cc4ebfcff00708767fa4524 100644 (file)
@@ -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();
index 172cc2ae73888001e36d04d752ac0e898bad80e2..717a16a9cbe280125557d42d2191e967d18d5c5d 100644 (file)
@@ -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);
 }
 
index ec8d61926f87c6ba46618d5f4c4be5a00052e656..86bb6db435b379335cc020586eeb582007c5d136 100644 (file)
@@ -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();
index 0b39d25642a324f68ca766fc2223a98c2bc2e4ba..78f1ace66de0e97c971ce91a63f31ecbeb64ae27 100644 (file)
@@ -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
index 64c71cfaee9afca8ef3d87d44fcb0b2c7c637413..e8f90c6aca5c39c2f7983a5c17be787e600886fd 100644 (file)
@@ -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) {
index 6555ccdd83f3cf384c3a7315be6649a271aa6f96..95cc26e9cbcfb4180e57d0ca5a06293063010f6d 100644 (file)
@@ -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_));
index 9b56a6947be1a28441893dbce21e920b8845c3be..21a27f534e0a5d457291de34a4d5f90ffd3180be 100644 (file)
@@ -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();
+}
index 101c7a0ee193dea1e6d473897add3f35ca450a3b..2fa3d3bdc38bff807ce699bf77249b171f8fc7ed 100644 (file)
   '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],