Revision: 22540
Author:   [email protected]
Date:     Wed Jul 23 07:16:32 2014 UTC
Log: Correctly hook up back references to internalized strings in code deserializer.

[email protected]

Review URL: https://codereview.chromium.org/411483002
http://code.google.com/p/v8/source/detail?r=22540

Added:
 /branches/bleeding_edge/test/mjsunit/deserialize-reference.js
Modified:
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/serialize.cc
 /branches/bleeding_edge/src/serialize.h
 /branches/bleeding_edge/test/cctest/test-serialize.cc

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/deserialize-reference.js Wed Jul 23 07:16:32 2014 UTC
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --cache=code --serialize-toplevel
+
+var a = "123";
+assertEquals(a, "123");
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Mon Jul 21 13:10:14 2014 UTC
+++ /branches/bleeding_edge/src/objects-inl.h   Wed Jul 23 07:16:32 2014 UTC
@@ -6578,6 +6578,32 @@
   }
   return SlowAsArrayIndex(index);
 }
+
+
+void String::SetForwardedInternalizedString(String* canonical) {
+  ASSERT(IsInternalizedString());
+  ASSERT(HasHashCode());
+  if (canonical == this) return;  // No need to forward.
+  ASSERT(SlowEquals(canonical));
+  ASSERT(canonical->IsInternalizedString());
+  ASSERT(canonical->HasHashCode());
+  WRITE_FIELD(this, kHashFieldOffset, canonical);
+ // Setting the hash field to a tagged value sets the LSB, causing the hash + // code to be interpreted as uninitialized. We use this fact to recognize
+  // that we have a forwarded string.
+  ASSERT(!HasHashCode());
+}
+
+
+String* String::GetForwardedInternalizedString() {
+  ASSERT(IsInternalizedString());
+  if (HasHashCode()) return this;
+  String* canonical = String::cast(READ_FIELD(this, kHashFieldOffset));
+  ASSERT(canonical->IsInternalizedString());
+  ASSERT(SlowEquals(canonical));
+  ASSERT(canonical->HasHashCode());
+  return canonical;
+}


 Object* JSReceiver::GetConstructor() {
=======================================
--- /branches/bleeding_edge/src/objects.h       Tue Jul 22 08:28:49 2014 UTC
+++ /branches/bleeding_edge/src/objects.h       Wed Jul 23 07:16:32 2014 UTC
@@ -9310,6 +9310,11 @@
   static Handle<FixedArray> CalculateLineEnds(Handle<String> string,
                                               bool include_ending_line);

+  // Use the hash field to forward to the canonical internalized string
+  // when deserializing an internalized string.
+  inline void SetForwardedInternalizedString(String* string);
+  inline String* GetForwardedInternalizedString();
+
  private:
   friend class Name;
   friend class StringTableInsertionKey;
=======================================
--- /branches/bleeding_edge/src/serialize.cc    Tue Jul 22 10:35:38 2014 UTC
+++ /branches/bleeding_edge/src/serialize.cc    Wed Jul 23 07:16:32 2014 UTC
@@ -867,7 +867,7 @@
 };


-HeapObject* Deserializer::ProcessObjectFromSerializedCode(HeapObject* obj) { +HeapObject* Deserializer::ProcessNewObjectFromSerializedCode(HeapObject* obj) {
   if (obj->IsString()) {
     String* string = String::cast(obj);
     // Uninitialize hash field as the hash seed may have changed.
@@ -876,11 +876,21 @@
       DisallowHeapAllocation no_gc;
       HandleScope scope(isolate_);
       StringTableInsertionKey key(string);
-      return *StringTable::LookupKey(isolate_, &key);
+      String* canonical = *StringTable::LookupKey(isolate_, &key);
+      string->SetForwardedInternalizedString(canonical);
+      return canonical;
     }
   }
   return obj;
 }
+
+
+Object* Deserializer::ProcessBackRefInSerializedCode(Object* obj) {
+  if (obj->IsInternalizedString()) {
+    return String::cast(obj)->GetForwardedInternalizedString();
+  }
+  return obj;
+}


 // This routine writes the new object into the pointer provided and then
