Upgrade to 3.29
Update V8 to 3.29.88.17 and update makefiles to support building on
all the relevant platforms.
Bug: 17370214
Change-Id: Ia3407c157fd8d72a93e23d8318ccaf6ecf77fa4e
diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc
index e426e7b..94b400e 100644
--- a/test/cctest/test-serialize.cc
+++ b/test/cctest/test-serialize.cc
@@ -27,63 +27,28 @@
#include <signal.h>
-#include "sys/stat.h"
-#include "v8.h"
+#include <sys/stat.h>
-#include "debug.h"
-#include "ic-inl.h"
-#include "runtime.h"
-#include "serialize.h"
-#include "scopeinfo.h"
-#include "snapshot.h"
-#include "cctest.h"
-#include "spaces.h"
-#include "objects.h"
-#include "natives.h"
-#include "bootstrapper.h"
+#include "src/v8.h"
+
+#include "src/bootstrapper.h"
+#include "src/compilation-cache.h"
+#include "src/debug.h"
+#include "src/heap/spaces.h"
+#include "src/natives.h"
+#include "src/objects.h"
+#include "src/runtime.h"
+#include "src/scopeinfo.h"
+#include "src/serialize.h"
+#include "src/snapshot.h"
+#include "test/cctest/cctest.h"
using namespace v8::internal;
-static const unsigned kCounters = 256;
-static int local_counters[kCounters];
-static const char* local_counter_names[kCounters];
-
-
-static unsigned CounterHash(const char* s) {
- unsigned hash = 0;
- while (*++s) {
- hash |= hash << 5;
- hash += *s;
- }
- return hash;
-}
-
-
-// Callback receiver to track counters in test.
-static int* counter_function(const char* name) {
- unsigned hash = CounterHash(name) % kCounters;
- unsigned original_hash = hash;
- USE(original_hash);
- while (true) {
- if (local_counter_names[hash] == name) {
- return &local_counters[hash];
- }
- if (local_counter_names[hash] == 0) {
- local_counter_names[hash] = name;
- return &local_counters[hash];
- }
- if (strcmp(local_counter_names[hash], name) == 0) {
- return &local_counters[hash];
- }
- hash = (hash + 1) % kCounters;
- ASSERT(hash != original_hash); // Hash table has been filled up.
- }
-}
-
template <class T>
static Address AddressOf(T id) {
- return ExternalReference(id, i::Isolate::Current()).address();
+ return ExternalReference(id, CcTest::i_isolate()).address();
}
@@ -99,78 +64,60 @@
TEST(ExternalReferenceEncoder) {
- Isolate* isolate = i::Isolate::Current();
- isolate->stats_table()->SetCounterFunction(counter_function);
+ Isolate* isolate = CcTest::i_isolate();
v8::V8::Initialize();
- ExternalReferenceEncoder encoder;
+ ExternalReferenceEncoder encoder(isolate);
CHECK_EQ(make_code(BUILTIN, Builtins::kArrayCode),
Encode(encoder, Builtins::kArrayCode));
CHECK_EQ(make_code(v8::internal::RUNTIME_FUNCTION, Runtime::kAbort),
Encode(encoder, Runtime::kAbort));
- CHECK_EQ(make_code(IC_UTILITY, IC::kLoadCallbackProperty),
- Encode(encoder, IC_Utility(IC::kLoadCallbackProperty)));
- ExternalReference keyed_load_function_prototype =
- ExternalReference(isolate->counters()->keyed_load_function_prototype());
- CHECK_EQ(make_code(STATS_COUNTER, Counters::k_keyed_load_function_prototype),
- encoder.Encode(keyed_load_function_prototype.address()));
ExternalReference stack_limit_address =
ExternalReference::address_of_stack_limit(isolate);
- CHECK_EQ(make_code(UNCLASSIFIED, 4),
+ CHECK_EQ(make_code(UNCLASSIFIED, 2),
encoder.Encode(stack_limit_address.address()));
ExternalReference real_stack_limit_address =
ExternalReference::address_of_real_stack_limit(isolate);
- CHECK_EQ(make_code(UNCLASSIFIED, 5),
- encoder.Encode(real_stack_limit_address.address()));
-#ifdef ENABLE_DEBUGGER_SUPPORT
- CHECK_EQ(make_code(UNCLASSIFIED, 16),
- encoder.Encode(ExternalReference::debug_break(isolate).address()));
-#endif // ENABLE_DEBUGGER_SUPPORT
- CHECK_EQ(make_code(UNCLASSIFIED, 10),
- encoder.Encode(
- ExternalReference::new_space_start(isolate).address()));
CHECK_EQ(make_code(UNCLASSIFIED, 3),
- encoder.Encode(
- ExternalReference::roots_array_start(isolate).address()));
+ encoder.Encode(real_stack_limit_address.address()));
+ CHECK_EQ(make_code(UNCLASSIFIED, 8),
+ encoder.Encode(ExternalReference::debug_break(isolate).address()));
+ CHECK_EQ(
+ make_code(UNCLASSIFIED, 4),
+ encoder.Encode(ExternalReference::new_space_start(isolate).address()));
+ CHECK_EQ(
+ make_code(UNCLASSIFIED, 1),
+ encoder.Encode(ExternalReference::roots_array_start(isolate).address()));
+ CHECK_EQ(make_code(UNCLASSIFIED, 34),
+ encoder.Encode(ExternalReference::cpu_features().address()));
}
TEST(ExternalReferenceDecoder) {
- Isolate* isolate = i::Isolate::Current();
- isolate->stats_table()->SetCounterFunction(counter_function);
+ Isolate* isolate = CcTest::i_isolate();
v8::V8::Initialize();
- ExternalReferenceDecoder decoder;
+ ExternalReferenceDecoder decoder(isolate);
CHECK_EQ(AddressOf(Builtins::kArrayCode),
decoder.Decode(make_code(BUILTIN, Builtins::kArrayCode)));
CHECK_EQ(AddressOf(Runtime::kAbort),
decoder.Decode(make_code(v8::internal::RUNTIME_FUNCTION,
Runtime::kAbort)));
- CHECK_EQ(AddressOf(IC_Utility(IC::kLoadCallbackProperty)),
- decoder.Decode(make_code(IC_UTILITY, IC::kLoadCallbackProperty)));
- ExternalReference keyed_load_function =
- ExternalReference(isolate->counters()->keyed_load_function_prototype());
- CHECK_EQ(keyed_load_function.address(),
- decoder.Decode(
- make_code(STATS_COUNTER,
- Counters::k_keyed_load_function_prototype)));
CHECK_EQ(ExternalReference::address_of_stack_limit(isolate).address(),
- decoder.Decode(make_code(UNCLASSIFIED, 4)));
+ decoder.Decode(make_code(UNCLASSIFIED, 2)));
CHECK_EQ(ExternalReference::address_of_real_stack_limit(isolate).address(),
- decoder.Decode(make_code(UNCLASSIFIED, 5)));
-#ifdef ENABLE_DEBUGGER_SUPPORT
+ decoder.Decode(make_code(UNCLASSIFIED, 3)));
CHECK_EQ(ExternalReference::debug_break(isolate).address(),
- decoder.Decode(make_code(UNCLASSIFIED, 16)));
-#endif // ENABLE_DEBUGGER_SUPPORT
+ decoder.Decode(make_code(UNCLASSIFIED, 8)));
CHECK_EQ(ExternalReference::new_space_start(isolate).address(),
- decoder.Decode(make_code(UNCLASSIFIED, 10)));
+ decoder.Decode(make_code(UNCLASSIFIED, 4)));
}
class FileByteSink : public SnapshotByteSink {
public:
explicit FileByteSink(const char* snapshot_file) {
- fp_ = OS::FOpen(snapshot_file, "wb");
+ fp_ = v8::base::OS::FOpen(snapshot_file, "wb");
file_name_ = snapshot_file;
if (fp_ == NULL) {
PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file);
@@ -182,9 +129,9 @@
fclose(fp_);
}
}
- virtual void Put(int byte, const char* description) {
+ virtual void Put(byte b, const char* description) {
if (fp_ != NULL) {
- fputc(byte, fp_);
+ fputc(b, fp_);
}
}
virtual int Position() {
@@ -197,7 +144,7 @@
int code_space_used,
int map_space_used,
int cell_space_used,
- int large_space_used);
+ int property_cell_space_used);
private:
FILE* fp_;
@@ -212,11 +159,11 @@
int code_space_used,
int map_space_used,
int cell_space_used,
- int large_space_used) {
+ int property_cell_space_used) {
int file_name_length = StrLength(file_name_) + 10;
Vector<char> name = Vector<char>::New(file_name_length + 1);
- OS::SNPrintF(name, "%s.size", file_name_);
- FILE* fp = OS::FOpen(name.start(), "w");
+ SNPrintF(name, "%s.size", file_name_);
+ FILE* fp = v8::base::OS::FOpen(name.start(), "w");
name.Dispose();
fprintf(fp, "new %d\n", new_space_used);
fprintf(fp, "pointer %d\n", pointer_space_used);
@@ -224,187 +171,82 @@
fprintf(fp, "code %d\n", code_space_used);
fprintf(fp, "map %d\n", map_space_used);
fprintf(fp, "cell %d\n", cell_space_used);
- fprintf(fp, "large %d\n", large_space_used);
+ fprintf(fp, "property cell %d\n", property_cell_space_used);
fclose(fp);
}
-static bool WriteToFile(const char* snapshot_file) {
+static bool WriteToFile(Isolate* isolate, const char* snapshot_file) {
FileByteSink file(snapshot_file);
- StartupSerializer ser(&file);
+ StartupSerializer ser(isolate, &file);
ser.Serialize();
+
+ file.WriteSpaceUsed(
+ ser.CurrentAllocationAddress(NEW_SPACE),
+ ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
+ ser.CurrentAllocationAddress(OLD_DATA_SPACE),
+ ser.CurrentAllocationAddress(CODE_SPACE),
+ ser.CurrentAllocationAddress(MAP_SPACE),
+ ser.CurrentAllocationAddress(CELL_SPACE),
+ ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+
return true;
}
-static void Serialize() {
+static void Serialize(v8::Isolate* isolate) {
// We have to create one context. One reason for this is so that the builtins
// can be loaded from v8natives.js and their addresses can be processed. This
// will clear the pending fixups array, which would otherwise contain GC roots
// that would confuse the serialization/deserialization process.
- v8::Persistent<v8::Context> env = v8::Context::New();
- env.Dispose();
- WriteToFile(FLAG_testing_serialization_file);
+ v8::Isolate::Scope isolate_scope(isolate);
+ {
+ v8::HandleScope scope(isolate);
+ v8::Context::New(isolate);
+ }
+
+ Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
+ internal_isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "serialize");
+ WriteToFile(internal_isolate, FLAG_testing_serialization_file);
}
// Test that the whole heap can be serialized.
-TEST(Serialize) {
- Serializer::Enable();
- v8::V8::Initialize();
- Serialize();
+UNINITIALIZED_TEST(Serialize) {
+ if (!Snapshot::HaveASnapshotToStartFrom()) {
+ v8::Isolate::CreateParams params;
+ params.enable_serializer = true;
+ v8::Isolate* isolate = v8::Isolate::New(params);
+ Serialize(isolate);
+ }
}
// Test that heap serialization is non-destructive.
-TEST(SerializeTwice) {
- Serializer::Enable();
- v8::V8::Initialize();
- Serialize();
- Serialize();
+UNINITIALIZED_TEST(SerializeTwice) {
+ if (!Snapshot::HaveASnapshotToStartFrom()) {
+ v8::Isolate::CreateParams params;
+ params.enable_serializer = true;
+ v8::Isolate* isolate = v8::Isolate::New(params);
+ Serialize(isolate);
+ Serialize(isolate);
+ }
}
//----------------------------------------------------------------------------
// Tests that the heap can be deserialized.
-static void Deserialize() {
- CHECK(Snapshot::Initialize(FLAG_testing_serialization_file));
-}
-
-static void SanityCheck() {
- v8::HandleScope scope;
-#ifdef DEBUG
- HEAP->Verify();
-#endif
- CHECK(Isolate::Current()->global()->IsJSObject());
- CHECK(Isolate::Current()->global_context()->IsContext());
- CHECK(HEAP->symbol_table()->IsSymbolTable());
- CHECK(!FACTORY->LookupAsciiSymbol("Empty")->IsFailure());
-}
-
-
-DEPENDENT_TEST(Deserialize, Serialize) {
- // The serialize-deserialize tests only work if the VM is built without
- // serialization. That doesn't matter. We don't need to be able to
- // serialize a snapshot in a VM that is booted from a snapshot.
- if (!Snapshot::IsEnabled()) {
- v8::HandleScope scope;
- Deserialize();
-
- v8::Persistent<v8::Context> env = v8::Context::New();
- env->Enter();
-
- SanityCheck();
- }
-}
-
-
-DEPENDENT_TEST(DeserializeFromSecondSerialization, SerializeTwice) {
- if (!Snapshot::IsEnabled()) {
- v8::HandleScope scope;
- Deserialize();
-
- v8::Persistent<v8::Context> env = v8::Context::New();
- env->Enter();
-
- SanityCheck();
- }
-}
-
-
-DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
- if (!Snapshot::IsEnabled()) {
- v8::HandleScope scope;
- Deserialize();
-
- v8::Persistent<v8::Context> env = v8::Context::New();
- env->Enter();
-
- const char* c_source = "\"1234\".length";
- v8::Local<v8::String> source = v8::String::New(c_source);
- v8::Local<v8::Script> script = v8::Script::Compile(source);
- CHECK_EQ(4, script->Run()->Int32Value());
- }
-}
-
-
-DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
- SerializeTwice) {
- if (!Snapshot::IsEnabled()) {
- v8::HandleScope scope;
- Deserialize();
-
- v8::Persistent<v8::Context> env = v8::Context::New();
- env->Enter();
-
- const char* c_source = "\"1234\".length";
- v8::Local<v8::String> source = v8::String::New(c_source);
- v8::Local<v8::Script> script = v8::Script::Compile(source);
- CHECK_EQ(4, script->Run()->Int32Value());
- }
-}
-
-
-TEST(PartialSerialization) {
- Serializer::Enable();
- v8::V8::Initialize();
-
- v8::Persistent<v8::Context> env = v8::Context::New();
- ASSERT(!env.IsEmpty());
- env->Enter();
- // Make sure all builtin scripts are cached.
- { HandleScope scope;
- for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
- Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
- }
- }
- HEAP->CollectAllGarbage(Heap::kNoGCFlags);
- HEAP->CollectAllGarbage(Heap::kNoGCFlags);
-
- Object* raw_foo;
- {
- v8::HandleScope handle_scope;
- v8::Local<v8::String> foo = v8::String::New("foo");
- ASSERT(!foo.IsEmpty());
- raw_foo = *(v8::Utils::OpenHandle(*foo));
- }
-
- int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
- Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
- OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
-
- env->Exit();
- env.Dispose();
-
- FileByteSink startup_sink(startup_name.start());
- startup_name.Dispose();
- StartupSerializer startup_serializer(&startup_sink);
- startup_serializer.SerializeStrongReferences();
-
- FileByteSink partial_sink(FLAG_testing_serialization_file);
- PartialSerializer p_ser(&startup_serializer, &partial_sink);
- p_ser.Serialize(&raw_foo);
- startup_serializer.SerializeWeakReferences();
- partial_sink.WriteSpaceUsed(p_ser.CurrentAllocationAddress(NEW_SPACE),
- p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
- p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
- p_ser.CurrentAllocationAddress(CODE_SPACE),
- p_ser.CurrentAllocationAddress(MAP_SPACE),
- p_ser.CurrentAllocationAddress(CELL_SPACE),
- p_ser.CurrentAllocationAddress(LO_SPACE));
-}
-
-
-static void ReserveSpaceForPartialSnapshot(const char* file_name) {
+static void ReserveSpaceForSnapshot(Deserializer* deserializer,
+ const char* file_name) {
int file_name_length = StrLength(file_name) + 10;
Vector<char> name = Vector<char>::New(file_name_length + 1);
- OS::SNPrintF(name, "%s.size", file_name);
- FILE* fp = OS::FOpen(name.start(), "r");
+ SNPrintF(name, "%s.size", file_name);
+ FILE* fp = v8::base::OS::FOpen(name.start(), "r");
name.Dispose();
- int new_size, pointer_size, data_size, code_size, map_size, cell_size;
- int large_size;
+ int new_size, pointer_size, data_size, code_size, map_size, cell_size,
+ property_cell_size;
#ifdef _MSC_VER
// Avoid warning about unsafe fscanf from MSVC.
// Please note that this is only fine if %c and %s are not being used.
@@ -416,254 +258,385 @@
CHECK_EQ(1, fscanf(fp, "code %d\n", &code_size));
CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size));
CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size));
- CHECK_EQ(1, fscanf(fp, "large %d\n", &large_size));
+ CHECK_EQ(1, fscanf(fp, "property cell %d\n", &property_cell_size));
#ifdef _MSC_VER
#undef fscanf
#endif
fclose(fp);
- HEAP->ReserveSpace(new_size,
- pointer_size,
- data_size,
- code_size,
- map_size,
- cell_size,
- large_size);
+ deserializer->set_reservation(NEW_SPACE, new_size);
+ deserializer->set_reservation(OLD_POINTER_SPACE, pointer_size);
+ deserializer->set_reservation(OLD_DATA_SPACE, data_size);
+ deserializer->set_reservation(CODE_SPACE, code_size);
+ deserializer->set_reservation(MAP_SPACE, map_size);
+ deserializer->set_reservation(CELL_SPACE, cell_size);
+ deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size);
}
-DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
- if (!Snapshot::IsEnabled()) {
+v8::Isolate* InitializeFromFile(const char* snapshot_file) {
+ int len;
+ byte* str = ReadBytes(snapshot_file, &len);
+ if (!str) return NULL;
+ v8::Isolate* v8_isolate = NULL;
+ {
+ SnapshotByteSource source(str, len);
+ Deserializer deserializer(&source);
+ ReserveSpaceForSnapshot(&deserializer, snapshot_file);
+ Isolate* isolate = Isolate::NewForTesting();
+ v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+ v8::Isolate::Scope isolate_scope(v8_isolate);
+ isolate->Init(&deserializer);
+ }
+ DeleteArray(str);
+ return v8_isolate;
+}
+
+
+static v8::Isolate* Deserialize() {
+ v8::Isolate* isolate = InitializeFromFile(FLAG_testing_serialization_file);
+ CHECK(isolate);
+ return isolate;
+}
+
+
+static void SanityCheck(v8::Isolate* v8_isolate) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
+ v8::HandleScope scope(v8_isolate);
+#ifdef VERIFY_HEAP
+ isolate->heap()->Verify();
+#endif
+ CHECK(isolate->global_object()->IsJSObject());
+ CHECK(isolate->native_context()->IsContext());
+ CHECK(isolate->heap()->string_table()->IsStringTable());
+ isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Empty"));
+}
+
+
+UNINITIALIZED_DEPENDENT_TEST(Deserialize, Serialize) {
+ // The serialize-deserialize tests only work if the VM is built without
+ // serialization. That doesn't matter. We don't need to be able to
+ // serialize a snapshot in a VM that is booted from a snapshot.
+ if (!Snapshot::HaveASnapshotToStartFrom()) {
+ v8::Isolate* isolate = Deserialize();
+ {
+ v8::HandleScope handle_scope(isolate);
+ v8::Isolate::Scope isolate_scope(isolate);
+
+ v8::Local<v8::Context> env = v8::Context::New(isolate);
+ env->Enter();
+
+ SanityCheck(isolate);
+ }
+ isolate->Dispose();
+ }
+}
+
+
+UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerialization,
+ SerializeTwice) {
+ if (!Snapshot::HaveASnapshotToStartFrom()) {
+ v8::Isolate* isolate = Deserialize();
+ {
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> env = v8::Context::New(isolate);
+ env->Enter();
+
+ SanityCheck(isolate);
+ }
+ isolate->Dispose();
+ }
+}
+
+
+UNINITIALIZED_DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
+ if (!Snapshot::HaveASnapshotToStartFrom()) {
+ v8::Isolate* isolate = Deserialize();
+ {
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope handle_scope(isolate);
+
+
+ v8::Local<v8::Context> env = v8::Context::New(isolate);
+ env->Enter();
+
+ const char* c_source = "\"1234\".length";
+ v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
+ v8::Local<v8::Script> script = v8::Script::Compile(source);
+ CHECK_EQ(4, script->Run()->Int32Value());
+ }
+ isolate->Dispose();
+ }
+}
+
+
+UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
+ SerializeTwice) {
+ if (!Snapshot::HaveASnapshotToStartFrom()) {
+ v8::Isolate* isolate = Deserialize();
+ {
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> env = v8::Context::New(isolate);
+ env->Enter();
+
+ const char* c_source = "\"1234\".length";
+ v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
+ v8::Local<v8::Script> script = v8::Script::Compile(source);
+ CHECK_EQ(4, script->Run()->Int32Value());
+ }
+ isolate->Dispose();
+ }
+}
+
+
+UNINITIALIZED_TEST(PartialSerialization) {
+ if (!Snapshot::HaveASnapshotToStartFrom()) {
+ v8::Isolate::CreateParams params;
+ params.enable_serializer = true;
+ v8::Isolate* v8_isolate = v8::Isolate::New(params);
+ Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
+ v8_isolate->Enter();
+ {
+ Heap* heap = isolate->heap();
+
+ v8::Persistent<v8::Context> env;
+ {
+ HandleScope scope(isolate);
+ env.Reset(v8_isolate, v8::Context::New(v8_isolate));
+ }
+ DCHECK(!env.IsEmpty());
+ {
+ v8::HandleScope handle_scope(v8_isolate);
+ v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
+ }
+ // Make sure all builtin scripts are cached.
+ {
+ HandleScope scope(isolate);
+ for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
+ isolate->bootstrapper()->NativesSourceLookup(i);
+ }
+ }
+ heap->CollectAllGarbage(Heap::kNoGCFlags);
+ heap->CollectAllGarbage(Heap::kNoGCFlags);
+
+ Object* raw_foo;
+ {
+ v8::HandleScope handle_scope(v8_isolate);
+ v8::Local<v8::String> foo = v8::String::NewFromUtf8(v8_isolate, "foo");
+ DCHECK(!foo.IsEmpty());
+ raw_foo = *(v8::Utils::OpenHandle(*foo));
+ }
+
+ int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
+ Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
+ SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+
+ {
+ v8::HandleScope handle_scope(v8_isolate);
+ v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
+ }
+ env.Reset();
+
+ FileByteSink startup_sink(startup_name.start());
+ StartupSerializer startup_serializer(isolate, &startup_sink);
+ startup_serializer.SerializeStrongReferences();
+
+ FileByteSink partial_sink(FLAG_testing_serialization_file);
+ PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
+ p_ser.Serialize(&raw_foo);
+ startup_serializer.SerializeWeakReferences();
+
+ partial_sink.WriteSpaceUsed(
+ p_ser.CurrentAllocationAddress(NEW_SPACE),
+ p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
+ p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
+ p_ser.CurrentAllocationAddress(CODE_SPACE),
+ p_ser.CurrentAllocationAddress(MAP_SPACE),
+ p_ser.CurrentAllocationAddress(CELL_SPACE),
+ p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+
+ startup_sink.WriteSpaceUsed(
+ startup_serializer.CurrentAllocationAddress(NEW_SPACE),
+ startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
+ startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
+ startup_serializer.CurrentAllocationAddress(CODE_SPACE),
+ startup_serializer.CurrentAllocationAddress(MAP_SPACE),
+ startup_serializer.CurrentAllocationAddress(CELL_SPACE),
+ startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+ startup_name.Dispose();
+ }
+ v8_isolate->Exit();
+ v8_isolate->Dispose();
+ }
+}
+
+
+UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
+ if (!Snapshot::HaveASnapshotToStartFrom()) {
int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
- OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+ SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
- CHECK(Snapshot::Initialize(startup_name.start()));
+ v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
+ CHECK(v8_isolate);
startup_name.Dispose();
-
- const char* file_name = FLAG_testing_serialization_file;
- ReserveSpaceForPartialSnapshot(file_name);
-
- int snapshot_size = 0;
- byte* snapshot = ReadBytes(file_name, &snapshot_size);
-
- Object* root;
{
- SnapshotByteSource source(snapshot, snapshot_size);
- Deserializer deserializer(&source);
- deserializer.DeserializePartial(&root);
- CHECK(root->IsString());
- }
- v8::HandleScope handle_scope;
- Handle<Object> root_handle(root);
+ v8::Isolate::Scope isolate_scope(v8_isolate);
- ReserveSpaceForPartialSnapshot(file_name);
+ const char* file_name = FLAG_testing_serialization_file;
- Object* root2;
- {
- SnapshotByteSource source(snapshot, snapshot_size);
- Deserializer deserializer(&source);
- deserializer.DeserializePartial(&root2);
- CHECK(root2->IsString());
- CHECK(*root_handle == root2);
+ int snapshot_size = 0;
+ byte* snapshot = ReadBytes(file_name, &snapshot_size);
+
+ Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
+ Object* root;
+ {
+ SnapshotByteSource source(snapshot, snapshot_size);
+ Deserializer deserializer(&source);
+ ReserveSpaceForSnapshot(&deserializer, file_name);
+ deserializer.DeserializePartial(isolate, &root);
+ CHECK(root->IsString());
+ }
+ HandleScope handle_scope(isolate);
+ Handle<Object> root_handle(root, isolate);
+
+
+ Object* root2;
+ {
+ SnapshotByteSource source(snapshot, snapshot_size);
+ Deserializer deserializer(&source);
+ ReserveSpaceForSnapshot(&deserializer, file_name);
+ deserializer.DeserializePartial(isolate, &root2);
+ CHECK(root2->IsString());
+ CHECK(*root_handle == root2);
+ }
}
+ v8_isolate->Dispose();
}
}
-TEST(ContextSerialization) {
- Serializer::Enable();
- v8::V8::Initialize();
+UNINITIALIZED_TEST(ContextSerialization) {
+ if (!Snapshot::HaveASnapshotToStartFrom()) {
+ v8::Isolate::CreateParams params;
+ params.enable_serializer = true;
+ v8::Isolate* v8_isolate = v8::Isolate::New(params);
+ Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
+ Heap* heap = isolate->heap();
+ {
+ v8::Isolate::Scope isolate_scope(v8_isolate);
- v8::Persistent<v8::Context> env = v8::Context::New();
- ASSERT(!env.IsEmpty());
- env->Enter();
- // Make sure all builtin scripts are cached.
- { HandleScope scope;
- for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
- Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
+ v8::Persistent<v8::Context> env;
+ {
+ HandleScope scope(isolate);
+ env.Reset(v8_isolate, v8::Context::New(v8_isolate));
+ }
+ DCHECK(!env.IsEmpty());
+ {
+ v8::HandleScope handle_scope(v8_isolate);
+ v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
+ }
+ // Make sure all builtin scripts are cached.
+ {
+ HandleScope scope(isolate);
+ for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
+ isolate->bootstrapper()->NativesSourceLookup(i);
+ }
+ }
+ // If we don't do this then we end up with a stray root pointing at the
+ // context even after we have disposed of env.
+ heap->CollectAllGarbage(Heap::kNoGCFlags);
+
+ int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
+ Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
+ SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+
+ {
+ v8::HandleScope handle_scope(v8_isolate);
+ v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
+ }
+
+ i::Object* raw_context = *v8::Utils::OpenPersistent(env);
+
+ env.Reset();
+
+ FileByteSink startup_sink(startup_name.start());
+ StartupSerializer startup_serializer(isolate, &startup_sink);
+ startup_serializer.SerializeStrongReferences();
+
+ FileByteSink partial_sink(FLAG_testing_serialization_file);
+ PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
+ p_ser.Serialize(&raw_context);
+ startup_serializer.SerializeWeakReferences();
+
+ partial_sink.WriteSpaceUsed(
+ p_ser.CurrentAllocationAddress(NEW_SPACE),
+ p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
+ p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
+ p_ser.CurrentAllocationAddress(CODE_SPACE),
+ p_ser.CurrentAllocationAddress(MAP_SPACE),
+ p_ser.CurrentAllocationAddress(CELL_SPACE),
+ p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+
+ startup_sink.WriteSpaceUsed(
+ startup_serializer.CurrentAllocationAddress(NEW_SPACE),
+ startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
+ startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
+ startup_serializer.CurrentAllocationAddress(CODE_SPACE),
+ startup_serializer.CurrentAllocationAddress(MAP_SPACE),
+ startup_serializer.CurrentAllocationAddress(CELL_SPACE),
+ startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+ startup_name.Dispose();
}
+ v8_isolate->Dispose();
}
- // If we don't do this then we end up with a stray root pointing at the
- // context even after we have disposed of env.
- HEAP->CollectAllGarbage(Heap::kNoGCFlags);
-
- int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
- Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
- OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
-
- env->Exit();
-
- Object* raw_context = *(v8::Utils::OpenHandle(*env));
-
- env.Dispose();
-
- FileByteSink startup_sink(startup_name.start());
- startup_name.Dispose();
- StartupSerializer startup_serializer(&startup_sink);
- startup_serializer.SerializeStrongReferences();
-
- FileByteSink partial_sink(FLAG_testing_serialization_file);
- PartialSerializer p_ser(&startup_serializer, &partial_sink);
- p_ser.Serialize(&raw_context);
- startup_serializer.SerializeWeakReferences();
- partial_sink.WriteSpaceUsed(p_ser.CurrentAllocationAddress(NEW_SPACE),
- p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
- p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
- p_ser.CurrentAllocationAddress(CODE_SPACE),
- p_ser.CurrentAllocationAddress(MAP_SPACE),
- p_ser.CurrentAllocationAddress(CELL_SPACE),
- p_ser.CurrentAllocationAddress(LO_SPACE));
}
-DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
- if (!Snapshot::IsEnabled()) {
+UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
+ if (!Snapshot::HaveASnapshotToStartFrom()) {
int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
- OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+ SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
- CHECK(Snapshot::Initialize(startup_name.start()));
+ v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
+ CHECK(v8_isolate);
startup_name.Dispose();
-
- const char* file_name = FLAG_testing_serialization_file;
- ReserveSpaceForPartialSnapshot(file_name);
-
- int snapshot_size = 0;
- byte* snapshot = ReadBytes(file_name, &snapshot_size);
-
- Object* root;
{
- SnapshotByteSource source(snapshot, snapshot_size);
- Deserializer deserializer(&source);
- deserializer.DeserializePartial(&root);
- CHECK(root->IsContext());
- }
- v8::HandleScope handle_scope;
- Handle<Object> root_handle(root);
+ v8::Isolate::Scope isolate_scope(v8_isolate);
- ReserveSpaceForPartialSnapshot(file_name);
+ const char* file_name = FLAG_testing_serialization_file;
- Object* root2;
- {
- SnapshotByteSource source(snapshot, snapshot_size);
- Deserializer deserializer(&source);
- deserializer.DeserializePartial(&root2);
- CHECK(root2->IsContext());
- CHECK(*root_handle != root2);
- }
- }
-}
+ int snapshot_size = 0;
+ byte* snapshot = ReadBytes(file_name, &snapshot_size);
-
-TEST(LinearAllocation) {
- v8::V8::Initialize();
- int new_space_max = 512 * KB;
- int paged_space_max = Page::kMaxNonCodeHeapObjectSize;
- int code_space_max = HEAP->code_space()->AreaSize();
-
- for (int size = 1000; size < 5 * MB; size += size >> 1) {
- size &= ~8; // Round.
- int new_space_size = (size < new_space_max) ? size : new_space_max;
- int paged_space_size = (size < paged_space_max) ? size : paged_space_max;
- HEAP->ReserveSpace(
- new_space_size,
- paged_space_size, // Old pointer space.
- paged_space_size, // Old data space.
- HEAP->code_space()->RoundSizeDownToObjectAlignment(code_space_max),
- HEAP->map_space()->RoundSizeDownToObjectAlignment(paged_space_size),
- HEAP->cell_space()->RoundSizeDownToObjectAlignment(paged_space_size),
- size); // Large object space.
- LinearAllocationScope linear_allocation_scope;
- const int kSmallFixedArrayLength = 4;
- const int kSmallFixedArraySize =
- FixedArray::kHeaderSize + kSmallFixedArrayLength * kPointerSize;
- const int kSmallStringLength = 16;
- const int kSmallStringSize =
- (SeqAsciiString::kHeaderSize + kSmallStringLength +
- kObjectAlignmentMask) & ~kObjectAlignmentMask;
- const int kMapSize = Map::kSize;
-
- Object* new_last = NULL;
- for (int i = 0;
- i + kSmallFixedArraySize <= new_space_size;
- i += kSmallFixedArraySize) {
- Object* obj =
- HEAP->AllocateFixedArray(kSmallFixedArrayLength)->ToObjectChecked();
- if (new_last != NULL) {
- CHECK(reinterpret_cast<char*>(obj) ==
- reinterpret_cast<char*>(new_last) + kSmallFixedArraySize);
+ Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
+ Object* root;
+ {
+ SnapshotByteSource source(snapshot, snapshot_size);
+ Deserializer deserializer(&source);
+ ReserveSpaceForSnapshot(&deserializer, file_name);
+ deserializer.DeserializePartial(isolate, &root);
+ CHECK(root->IsContext());
}
- new_last = obj;
- }
+ HandleScope handle_scope(isolate);
+ Handle<Object> root_handle(root, isolate);
- Object* pointer_last = NULL;
- for (int i = 0;
- i + kSmallFixedArraySize <= paged_space_size;
- i += kSmallFixedArraySize) {
- Object* obj = HEAP->AllocateFixedArray(kSmallFixedArrayLength,
- TENURED)->ToObjectChecked();
- int old_page_fullness = i % Page::kPageSize;
- int page_fullness = (i + kSmallFixedArraySize) % Page::kPageSize;
- if (page_fullness < old_page_fullness ||
- page_fullness > HEAP->old_pointer_space()->AreaSize()) {
- i = RoundUp(i, Page::kPageSize);
- pointer_last = NULL;
- }
- if (pointer_last != NULL) {
- CHECK(reinterpret_cast<char*>(obj) ==
- reinterpret_cast<char*>(pointer_last) + kSmallFixedArraySize);
- }
- pointer_last = obj;
- }
- Object* data_last = NULL;
- for (int i = 0;
- i + kSmallStringSize <= paged_space_size;
- i += kSmallStringSize) {
- Object* obj = HEAP->AllocateRawAsciiString(kSmallStringLength,
- TENURED)->ToObjectChecked();
- int old_page_fullness = i % Page::kPageSize;
- int page_fullness = (i + kSmallStringSize) % Page::kPageSize;
- if (page_fullness < old_page_fullness ||
- page_fullness > HEAP->old_data_space()->AreaSize()) {
- i = RoundUp(i, Page::kPageSize);
- data_last = NULL;
+ Object* root2;
+ {
+ SnapshotByteSource source(snapshot, snapshot_size);
+ Deserializer deserializer(&source);
+ ReserveSpaceForSnapshot(&deserializer, file_name);
+ deserializer.DeserializePartial(isolate, &root2);
+ CHECK(root2->IsContext());
+ CHECK(*root_handle != root2);
}
- if (data_last != NULL) {
- CHECK(reinterpret_cast<char*>(obj) ==
- reinterpret_cast<char*>(data_last) + kSmallStringSize);
- }
- data_last = obj;
}
-
- Object* map_last = NULL;
- for (int i = 0; i + kMapSize <= paged_space_size; i += kMapSize) {
- Object* obj = HEAP->AllocateMap(JS_OBJECT_TYPE,
- 42 * kPointerSize)->ToObjectChecked();
- int old_page_fullness = i % Page::kPageSize;
- int page_fullness = (i + kMapSize) % Page::kPageSize;
- if (page_fullness < old_page_fullness ||
- page_fullness > HEAP->map_space()->AreaSize()) {
- i = RoundUp(i, Page::kPageSize);
- map_last = NULL;
- }
- if (map_last != NULL) {
- CHECK(reinterpret_cast<char*>(obj) ==
- reinterpret_cast<char*>(map_last) + kMapSize);
- }
- map_last = obj;
- }
-
- if (size > Page::kMaxNonCodeHeapObjectSize) {
- // Support for reserving space in large object space is not there yet,
- // but using an always-allocate scope is fine for now.
- AlwaysAllocateScope always;
- int large_object_array_length =
- (size - FixedArray::kHeaderSize) / kPointerSize;
- Object* obj = HEAP->AllocateFixedArray(large_object_array_length,
- TENURED)->ToObjectChecked();
- CHECK(!obj->IsFailure());
- }
+ v8_isolate->Dispose();
}
}
@@ -682,3 +655,185 @@
bool ArtificialFailure2 = false;
CHECK(ArtificialFailure2);
}
+
+
+int CountBuiltins() {
+ // Check that we have not deserialized any additional builtin.
+ HeapIterator iterator(CcTest::heap());
+ DisallowHeapAllocation no_allocation;
+ int counter = 0;
+ for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
+ if (obj->IsCode() && Code::cast(obj)->kind() == Code::BUILTIN) counter++;
+ }
+ return counter;
+}
+
+
+TEST(SerializeToplevelOnePlusOne) {
+ 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());
+
+ const char* source = "1 + 1";
+
+ Handle<String> orig_source = isolate->factory()
+ ->NewStringFromUtf8(CStrVector(source))
+ .ToHandleChecked();
+ Handle<String> copy_source = isolate->factory()
+ ->NewStringFromUtf8(CStrVector(source))
+ .ToHandleChecked();
+ CHECK(!orig_source.is_identical_to(copy_source));
+ CHECK(orig_source->Equals(*copy_source));
+
+ ScriptData* cache = NULL;
+
+ Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+ orig_source, Handle<String>(), 0, 0, false,
+ Handle<Context>(isolate->native_context()), NULL, &cache,
+ v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+ int builtins_count = CountBuiltins();
+
+ Handle<SharedFunctionInfo> copy;
+ {
+ DisallowCompilation no_compile_expected(isolate);
+ copy = Compiler::CompileScript(
+ copy_source, Handle<String>(), 0, 0, false,
+ Handle<Context>(isolate->native_context()), NULL, &cache,
+ v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+ }
+
+ CHECK_NE(*orig, *copy);
+ CHECK(Script::cast(copy->script())->source() == *copy_source);
+
+ Handle<JSFunction> copy_fun =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(
+ 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;
+ Isolate* isolate = CcTest::i_isolate();
+ isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
+
+ v8::HandleScope scope(CcTest::isolate());
+
+ const char* source = "'string1'";
+
+ Handle<String> orig_source = isolate->factory()
+ ->NewStringFromUtf8(CStrVector(source))
+ .ToHandleChecked();
+ Handle<String> copy_source = isolate->factory()
+ ->NewStringFromUtf8(CStrVector(source))
+ .ToHandleChecked();
+ CHECK(!orig_source.is_identical_to(copy_source));
+ CHECK(orig_source->Equals(*copy_source));
+
+ Handle<JSObject> global(isolate->context()->global_object());
+ ScriptData* cache = NULL;
+
+ Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+ orig_source, Handle<String>(), 0, 0, false,
+ Handle<Context>(isolate->native_context()), NULL, &cache,
+ v8::ScriptCompiler::kProduceCodeCache, 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;
+ {
+ DisallowCompilation no_compile_expected(isolate);
+ copy = Compiler::CompileScript(
+ copy_source, Handle<String>(), 0, 0, false,
+ Handle<Context>(isolate->native_context()), NULL, &cache,
+ v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+ }
+ CHECK_NE(*orig, *copy);
+ CHECK(Script::cast(copy->script())->source() == *copy_source);
+
+ 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;
+}
+
+
+TEST(SerializeToplevelIsolates) {
+ FLAG_serialize_toplevel = true;
+
+ const char* source = "function f() { return 'abc'; }; f() + 'def'";
+ v8::ScriptCompiler::CachedData* cache;
+
+ v8::Isolate* isolate1 = v8::Isolate::New();
+ {
+ v8::Isolate::Scope iscope(isolate1);
+ v8::HandleScope scope(isolate1);
+ v8::Local<v8::Context> context = v8::Context::New(isolate1);
+ 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(
+ isolate1, &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")));
+ }
+ isolate1->Dispose();
+
+ v8::Isolate* isolate2 = v8::Isolate::New();
+ {
+ v8::Isolate::Scope iscope(isolate2);
+ v8::HandleScope scope(isolate2);
+ v8::Local<v8::Context> context = v8::Context::New(isolate2);
+ 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*>(isolate2));
+ script = v8::ScriptCompiler::CompileUnbound(
+ isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
+ }
+ v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+ CHECK(result->ToString()->Equals(v8_str("abcdef")));
+ }
+ isolate2->Dispose();
+}