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.