Revision: 22398
Author: [email protected]
Date: Tue Jul 15 08:46:47 2014 UTC
Log: Fix up internalized strings after deserializing user code.
[email protected]
Review URL: https://codereview.chromium.org/387343002
http://code.google.com/p/v8/source/detail?r=22398
Modified:
/branches/bleeding_edge/src/objects.cc
/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
=======================================
--- /branches/bleeding_edge/src/objects.cc Mon Jul 14 14:52:24 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc Tue Jul 15 08:46:47 2014 UTC
@@ -14051,33 +14051,6 @@
int JSObject::GetEnumElementKeys(FixedArray* storage) {
return GetOwnElementKeys(storage,
static_cast<PropertyAttributes>(DONT_ENUM));
}
-
-
-// StringKey simply carries a string object as key.
-class StringKey : public HashTableKey {
- public:
- explicit StringKey(String* string) :
- string_(string),
- hash_(HashForObject(string)) { }
-
- bool IsMatch(Object* string) {
- // We know that all entries in a hash table had their hash keys
created.
- // Use that knowledge to have fast failure.
- if (hash_ != HashForObject(string)) {
- return false;
- }
- return string_->Equals(String::cast(string));
- }
-
- uint32_t Hash() { return hash_; }
-
- uint32_t HashForObject(Object* other) { return
String::cast(other)->Hash(); }
-
- Object* AsObject(Heap* heap) { return string_; }
-
- String* string_;
- uint32_t hash_;
-};
// StringSharedKeys are used as keys in the eval cache.
=======================================
--- /branches/bleeding_edge/src/objects.h Mon Jul 14 14:52:24 2014 UTC
+++ /branches/bleeding_edge/src/objects.h Tue Jul 15 08:46:47 2014 UTC
@@ -9328,6 +9328,7 @@
private:
friend class Name;
+ friend class StringTableInsertionKey;
static Handle<String> SlowFlatten(Handle<ConsString> cons,
PretenureFlag tenure);
=======================================
--- /branches/bleeding_edge/src/serialize.cc Mon Jul 14 11:22:03 2014 UTC
+++ /branches/bleeding_edge/src/serialize.cc Tue Jul 15 08:46:47 2014 UTC
@@ -718,6 +718,7 @@
Deserializer::Deserializer(SnapshotByteSource* source)
: isolate_(NULL),
+ deserialize_code_(false),
source_(source),
external_reference_decoder_(NULL) {
for (int i = 0; i < LAST_SPACE + 1; i++) {
@@ -832,6 +833,54 @@
}
+// Used to insert a deserialized internalized string into the string table.
+class StringTableInsertionKey : public HashTableKey {
+ public:
+ explicit StringTableInsertionKey(String* string)
+ : string_(string), hash_(HashForObject(string)) {
+ ASSERT(string->IsInternalizedString());
+ }
+
+ virtual bool IsMatch(Object* string) {
+ // We know that all entries in a hash table had their hash keys
created.
+ // Use that knowledge to have fast failure.
+ if (hash_ != HashForObject(string)) return false;
+ // We want to compare the content of two internalized strings here.
+ return string_->SlowEquals(String::cast(string));
+ }
+
+ virtual uint32_t Hash() V8_OVERRIDE { return hash_; }
+
+ virtual uint32_t HashForObject(Object* key) V8_OVERRIDE {
+ return String::cast(key)->Hash();
+ }
+
+ MUST_USE_RESULT virtual Handle<Object> AsHandle(Isolate* isolate)
+ V8_OVERRIDE {
+ return handle(string_, isolate);
+ }
+
+ String* string_;
+ uint32_t hash_;
+};
+
+
+HeapObject* Deserializer::ProcessObjectFromSerializedCode(HeapObject* obj)
{
+ if (obj->IsString()) {
+ String* string = String::cast(obj);
+ // Uninitialize hash field as the hash seed may have changed.
+ string->set_hash_field(String::kEmptyHashField);
+ if (string->IsInternalizedString()) {
+ DisallowHeapAllocation no_gc;
+ HandleScope scope(isolate_);
+ StringTableInsertionKey key(string);
+ return *StringTable::LookupKey(isolate_, &key);
+ }
+ }
+ 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
@@ -843,7 +892,6 @@
Address address = Allocate(space_number, size);
HeapObject* obj = HeapObject::FromAddress(address);
isolate_->heap()->OnAllocationEvent(obj, size);
- *write_back = obj;
Object** current = reinterpret_cast<Object**>(address);
Object** limit = current + (size >> kPointerSizeLog2);
if (FLAG_log_snapshot_positions) {
@@ -854,10 +902,12 @@
// TODO(mvstanton): consider treating the heap()->allocation_sites_list()
// as a (weak) root. If this root is relocated correctly,
// RelinkAllocationSite() isn't necessary.
- if (obj->IsAllocationSite()) {
- RelinkAllocationSite(AllocationSite::cast(obj));
- }
+ if (obj->IsAllocationSite())
RelinkAllocationSite(AllocationSite::cast(obj));
+
+ // Fix up strings from serialized user code.
+ if (deserialize_code_) obj = ProcessObjectFromSerializedCode(obj);
+ *write_back = obj;
#ifdef DEBUG
bool is_codespace = (space_number == CODE_SPACE);
ASSERT(obj->IsCode() == is_codespace);
@@ -921,13 +971,13 @@
emit_write_barrier = (space_number ==
NEW_SPACE); \
new_object = GetAddressFromEnd(data &
kSpaceMask); \
} else if (where == kBuiltin)
{ \
+
ASSERT(deserialize_code_); \
int builtin_id =
source_->GetInt(); \
ASSERT_LE(0,
builtin_id); \
ASSERT_LT(builtin_id,
Builtins::builtin_count); \
Builtins::Name name =
static_cast<Builtins::Name>(builtin_id); \
new_object =
isolate->builtins()->builtin(name); \
emit_write_barrier =
false; \
- PrintF("BUILTIN how within %d, %d\n", how,
within); \
} else
{ \
ASSERT(where ==
kBackrefWithSkip); \
int skip =
source_->GetInt(); \
@@ -1859,8 +1909,6 @@
// TODO(yangguo) wire up stubs from stub cache.
// TODO(yangguo) wire up script source.
- // TODO(yangguo) wire up internalized strings
- ASSERT(!heap_object->IsInternalizedString());
// TODO(yangguo) We cannot deal with different hash seeds yet.
ASSERT(!heap_object->IsHashTable());
@@ -1916,6 +1964,7 @@
SerializedCodeData scd(data);
SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
Deserializer deserializer(&payload);
+ deserializer.ExpectSerializedCode();
STATIC_ASSERT(NEW_SPACE == 0);
// TODO(yangguo) what happens if remaining new space is too small?
for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
=======================================
--- /branches/bleeding_edge/src/serialize.h Mon Jul 14 11:22:03 2014 UTC
+++ /branches/bleeding_edge/src/serialize.h Tue Jul 15 08:46:47 2014 UTC
@@ -251,6 +251,10 @@
}
void FlushICacheForNewCodeObjects();
+
+ // Call this to indicate that the serialized data represents user code.
+ // There are some more wiring up required in this case.
+ void ExpectSerializedCode() { deserialize_code_ = true; }
private:
virtual void VisitPointers(Object** start, Object** end);
@@ -272,6 +276,8 @@
Object** start, Object** end, int space, Address object_address);
void ReadObject(int space_number, Object** write_back);
+ HeapObject* ProcessObjectFromSerializedCode(HeapObject* obj);
+
// This routine both allocates a new object, and also keeps
// track of where objects have been allocated so that we can
// fix back references when deserializing.
@@ -291,6 +297,7 @@
// Cached current isolate.
Isolate* isolate_;
+ bool deserialize_code_;
SnapshotByteSource* source_;
// This is the address of the next object that will be allocated in each
=======================================
--- /branches/bleeding_edge/test/cctest/test-serialize.cc Mon Jul 14
11:22:03 2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-serialize.cc Tue Jul 15
08:46:47 2014 UTC
@@ -675,11 +675,10 @@
}
-TEST(SerializeToplevel) {
+TEST(SerializeToplevelOnePlusOne) {
FLAG_serialize_toplevel = true;
+ LocalContext context;
v8::HandleScope scope(CcTest::isolate());
- v8::Local<v8::Context> context = CcTest::NewContext(PRINT_EXTENSION);
- v8::Context::Scope context_scope(context);
const char* source1 = "1 + 1";
const char* source2 = "1 + 2"; // Use alternate string to verify
caching.
@@ -702,20 +701,74 @@
int builtins_count = CountBuiltins();
- Handle<SharedFunctionInfo> info =
+ Handle<SharedFunctionInfo> copy =
Compiler::CompileScript(source2_string, Handle<String>(), 0, 0,
false,
Handle<Context>(isolate->native_context()),
NULL,
&cache, CONSUME_CACHED_DATA,
NOT_NATIVES_CODE);
- CHECK_NE(*orig, *info);
- Handle<JSFunction> fun =
+ CHECK_NE(*orig, *copy);
+ Handle<JSFunction> copy_fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
- info, isolate->native_context());
+ copy, isolate->native_context());
+ Handle<JSObject> global(isolate->context()->global_object());
+ Handle<Object> copy_result =
+ Execution::Call(isolate, copy_fun, global, 0,
NULL).ToHandleChecked();
+ CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value());
+
+ CHECK_EQ(builtins_count, CountBuiltins());
+
+ delete cache;
+}
+
+
+TEST(SerializeToplevelInternalizedString) {
+ FLAG_serialize_toplevel = true;
+ LocalContext context;
+ v8::HandleScope scope(CcTest::isolate());
+
+ const char* source1 = "'string1'";
+ const char* source2 = "'string2'"; // Use alternate string to verify
caching.
+
+ Isolate* isolate = CcTest::i_isolate();
+ Handle<String> source1_string = isolate->factory()
+
->NewStringFromUtf8(CStrVector(source1))
+ .ToHandleChecked();
+
+ Handle<String> source2_string = isolate->factory()
+
->NewStringFromUtf8(CStrVector(source2))
+ .ToHandleChecked();
Handle<JSObject> global(isolate->context()->global_object());
- Handle<Object> result =
- Execution::Call(isolate, fun, global, 0, NULL).ToHandleChecked();
- CHECK_EQ(2, Handle<Smi>::cast(result)->value());
+ ScriptData* cache = NULL;
+
+ Handle<SharedFunctionInfo> orig =
+ Compiler::CompileScript(source1_string, Handle<String>(), 0, 0,
false,
+ Handle<Context>(isolate->native_context()),
NULL,
+ &cache, PRODUCE_CACHED_DATA,
NOT_NATIVES_CODE);
+ Handle<JSFunction> orig_fun =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(
+ orig, isolate->native_context());
+ Handle<Object> orig_result =
+ Execution::Call(isolate, orig_fun, global, 0,
NULL).ToHandleChecked();
+ CHECK(orig_result->IsInternalizedString());
+
+ int builtins_count = CountBuiltins();
+
+ Handle<SharedFunctionInfo> copy =
+ Compiler::CompileScript(source2_string, Handle<String>(), 0, 0,
false,
+ Handle<Context>(isolate->native_context()),
NULL,
+ &cache, CONSUME_CACHED_DATA,
NOT_NATIVES_CODE);
+ CHECK_NE(*orig, *copy);
+ Handle<JSFunction> copy_fun =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(
+ copy, isolate->native_context());
+ CHECK_NE(*orig_fun, *copy_fun);
+ Handle<Object> copy_result =
+ Execution::Call(isolate, copy_fun, global, 0,
NULL).ToHandleChecked();
+ CHECK(orig_result.is_identical_to(copy_result));
+ Handle<String> expected =
+ isolate->factory()->NewStringFromAsciiChecked("string1");
+ CHECK(Handle<String>::cast(copy_result)->Equals(*expected));
CHECK_EQ(builtins_count, CountBuiltins());
delete cache;
--
--
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.