Commit ed04566c authored by yangguo@chromium.org's avatar yangguo@chromium.org

Correctly hook up back references to internalized strings in code deserializer.

R=mvstanton@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22540 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f6c1f3c4
......@@ -6580,6 +6580,32 @@ bool String::AsArrayIndex(uint32_t* 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() {
return map()->constructor();
}
......
......@@ -9310,6 +9310,11 @@ class String: public Name {
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;
......
......@@ -867,7 +867,7 @@ class StringTableInsertionKey : public HashTableKey {
};
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,13 +876,23 @@ HeapObject* Deserializer::ProcessObjectFromSerializedCode(HeapObject* obj) {
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
// returns true if the new object was in young space and false otherwise.
// The reason for this strange interface is that otherwise the object is
......@@ -907,7 +917,7 @@ void Deserializer::ReadObject(int space_number,
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 @@ void Deserializer::ReadChunk(Object** current,
} 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 @@ void Deserializer::ReadChunk(Object** current,
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()) { \
......
......@@ -280,7 +280,9 @@ class Deserializer: public SerializerDeserializer {
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
......
......@@ -791,3 +791,56 @@ TEST(SerializeToplevelInternalizedString) {
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();
}
// 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");
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