Handle external strings in the code serializer.
R=mvstanton@chromium.org Review URL: https://codereview.chromium.org/623453003 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24378 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
2134c5c0ba
commit
43ddad10b3
@ -834,6 +834,7 @@ Address Deserializer::Allocate(int space_index, int size) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Deserializer::ReadChunk(Object** current,
|
||||
Object** limit,
|
||||
int source_space,
|
||||
@ -1514,10 +1515,8 @@ void PartialSerializer::SerializeObject(
|
||||
}
|
||||
|
||||
|
||||
void Serializer::ObjectSerializer::Serialize() {
|
||||
int space = Serializer::SpaceOfObject(object_);
|
||||
int size = object_->Size();
|
||||
|
||||
void Serializer::ObjectSerializer::SerializePrologue(int space, int size,
|
||||
Map* map) {
|
||||
sink_->Put(kNewObject + reference_representation_ + space,
|
||||
"ObjectSerialization");
|
||||
sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
|
||||
@ -1546,14 +1545,80 @@ void Serializer::ObjectSerializer::Serialize() {
|
||||
}
|
||||
|
||||
// Serialize the map (first word of the object).
|
||||
serializer_->SerializeObject(object_->map(), kPlain, kStartOfObject, 0);
|
||||
serializer_->SerializeObject(map, kPlain, kStartOfObject, 0);
|
||||
}
|
||||
|
||||
|
||||
void Serializer::ObjectSerializer::SerializeExternalString() {
|
||||
// Instead of serializing this as an external string, we serialize
|
||||
// an imaginary sequential string with the same content.
|
||||
DCHECK(object_->IsExternalString() && object_->IsInternalizedString());
|
||||
Isolate* isolate = serializer_->isolate();
|
||||
ExternalString* string = ExternalString::cast(object_);
|
||||
int length = string->length();
|
||||
Map* map;
|
||||
int size;
|
||||
const char* resource;
|
||||
// Find the map and size for the imaginary sequential string.
|
||||
if (object_->IsExternalOneByteString()) {
|
||||
map = isolate->heap()->one_byte_internalized_string_map();
|
||||
size = SeqOneByteString::SizeFor(length);
|
||||
resource = ExternalOneByteString::cast(string)->resource()->data();
|
||||
} else {
|
||||
map = isolate->heap()->internalized_string_map();
|
||||
size = SeqTwoByteString::SizeFor(length);
|
||||
resource = reinterpret_cast<const char*>(
|
||||
ExternalTwoByteString::cast(string)->resource()->data());
|
||||
}
|
||||
|
||||
int space =
|
||||
(size > Page::kMaxRegularHeapObjectSize) ? LO_SPACE : OLD_DATA_SPACE;
|
||||
SerializePrologue(space, size, map);
|
||||
|
||||
// Output the rest of the imaginary string.
|
||||
int bytes_to_output = size - HeapObject::kHeaderSize;
|
||||
|
||||
// Output raw data header. Do not bother with common raw length cases here.
|
||||
sink_->Put(kRawData, "RawDataForString");
|
||||
sink_->PutInt(bytes_to_output, "length");
|
||||
|
||||
// Serialize string header (except for map).
|
||||
Address string_start = string->address();
|
||||
for (int i = HeapObject::kHeaderSize; i < SeqString::kHeaderSize; i++) {
|
||||
sink_->PutSection(string_start[i], "StringHeader");
|
||||
}
|
||||
|
||||
// Serialize string content.
|
||||
int content_length = size - SeqString::kHeaderSize;
|
||||
for (int i = 0; i < content_length; i++) {
|
||||
sink_->PutSection(resource[i], "StringContent");
|
||||
}
|
||||
|
||||
sink_->Put(kSkip, "SkipAfterString");
|
||||
sink_->PutInt(bytes_to_output, "SkipDistance");
|
||||
}
|
||||
|
||||
|
||||
void Serializer::ObjectSerializer::Serialize() {
|
||||
if (object_->IsExternalString() && object_->IsInternalizedString()) {
|
||||
// Native source code strings are not internalized and are handled in
|
||||
// VisitExternalOneByteString. We deal with embedded external strings
|
||||
// by serializing them as sequential strings on the heap.
|
||||
// This can only happen with CodeSerializer.
|
||||
SerializeExternalString();
|
||||
} else {
|
||||
int size = object_->Size();
|
||||
Map* map = object_->map();
|
||||
SerializePrologue(Serializer::SpaceOfObject(object_), size, map);
|
||||
|
||||
// Serialize the rest of the object.
|
||||
CHECK_EQ(0, bytes_processed_so_far_);
|
||||
bytes_processed_so_far_ = kPointerSize;
|
||||
object_->IterateBody(object_->map()->instance_type(), size, this);
|
||||
|
||||
object_->IterateBody(map->instance_type(), size, this);
|
||||
OutputRawData(object_->address() + size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Serializer::ObjectSerializer::VisitPointers(Object** start,
|
||||
@ -1697,7 +1762,7 @@ void Serializer::ObjectSerializer::VisitExternalOneByteString(
|
||||
}
|
||||
}
|
||||
// One of the strings in the natives cache should match the resource. We
|
||||
// can't serialize any other kinds of external strings.
|
||||
// don't expect any other kinds of external strings here.
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@ -1876,6 +1941,11 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
|
||||
}
|
||||
|
||||
if (address_mapper_.IsMapped(heap_object)) {
|
||||
if (FLAG_trace_code_serializer) {
|
||||
PrintF("Encoding back reference to: ");
|
||||
heap_object->ShortPrint();
|
||||
PrintF("\n");
|
||||
}
|
||||
SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
|
||||
skip);
|
||||
return;
|
||||
|
@ -439,12 +439,16 @@ class Serializer : public SerializerDeserializer {
|
||||
}
|
||||
|
||||
private:
|
||||
void SerializePrologue(int space, int size, Map* map);
|
||||
|
||||
enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn };
|
||||
// This function outputs or skips the raw data between the last pointer and
|
||||
// up to the current position. It optionally can just return the number of
|
||||
// bytes to skip instead of performing a skip instruction, in case the skip
|
||||
// can be merged into the next instruction.
|
||||
int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn);
|
||||
// External strings are serialized in a way to resemble sequential strings.
|
||||
void SerializeExternalString();
|
||||
|
||||
Serializer* serializer_;
|
||||
HeapObject* object_;
|
||||
|
@ -901,6 +901,163 @@ TEST(SerializeToplevelLargeString) {
|
||||
}
|
||||
|
||||
|
||||
class OneByteResource : public v8::String::ExternalOneByteStringResource {
|
||||
public:
|
||||
OneByteResource(const char* data, size_t length)
|
||||
: data_(data), length_(length) {}
|
||||
virtual const char* data() const { return data_; }
|
||||
virtual size_t length() const { return length_; }
|
||||
|
||||
private:
|
||||
const char* data_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
|
||||
class TwoByteResource : public v8::String::ExternalStringResource {
|
||||
public:
|
||||
TwoByteResource(const char* data, size_t length)
|
||||
: data_(AsciiToTwoByteString(data)), length_(length) {}
|
||||
~TwoByteResource() { DeleteArray<const uint16_t>(data_); }
|
||||
|
||||
virtual const uint16_t* data() const { return data_; }
|
||||
virtual size_t length() const { return length_; }
|
||||
|
||||
private:
|
||||
const uint16_t* data_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
|
||||
TEST(SerializeToplevelExternalString) {
|
||||
FLAG_serialize_toplevel = true;
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
|
||||
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
// Obtain external internalized one-byte string.
|
||||
OneByteResource one_byte_resource("one_byte", 8);
|
||||
Handle<String> one_byte_string =
|
||||
isolate->factory()->NewStringFromAsciiChecked("one_byte");
|
||||
one_byte_string = isolate->factory()->InternalizeString(one_byte_string);
|
||||
one_byte_string->MakeExternal(&one_byte_resource);
|
||||
CHECK(one_byte_string->IsExternalOneByteString());
|
||||
CHECK(one_byte_string->IsInternalizedString());
|
||||
|
||||
// Obtain external internalized two-byte string.
|
||||
TwoByteResource two_byte_resource("two_byte", 8);
|
||||
Handle<String> two_byte_string =
|
||||
isolate->factory()->NewStringFromAsciiChecked("two_byte");
|
||||
two_byte_string = isolate->factory()->InternalizeString(two_byte_string);
|
||||
two_byte_string->MakeExternal(&two_byte_resource);
|
||||
CHECK(two_byte_string->IsExternalTwoByteString());
|
||||
CHECK(two_byte_string->IsInternalizedString());
|
||||
|
||||
const char* source =
|
||||
"var o = {} \n"
|
||||
"o.one_byte = 7; \n"
|
||||
"o.two_byte = 8; \n"
|
||||
"o.one_byte + o.two_byte; \n";
|
||||
Handle<String> source_string = isolate->factory()
|
||||
->NewStringFromUtf8(CStrVector(source))
|
||||
.ToHandleChecked();
|
||||
|
||||
Handle<JSObject> global(isolate->context()->global_object());
|
||||
ScriptData* cache = NULL;
|
||||
|
||||
Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
|
||||
source_string, Handle<String>(), 0, 0, false,
|
||||
Handle<Context>(isolate->native_context()), NULL, &cache,
|
||||
v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
|
||||
|
||||
Handle<SharedFunctionInfo> copy;
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
copy = Compiler::CompileScript(
|
||||
source_string, Handle<String>(), 0, 0, false,
|
||||
Handle<Context>(isolate->native_context()), NULL, &cache,
|
||||
v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
|
||||
}
|
||||
CHECK_NE(*orig, *copy);
|
||||
|
||||
Handle<JSFunction> copy_fun =
|
||||
isolate->factory()->NewFunctionFromSharedFunctionInfo(
|
||||
copy, isolate->native_context());
|
||||
|
||||
Handle<Object> copy_result =
|
||||
Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
|
||||
|
||||
CHECK_EQ(15.0f, copy_result->Number());
|
||||
|
||||
delete cache;
|
||||
}
|
||||
|
||||
|
||||
TEST(SerializeToplevelLargeExternalString) {
|
||||
FLAG_serialize_toplevel = true;
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
|
||||
|
||||
Factory* f = isolate->factory();
|
||||
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
// Create a huge external internalized string to use as variable name.
|
||||
Vector<const uint8_t> string =
|
||||
ConstructSource(STATIC_CHAR_VECTOR(""), STATIC_CHAR_VECTOR("abcdef"),
|
||||
STATIC_CHAR_VECTOR(""), 1000000);
|
||||
Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked();
|
||||
OneByteResource one_byte_resource(
|
||||
reinterpret_cast<const char*>(string.start()), string.length());
|
||||
name = f->InternalizeString(name);
|
||||
name->MakeExternal(&one_byte_resource);
|
||||
CHECK(name->IsExternalOneByteString());
|
||||
CHECK(name->IsInternalizedString());
|
||||
CHECK(isolate->heap()->InSpace(*name, LO_SPACE));
|
||||
|
||||
// Create the source, which is "var <literal> = 42; <literal>".
|
||||
Handle<String> source_str =
|
||||
f->NewConsString(
|
||||
f->NewConsString(f->NewStringFromAsciiChecked("var "), name)
|
||||
.ToHandleChecked(),
|
||||
f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name)
|
||||
.ToHandleChecked()).ToHandleChecked();
|
||||
|
||||
Handle<JSObject> global(isolate->context()->global_object());
|
||||
ScriptData* cache = NULL;
|
||||
|
||||
Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
|
||||
source_str, Handle<String>(), 0, 0, false,
|
||||
Handle<Context>(isolate->native_context()), NULL, &cache,
|
||||
v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
|
||||
|
||||
Handle<SharedFunctionInfo> copy;
|
||||
{
|
||||
DisallowCompilation no_compile_expected(isolate);
|
||||
copy = Compiler::CompileScript(
|
||||
source_str, Handle<String>(), 0, 0, false,
|
||||
Handle<Context>(isolate->native_context()), NULL, &cache,
|
||||
v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
|
||||
}
|
||||
CHECK_NE(*orig, *copy);
|
||||
|
||||
Handle<JSFunction> copy_fun =
|
||||
isolate->factory()->NewFunctionFromSharedFunctionInfo(
|
||||
copy, isolate->native_context());
|
||||
|
||||
Handle<Object> copy_result =
|
||||
Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
|
||||
|
||||
CHECK_EQ(42.0f, copy_result->Number());
|
||||
|
||||
delete cache;
|
||||
string.Dispose();
|
||||
}
|
||||
|
||||
|
||||
TEST(SerializeToplevelIsolates) {
|
||||
FLAG_serialize_toplevel = true;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user