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
This commit is contained in:
parent
f6c1f3c4a8
commit
ed04566cba
@ -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();
|
||||
}
|
||||
|
8
test/mjsunit/deserialize-reference.js
Normal file
8
test/mjsunit/deserialize-reference.js
Normal file
@ -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");
|
Loading…
Reference in New Issue
Block a user