@@ -907,7 +917,7 @@
if (obj->IsAllocationSite()) RelinkAllocationSite(AllocationSite::cast(obj));

   // Fix up strings from serialized user code.
- if (deserializing_user_code()) obj = ProcessObjectFromSerializedCode(obj); + if (deserializing_user_code()) obj = ProcessNewObjectFromSerializedCode(obj);

   *write_back = obj;
 #ifdef DEBUG
@@ -972,6 +982,9 @@
} else if (where == kBackref) { \ emit_write_barrier = (space_number == NEW_SPACE); \ new_object = GetAddressFromEnd(data & kSpaceMask); \ + if (deserializing_user_code()) { \ + new_object = ProcessBackRefInSerializedCode(new_object); \ + } \ } else if (where == kBuiltin) { \ ASSERT(deserializing_user_code()); \ int builtin_id = source_->GetInt(); \
@@ -992,6 +1005,9 @@
reinterpret_cast<Address>(current) + skip); \ emit_write_barrier = (space_number == NEW_SPACE); \ new_object = GetAddressFromEnd(data & kSpaceMask); \ + if (deserializing_user_code()) { \ + new_object = ProcessBackRefInSerializedCode(new_object); \ + } \ } \ if (within == kInnerPointer) { \ if (space_number != CODE_SPACE || new_object->IsCode()) { \
=======================================
--- /branches/bleeding_edge/src/serialize.h     Wed Jul 16 06:59:14 2014 UTC
+++ /branches/bleeding_edge/src/serialize.h     Wed Jul 23 07:16:32 2014 UTC
@@ -280,7 +280,9 @@
       Object** start, Object** end, int space, Address object_address);
   void ReadObject(int space_number, Object** write_back);

-  HeapObject* ProcessObjectFromSerializedCode(HeapObject* obj);
+ // Special handling for serialized code like hooking up internalized strings.
+  HeapObject* ProcessNewObjectFromSerializedCode(HeapObject* obj);
+  Object* ProcessBackRefInSerializedCode(Object* obj);

   // This routine both allocates a new object, and also keeps
   // track of where objects have been allocated so that we can
=======================================
--- /branches/bleeding_edge/test/cctest/test-serialize.cc Wed Jul 16 12:18:33 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-serialize.cc Wed Jul 23 07:16:32 2014 UTC
@@ -791,3 +791,56 @@

   delete cache;
 }
+
+
+TEST(SerializeToplevelIsolates) {
+  FLAG_serialize_toplevel = true;
+
+  const char* source = "function f() { return 'abc'; }; f() + 'def'";
+  v8::ScriptCompiler::CachedData* cache;
+
+  v8::Isolate* isolate = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate);
+    v8::HandleScope scope(isolate);
+    v8::Local<v8::Context> context = v8::Context::New(isolate);
+    v8::Context::Scope context_scope(context);
+
+    v8::Local<v8::String> source_str = v8_str(source);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin);
+ v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
+        isolate, &source, v8::ScriptCompiler::kProduceCodeCache);
+    const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
+    // Persist cached data.
+    uint8_t* buffer = NewArray<uint8_t>(data->length);
+    MemCopy(buffer, data->data, data->length);
+    cache = new v8::ScriptCompiler::CachedData(
+        buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
+
+    v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+    CHECK(result->ToString()->Equals(v8_str("abcdef")));
+  }
+  isolate->Dispose();
+
+  isolate = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate);
+    v8::HandleScope scope(isolate);
+    v8::Local<v8::Context> context = v8::Context::New(isolate);
+    v8::Context::Scope context_scope(context);
+
+    v8::Local<v8::String> source_str = v8_str(source);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin, cache);
+    v8::Local<v8::UnboundScript> script;
+    {
+      DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate));
+      script = v8::ScriptCompiler::CompileUnbound(
+          isolate, &source, v8::ScriptCompiler::kConsumeCodeCache);
+    }
+    v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+    CHECK(result->ToString()->Equals(v8_str("abcdef")));
+  }
+  isolate->Dispose();
+}

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to