Revision: 24378
Author: [email protected]
Date: Thu Oct 2 07:12:46 2014 UTC
Log: Handle external strings in the code serializer.
[email protected]
Review URL: https://codereview.chromium.org/623453003
https://code.google.com/p/v8/source/detail?r=24378
Modified:
/branches/bleeding_edge/src/serialize.cc
/branches/bleeding_edge/src/serialize.h
/branches/bleeding_edge/test/cctest/test-serialize.cc
=======================================
--- /branches/bleeding_edge/src/serialize.cc Thu Oct 2 07:04:28 2014 UTC
+++ /branches/bleeding_edge/src/serialize.cc Thu Oct 2 07:12:46 2014 UTC
@@ -833,6 +833,7 @@
return address;
}
}
+
void Deserializer::ReadChunk(Object** current,
Object** limit,
@@ -1514,10 +1515,8 @@
}
-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,13 +1545,79 @@
}
// Serialize the map (first word of the object).
- serializer_->SerializeObject(object_->map(), kPlain, kStartOfObject, 0);
+ serializer_->SerializeObject(map, kPlain, kStartOfObject, 0);
+}
- // 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);
- OutputRawData(object_->address() + size);
+
+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(map->instance_type(), size, this);
+ OutputRawData(object_->address() + size);
+ }
}
@@ -1697,7 +1762,7 @@
}
}
// 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 @@
}
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;
=======================================
--- /branches/bleeding_edge/src/serialize.h Mon Sep 29 07:53:22 2014 UTC
+++ /branches/bleeding_edge/src/serialize.h Thu Oct 2 07:12:46 2014 UTC
@@ -439,12 +439,16 @@
}
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_;
=======================================
--- /branches/bleeding_edge/test/cctest/test-serialize.cc Thu Sep 25
07:32:13 2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-serialize.cc Thu Oct 2
07:12:46 2014 UTC
@@ -899,6 +899,163 @@
delete cache;
source.Dispose();
}
+
+
+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) {
--
--
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.