diff --git a/patches/backport.R00000.patch b/patches/backport.R00000.patch new file mode 100644 index 0000000..2609434 --- /dev/null +++ b/patches/backport.R00000.patch @@ -0,0 +1,211 @@ +commit b324d0bb99045fcfe80397a978eb2ce29af4990f +Author: igorklopov +Date: Mon Aug 17 11:31:50 2015 +0400 + + U2 + +diff --git a/src/code-stubs.cc b/src/code-stubs.cc +index 0e68ab8..92aca16 100644 +--- node/deps/v8/src/code-stubs.cc ++++ node/deps/v8/src/code-stubs.cc +@@ -252,6 +252,172 @@ void CodeStub::PrintName(OStream& os) const { // NOLINT + } + + ++void CheckCodeStub(CodeStub* pstub, CodeStub::Major MajorKey, int MinorKey) { ++ if (pstub->MajorKey() != MajorKey) fprintf(stderr, "MajorKey %d != %d in %s\n", pstub->MajorKey(), MajorKey, pstub->MajorName(MajorKey, false)); ++ if (pstub->MinorKey() != MinorKey) fprintf(stderr, "MinorKey %d != %d in %s\n", pstub->MinorKey(), MinorKey, pstub->MajorName(MajorKey, false)); ++ // if (pstub->MajorKey() == MajorKey) fprintf(stderr, "correct MajorKey in %s\n", pstub->MajorName(MajorKey, false)); ++ // if (pstub->MinorKey() == MinorKey) fprintf(stderr, "correct MinorKey in %s\n", pstub->MajorName(MajorKey, false)); ++} ++ ++ ++void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out, ++ DispatchedCall call) { ++ CodeStub::Major MajorKey = MajorKeyFromKey(key); ++ int MinorKey = MinorKeyFromKey(key); ++ switch (MajorKey) { ++ case CEntry: { ++ // int result = (save_doubles_ == kSaveFPRegs) ? 1 : 0; ++ int result_size = (MinorKey & 0x02) ? 2 : 1; ++ // return result | ((result_size_ == 1) ? 0 : 2); ++ SaveFPRegsMode save_doubles = (MinorKey & 0x01) ? kSaveFPRegs : kDontSaveFPRegs; ++ CEntryStub stub(isolate, result_size, save_doubles); ++ CodeStub* pstub = &stub; ++ CheckCodeStub(pstub, MajorKey, MinorKey); ++ call(pstub, value_out); ++ break; ++ } ++ case CallConstruct: { ++ // int MinorKey() const { return flags_; } ++ CallConstructorFlags flags = (CallConstructorFlags) MinorKey; ++ CallConstructStub stub(isolate, flags); ++ CodeStub* pstub = &stub; ++ CheckCodeStub(pstub, MajorKey, MinorKey); ++ call(pstub, value_out); ++ break; ++ } ++ case FastNewContext: { ++ // int NotMissMinorKey() const V8_OVERRIDE { return slots_; } ++ int slots = MinorKey; ++ FastNewContextStub stub(isolate, slots); ++ CodeStub* pstub = &stub; ++ CheckCodeStub(pstub, MajorKey, MinorKey); ++ call(pstub, value_out); ++ break; ++ } ++ case FastNewClosure: { ++ // class StrictModeBits: public BitField {}; ++ StrictMode strict_mode = (StrictMode) (MinorKey & 0x01); ++ // class IsGeneratorBits: public BitField {}; ++ bool is_generator = MinorKey & 0x02; ++ FastNewClosureStub stub(isolate, strict_mode, is_generator); ++ CodeStub* pstub = &stub; ++ CheckCodeStub(pstub, MajorKey, MinorKey); ++ call(pstub, value_out); ++ break; ++ } ++ case RecordWrite: { ++ #if V8_TARGET_ARCH_IA32 ++ // class ObjectBits: public BitField {}; ++ Register object = Register::from_code(MinorKey & 0x07); ++ // class ValueBits: public BitField {}; ++ Register value = Register::from_code((MinorKey >> 3) & 0x07); ++ // class AddressBits: public BitField {}; ++ Register address = Register::from_code((MinorKey >> 6) & 0x07); ++ // class RememberedSetActionBits: public BitField {}; ++ RememberedSetAction remembered_set_action = (RememberedSetAction) ((MinorKey >> 9) & 0x01); ++ // class SaveFPRegsModeBits: public BitField {}; ++ SaveFPRegsMode fp_mode = (SaveFPRegsMode) ((MinorKey >> 10) & 0x01); ++ RecordWriteStub stub(isolate, object, value, address, remembered_set_action, fp_mode); ++ #endif ++ #if V8_TARGET_ARCH_X64 ++ // class ObjectBits: public BitField {}; ++ Register object = Register::from_code(MinorKey & 0x0F); ++ // class ValueBits: public BitField {}; ++ Register value = Register::from_code((MinorKey >> 4) & 0x0F); ++ // class AddressBits: public BitField {}; ++ Register address = Register::from_code((MinorKey >> 8) & 0x0F); ++ // class RememberedSetActionBits: public BitField {}; ++ RememberedSetAction remembered_set_action = (RememberedSetAction) ((MinorKey >> 12) & 0x01); ++ // class SaveFPRegsModeBits: public BitField {}; ++ SaveFPRegsMode fp_mode = (SaveFPRegsMode) ((MinorKey >> 13) & 0x01); ++ RecordWriteStub stub(isolate, object, value, address, remembered_set_action, fp_mode); ++ #endif ++ CodeStub* pstub = &stub; ++ CheckCodeStub(pstub, MajorKey, MinorKey); ++ call(pstub, value_out); ++ break; ++ } ++ case ToNumber: { ++ ToNumberStub stub(isolate); ++ CodeStub* pstub = &stub; ++ CheckCodeStub(pstub, MajorKey, MinorKey); ++ call(pstub, value_out); ++ break; ++ } ++ case ArgumentsAccess: { ++ // int MinorKey() const { return type_; } ++ ArgumentsAccessStub::Type type = (ArgumentsAccessStub::Type) MinorKey; ++ ArgumentsAccessStub stub(isolate, type); ++ CodeStub* pstub = &stub; ++ CheckCodeStub(pstub, MajorKey, MinorKey); ++ call(pstub, value_out); ++ break; ++ } ++ case FastCloneShallowArray: { ++ // class AllocationSiteModeBits: public BitField {}; ++ AllocationSiteMode allocation_site_mode = (AllocationSiteMode) (MinorKey & 0x01); ++ FastCloneShallowArrayStub stub(isolate, allocation_site_mode); ++ CodeStub* pstub = &stub; ++ CheckCodeStub(pstub, MajorKey, MinorKey); ++ call(pstub, value_out); ++ break; ++ } ++ case StoreArrayLiteralElement: { ++ StoreArrayLiteralElementStub stub(isolate); ++ CodeStub* pstub = &stub; ++ CheckCodeStub(pstub, MajorKey, MinorKey); ++ call(pstub, value_out); ++ break; ++ } ++ case CallFunction: { ++ // class FlagBits: public BitField {}; ++ CallFunctionFlags flags = (CallFunctionFlags) (MinorKey & 0x03); ++ // class ArgcBits : public BitField {}; ++ unsigned argc = MinorKey >> 2; ++ CallFunctionStub stub(isolate, argc, flags); ++ CodeStub* pstub = &stub; ++ CheckCodeStub(pstub, MajorKey, MinorKey); ++ call(pstub, value_out); ++ break; ++ } ++ case Instanceof: { ++ // int MinorKey() const { return static_cast(flags_); } ++ InstanceofStub::Flags flags = (InstanceofStub::Flags) MinorKey; ++ InstanceofStub stub(isolate, flags); ++ CodeStub* pstub = &stub; ++ CheckCodeStub(pstub, MajorKey, MinorKey); ++ call(pstub, value_out); ++ break; ++ } ++ case NUMBER_OF_IDS: ++ UNREACHABLE(); ++ case NoCache: ++ *value_out = NULL; ++ break; ++ default: { ++ fprintf(stderr, "unhandled MajorKey: %s (%d)\n", MajorName(MajorKey, false), MajorKey); ++ UNREACHABLE(); ++ } ++ } ++} ++ ++ ++void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) { ++ Handle* code_out = reinterpret_cast*>(value_out); ++ // Code stubs with special cache cannot be recreated from stub key. ++ *code_out = stub->UseSpecialCache() ? Handle() : stub->GetCode(); ++} ++ ++ ++MaybeHandle CodeStub::GetCode(Isolate* isolate, uint32_t key) { ++ HandleScope scope(isolate); ++ Handle code; ++ void** value_out = reinterpret_cast(&code); ++ Dispatch(isolate, key, value_out, &GetCodeDispatchCall); ++ return scope.CloseAndEscape(code); ++} ++ ++ + // static + void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) { + // Generate the uninitialized versions of the stub. +diff --git a/src/code-stubs.h b/src/code-stubs.h +index c1d051b..9cc12df 100644 +--- node/deps/v8/src/code-stubs.h ++++ node/deps/v8/src/code-stubs.h +@@ -179,6 +179,8 @@ class CodeStub BASE_EMBEDDED { + // Lookup the code in the (possibly custom) cache. + bool FindCodeInCache(Code** code_out); + ++ static MaybeHandle GetCode(Isolate* isolate, uint32_t key); ++ + // Returns information for computing the number key. + virtual Major MajorKey() const = 0; + virtual int MinorKey() const = 0; +@@ -242,6 +244,14 @@ class CodeStub BASE_EMBEDDED { + // If a stub uses a special cache override this. + virtual bool UseSpecialCache() { return false; } + ++ // We use this dispatch to statically instantiate the correct code stub for ++ // the given stub key and call the passed function with that code stub. ++ typedef void (*DispatchedCall)(CodeStub* stub, void** value_out); ++ static void Dispatch(Isolate* isolate, uint32_t key, void** value_out, ++ DispatchedCall call); ++ ++ static void GetCodeDispatchCall(CodeStub* stub, void** value_out); ++ + STATIC_ASSERT(NUMBER_OF_IDS < (1 << kStubMajorKeyBits)); + class MajorKeyBits: public BitField {}; + class MinorKeyBits: public BitField +Date: Wed Sep 17 12:50:17 2014 +0000 + + Serialize code stubs using stub key. + + Also add some tracing to the code serializer. + + R=mvstanton@chromium.org + + Review URL: https://codereview.chromium.org/556243005 + + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24002 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/flag-definitions.h b/src/flag-definitions.h +index 4208e62..792fda9 100644 +--- node/deps/v8/src/flag-definitions.h ++++ node/deps/v8/src/flag-definitions.h +@@ -428,6 +428,7 @@ DEFINE_BOOL(trace_stub_failures, false, + "trace deoptimization of generated code stubs") + + DEFINE_BOOL(serialize_toplevel, false, "enable caching of toplevel scripts") ++DEFINE_BOOL(trace_code_serializer, false, "trace code serializer") + + // compiler.cc + DEFINE_INT(min_preparse_length, 1024, +diff --git a/src/serialize.cc b/src/serialize.cc +index 1a19ab0..9447fc8 100644 +--- node/deps/v8/src/serialize.cc ++++ node/deps/v8/src/serialize.cc +@@ -8,6 +8,7 @@ + #include "src/api.h" + #include "src/base/platform/platform.h" + #include "src/bootstrapper.h" ++#include "src/code-stubs.h" + #include "src/deoptimizer.h" + #include "src/execution.h" + #include "src/global-handles.h" +@@ -872,7 +873,7 @@ void Deserializer::ReadChunk(Object** current, + } else if (where == kAttachedReference) { \ + DCHECK(deserializing_user_code()); \ + int index = source_->GetInt(); \ +- new_object = attached_objects_->at(index); \ ++ new_object = *attached_objects_->at(index); \ + emit_write_barrier = isolate->heap()->InNewSpace(new_object); \ + } else { \ + DCHECK(where == kBackrefWithSkip); \ +@@ -1125,6 +1126,10 @@ void Deserializer::ReadChunk(Object** current, + // the current object. + CASE_STATEMENT(kAttachedReference, kPlain, kStartOfObject, 0) + CASE_BODY(kAttachedReference, kPlain, kStartOfObject, 0) ++ CASE_STATEMENT(kAttachedReference, kPlain, kInnerPointer, 0) ++ CASE_BODY(kAttachedReference, kPlain, kInnerPointer, 0) ++ CASE_STATEMENT(kAttachedReference, kFromCode, kInnerPointer, 0) ++ CASE_BODY(kAttachedReference, kFromCode, kInnerPointer, 0) + + #undef CASE_STATEMENT + #undef CASE_BODY +@@ -1311,12 +1316,12 @@ int Serializer::RootIndex(HeapObject* heap_object, HowToCode from) { + // location into a later object. We can encode the location as an offset from + // the start of the deserialized objects or as an offset backwards from the + // current allocation pointer. +-void Serializer::SerializeReferenceToPreviousObject( +- int space, +- int address, +- HowToCode how_to_code, +- WhereToPoint where_to_point, +- int skip) { ++void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object, ++ HowToCode how_to_code, ++ WhereToPoint where_to_point, ++ int skip) { ++ int space = SpaceOfObject(heap_object); ++ int address = address_mapper_.MappedTo(heap_object); + int offset = CurrentAllocationAddress(space) - address; + // Shift out the bits that are always 0. + offset >>= kObjectAlignmentBits; +@@ -1347,12 +1352,7 @@ void StartupSerializer::SerializeObject( + } + + if (address_mapper_.IsMapped(heap_object)) { +- int space = SpaceOfObject(heap_object); +- int address = address_mapper_.MappedTo(heap_object); +- SerializeReferenceToPreviousObject(space, +- address, +- how_to_code, +- where_to_point, ++ SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point, + skip); + } else { + if (skip != 0) { +@@ -1455,12 +1455,7 @@ void PartialSerializer::SerializeObject( + DCHECK(!heap_object->IsInternalizedString()); + + if (address_mapper_.IsMapped(heap_object)) { +- int space = SpaceOfObject(heap_object); +- int address = address_mapper_.MappedTo(heap_object); +- SerializeReferenceToPreviousObject(space, +- address, +- how_to_code, +- where_to_point, ++ SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point, + skip); + } else { + if (skip != 0) { +@@ -1782,17 +1777,32 @@ void Serializer::InitializeCodeAddressMap() { + ScriptData* CodeSerializer::Serialize(Isolate* isolate, + Handle info, + Handle source) { ++ base::ElapsedTimer timer; ++ if (FLAG_profile_deserialization) timer.Start(); ++ + // Serialize code object. + List payload; + ListSnapshotSink list_sink(&payload); +- CodeSerializer cs(isolate, &list_sink, *source); ++ DebugSnapshotSink debug_sink(&list_sink); ++ SnapshotByteSink* sink = FLAG_trace_code_serializer ++ ? static_cast(&debug_sink) ++ : static_cast(&list_sink); ++ CodeSerializer cs(isolate, sink, *source); + DisallowHeapAllocation no_gc; + Object** location = Handle::cast(info).location(); + cs.VisitPointer(location); + cs.Pad(); + + SerializedCodeData data(&payload, &cs); +- return data.GetScriptData(); ++ ScriptData* script_data = data.GetScriptData(); ++ ++ if (FLAG_profile_deserialization) { ++ double ms = timer.Elapsed().InMillisecondsF(); ++ int length = script_data->length(); ++ PrintF("[Serializing to %d bytes took %0.3f ms]\n", length, ms); ++ } ++ ++ return script_data; + } + + +@@ -1813,16 +1823,13 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, + return; + } + +- // TODO(yangguo) wire up stubs from stub cache. + // TODO(yangguo) wire up global object. + // TODO(yangguo) We cannot deal with different hash seeds yet. + DCHECK(!heap_object->IsHashTable()); + + if (address_mapper_.IsMapped(heap_object)) { +- int space = SpaceOfObject(heap_object); +- int address = address_mapper_.MappedTo(heap_object); +- SerializeReferenceToPreviousObject(space, address, how_to_code, +- where_to_point, skip); ++ SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point, ++ skip); + return; + } + +@@ -1832,7 +1839,11 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, + SerializeBuiltin(code_object, how_to_code, where_to_point, skip); + return; + } +- // TODO(yangguo) figure out whether other code kinds can be handled smarter. ++ if (code_object->IsCodeStubOrIC()) { ++ SerializeCodeStub(code_object, how_to_code, where_to_point, skip); ++ return; ++ } ++ code_object->ClearInlineCaches(); + } + + if (heap_object == source_) { +@@ -1840,6 +1851,14 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, + return; + } + ++ SerializeHeapObject(heap_object, how_to_code, where_to_point, skip); ++} ++ ++ ++void CodeSerializer::SerializeHeapObject(HeapObject* heap_object, ++ HowToCode how_to_code, ++ WhereToPoint where_to_point, ++ int skip) { + if (heap_object->IsScript()) { + // The wrapper cache uses a Foreign object to point to a global handle. + // However, the object visitor expects foreign objects to point to external +@@ -1851,6 +1870,13 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, + sink_->Put(kSkip, "SkipFromSerializeObject"); + sink_->PutInt(skip, "SkipDistanceFromSerializeObject"); + } ++ ++ if (FLAG_trace_code_serializer) { ++ PrintF("Encoding heap object: "); ++ heap_object->ShortPrint(); ++ PrintF("\n"); ++ } ++ + // Object has not yet been serialized. Serialize it here. + ObjectSerializer serializer(this, heap_object, sink_, how_to_code, + where_to_point); +@@ -1870,11 +1896,62 @@ void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code, + int builtin_index = builtin->builtin_index(); + DCHECK_LT(builtin_index, Builtins::builtin_count); + DCHECK_LE(0, builtin_index); ++ ++ if (FLAG_trace_code_serializer) { ++ PrintF("Encoding builtin: %s\n", ++ isolate()->builtins()->name(builtin_index)); ++ } ++ + sink_->Put(kBuiltin + how_to_code + where_to_point, "Builtin"); + sink_->PutInt(builtin_index, "builtin_index"); + } + + ++void CodeSerializer::SerializeCodeStub(Code* code, HowToCode how_to_code, ++ WhereToPoint where_to_point, int skip) { ++ DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) || ++ (how_to_code == kPlain && where_to_point == kInnerPointer) || ++ (how_to_code == kFromCode && where_to_point == kInnerPointer)); ++ uint32_t stub_key = code->stub_key(); ++ ++ if (CodeStub::MajorKeyFromKey(stub_key) == CodeStub::NoCacheKey()) { ++ if (FLAG_trace_code_serializer) { ++ PrintF("Encoding uncacheable code stub as heap object\n"); ++ } ++ SerializeHeapObject(code, how_to_code, where_to_point, skip); ++ return; ++ } ++ ++ if (skip != 0) { ++ sink_->Put(kSkip, "SkipFromSerializeCodeStub"); ++ sink_->PutInt(skip, "SkipDistanceFromSerializeCodeStub"); ++ } ++ ++ int index = AddCodeStubKey(stub_key) + kCodeStubsBaseIndex; ++ ++ if (FLAG_trace_code_serializer) { ++ PrintF("Encoding code stub %s as %d\n", ++ CodeStub::MajorName(CodeStub::MajorKeyFromKey(stub_key), false), ++ index); ++ } ++ ++ sink_->Put(kAttachedReference + how_to_code + where_to_point, "CodeStub"); ++ sink_->PutInt(index, "CodeStub key"); ++} ++ ++ ++int CodeSerializer::AddCodeStubKey(uint32_t stub_key) { ++ // TODO(yangguo) Maybe we need a hash table for a faster lookup than O(n^2). ++ int index = 0; ++ while (index < stub_keys_.length()) { ++ if (stub_keys_[index] == stub_key) return index; ++ index++; ++ } ++ stub_keys_.Add(stub_key); ++ return index; ++} ++ ++ + void CodeSerializer::SerializeSourceObject(HowToCode how_to_code, + WhereToPoint where_to_point, + int skip) { +@@ -1883,6 +1960,10 @@ void CodeSerializer::SerializeSourceObject(HowToCode how_to_code, + sink_->PutInt(skip, "SkipDistanceFromSerializeSourceObject"); + } + ++ if (FLAG_trace_code_serializer) { ++ PrintF("Encoding source object\n"); ++ } ++ + DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject); + sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source"); + sink_->PutInt(kSourceObjectIndex, "kSourceObjectIndex"); +@@ -1894,22 +1975,36 @@ Handle CodeSerializer::Deserialize(Isolate* isolate, + Handle source) { + base::ElapsedTimer timer; + if (FLAG_profile_deserialization) timer.Start(); +- SerializedCodeData scd(data, *source); +- SnapshotByteSource payload(scd.Payload(), scd.PayloadLength()); +- Deserializer deserializer(&payload); +- STATIC_ASSERT(NEW_SPACE == 0); +- for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) { +- deserializer.set_reservation(i, scd.GetReservation(i)); +- } +- +- // Prepare and register list of attached objects. +- Vector attached_objects = Vector::New(1); +- attached_objects[kSourceObjectIndex] = *source; +- deserializer.SetAttachedObjects(&attached_objects); + + Object* root; +- deserializer.DeserializePartial(isolate, &root); +- deserializer.FlushICacheForNewCodeObjects(); ++ ++ { ++ HandleScope scope(isolate); ++ ++ SerializedCodeData scd(data, *source); ++ SnapshotByteSource payload(scd.Payload(), scd.PayloadLength()); ++ Deserializer deserializer(&payload); ++ STATIC_ASSERT(NEW_SPACE == 0); ++ for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) { ++ deserializer.set_reservation(i, scd.GetReservation(i)); ++ } ++ ++ // Prepare and register list of attached objects. ++ Vector code_stub_keys = scd.CodeStubKeys(); ++ Vector > attached_objects = Vector >::New( ++ code_stub_keys.length() + kCodeStubsBaseIndex); ++ attached_objects[kSourceObjectIndex] = source; ++ for (int i = 0; i < code_stub_keys.length(); i++) { ++ attached_objects[i + kCodeStubsBaseIndex] = ++ CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked(); ++ } ++ deserializer.SetAttachedObjects(&attached_objects); ++ ++ // Deserialize. ++ deserializer.DeserializePartial(isolate, &root); ++ deserializer.FlushICacheForNewCodeObjects(); ++ } ++ + if (FLAG_profile_deserialization) { + double ms = timer.Elapsed().InMillisecondsF(); + int length = data->length(); +@@ -1922,18 +2017,35 @@ Handle CodeSerializer::Deserialize(Isolate* isolate, + SerializedCodeData::SerializedCodeData(List* payload, CodeSerializer* cs) + : owns_script_data_(true) { + DisallowHeapAllocation no_gc; +- int data_length = payload->length() + kHeaderEntries * kIntSize; ++ List* stub_keys = cs->stub_keys(); ++ ++ // Calculate sizes. ++ int num_stub_keys = stub_keys->length(); ++ int stub_keys_size = stub_keys->length() * kInt32Size; ++ int data_length = kHeaderSize + stub_keys_size + payload->length(); ++ ++ // Allocate backing store and create result data. + byte* data = NewArray(data_length); + DCHECK(IsAligned(reinterpret_cast(data), kPointerAlignment)); +- CopyBytes(data + kHeaderEntries * kIntSize, payload->begin(), +- static_cast(payload->length())); + script_data_ = new ScriptData(data, data_length); + script_data_->AcquireDataOwnership(); ++ ++ // Set header values. + SetHeaderValue(kCheckSumOffset, CheckSum(cs->source())); ++ SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys); ++ SetHeaderValue(kPayloadLengthOffset, payload->length()); + STATIC_ASSERT(NEW_SPACE == 0); + for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) { + SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i)); + } ++ ++ // Copy code stub keys. ++ CopyBytes(data + kHeaderSize, reinterpret_cast(stub_keys->begin()), ++ stub_keys_size); ++ ++ // Copy serialized data. ++ CopyBytes(data + kHeaderSize + stub_keys_size, payload->begin(), ++ static_cast(payload->length())); + } + + +diff --git a/src/serialize.h b/src/serialize.h +index 066d75f..71b274b 100644 +--- node/deps/v8/src/serialize.h ++++ node/deps/v8/src/serialize.h +@@ -257,7 +257,7 @@ class Deserializer: public SerializerDeserializer { + + // Serialized user code reference certain objects that are provided in a list + // By calling this method, we assume that we are deserializing user code. +- void SetAttachedObjects(Vector* attached_objects) { ++ void SetAttachedObjects(Vector >* attached_objects) { + attached_objects_ = attached_objects; + } + +@@ -308,7 +308,7 @@ class Deserializer: public SerializerDeserializer { + Isolate* isolate_; + + // Objects from the attached object descriptions in the serialized user code. +- Vector* attached_objects_; ++ Vector >* attached_objects_; + + SnapshotByteSource* source_; + // This is the address of the next object that will be allocated in each +@@ -459,12 +459,10 @@ class Serializer : public SerializerDeserializer { + HowToCode how_to_code, + WhereToPoint where_to_point, + int skip) = 0; +- void SerializeReferenceToPreviousObject( +- int space, +- int address, +- HowToCode how_to_code, +- WhereToPoint where_to_point, +- int skip); ++ void SerializeReferenceToPreviousObject(HeapObject* heap_object, ++ HowToCode how_to_code, ++ WhereToPoint where_to_point, ++ int skip); + void InitializeAllocators(); + // This will return the space for an object. + static int SpaceOfObject(HeapObject* object); +@@ -594,20 +592,29 @@ class CodeSerializer : public Serializer { + Handle source); + + static const int kSourceObjectIndex = 0; ++ static const int kCodeStubsBaseIndex = 1; + + String* source() { + DCHECK(!AllowHeapAllocation::IsAllowed()); + return source_; + } + ++ List* stub_keys() { return &stub_keys_; } ++ + private: + void SerializeBuiltin(Code* builtin, HowToCode how_to_code, + WhereToPoint where_to_point, int skip); ++ void SerializeCodeStub(Code* code, HowToCode how_to_code, ++ WhereToPoint where_to_point, int skip); + void SerializeSourceObject(HowToCode how_to_code, WhereToPoint where_to_point, + int skip); ++ void SerializeHeapObject(HeapObject* heap_object, HowToCode how_to_code, ++ WhereToPoint where_to_point, int skip); ++ int AddCodeStubKey(uint32_t stub_key); + + DisallowHeapAllocation no_gc_; + String* source_; ++ List stub_keys_; + DISALLOW_COPY_AND_ASSIGN(CodeSerializer); + }; + +@@ -638,12 +645,22 @@ class SerializedCodeData { + return result; + } + ++ Vector CodeStubKeys() const { ++ return Vector( ++ reinterpret_cast(script_data_->data() + kHeaderSize), ++ GetHeaderValue(kNumCodeStubKeysOffset)); ++ } ++ + const byte* Payload() const { +- return script_data_->data() + kHeaderEntries * kIntSize; ++ int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size; ++ return script_data_->data() + kHeaderSize + code_stubs_size; + } + + int PayloadLength() const { +- return script_data_->length() - kHeaderEntries * kIntSize; ++ int payload_length = GetHeaderValue(kPayloadLengthOffset); ++ DCHECK_EQ(script_data_->data() + script_data_->length(), ++ Payload() + payload_length); ++ return payload_length; + } + + int GetReservation(int space) const { +@@ -666,10 +683,21 @@ class SerializedCodeData { + + // The data header consists of int-sized entries: + // [0] version hash +- // [1..7] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE. ++ // [1] number of code stub keys ++ // [2] payload length ++ // [3..9] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE. + static const int kCheckSumOffset = 0; +- static const int kReservationsOffset = 1; +- static const int kHeaderEntries = 8; ++ static const int kNumCodeStubKeysOffset = 1; ++ static const int kPayloadLengthOffset = 2; ++ static const int kReservationsOffset = 3; ++ ++ static const int kNumSpaces = PROPERTY_CELL_SPACE - NEW_SPACE + 1; ++ static const int kHeaderEntries = kReservationsOffset + kNumSpaces; ++ static const int kHeaderSize = kHeaderEntries * kIntSize; ++ ++ // Following the header, we store, in sequential order ++ // - code stub keys ++ // - serialization payload + + ScriptData* script_data_; + bool owns_script_data_; diff --git a/patches/backport.R24204.patch b/patches/backport.R24204.patch new file mode 100644 index 0000000..cb5461f --- /dev/null +++ b/patches/backport.R24204.patch @@ -0,0 +1,739 @@ +commit 1257f35c21c9aeb054ae57a0087c50d91f625c24 +Author: yangguo@chromium.org +Date: Thu Sep 25 07:32:13 2014 +0000 + + Support large objects in the serializer/deserializer. + + R=hpayer@chromium.org, mvstanton@chromium.org + + Review URL: https://codereview.chromium.org/581223004 + + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24204 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/heap/heap.cc b/src/heap/heap.cc +index 3d0c2f0..78c45b0 100644 +--- node/deps/v8/src/heap/heap.cc ++++ node/deps/v8/src/heap/heap.cc +@@ -923,9 +923,12 @@ void Heap::ReserveSpace(int* sizes, Address* locations_out) { + static const int kThreshold = 20; + while (gc_performed && counter++ < kThreshold) { + gc_performed = false; +- DCHECK(NEW_SPACE == FIRST_PAGED_SPACE - 1); +- for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) { +- if (sizes[space] != 0) { ++ for (int space = NEW_SPACE; space < Serializer::kNumberOfSpaces; space++) { ++ if (sizes[space] == 0) continue; ++ bool perform_gc = false; ++ if (space == LO_SPACE) { ++ perform_gc = !lo_space()->CanAllocateSize(sizes[space]); ++ } else { + AllocationResult allocation; + if (space == NEW_SPACE) { + allocation = new_space()->AllocateRaw(sizes[space]); +@@ -933,23 +936,27 @@ void Heap::ReserveSpace(int* sizes, Address* locations_out) { + allocation = paged_space(space)->AllocateRaw(sizes[space]); + } + FreeListNode* node; +- if (!allocation.To(&node)) { +- if (space == NEW_SPACE) { +- Heap::CollectGarbage(NEW_SPACE, +- "failed to reserve space in the new space"); +- } else { +- AbortIncrementalMarkingAndCollectGarbage( +- this, static_cast(space), +- "failed to reserve space in paged space"); +- } +- gc_performed = true; +- break; +- } else { ++ if (allocation.To(&node)) { + // Mark with a free list node, in case we have a GC before + // deserializing. + node->set_size(this, sizes[space]); ++ DCHECK(space < Serializer::kNumberOfPreallocatedSpaces); + locations_out[space] = node->address(); ++ } else { ++ perform_gc = true; ++ } ++ } ++ if (perform_gc) { ++ if (space == NEW_SPACE) { ++ Heap::CollectGarbage(NEW_SPACE, ++ "failed to reserve space in the new space"); ++ } else { ++ AbortIncrementalMarkingAndCollectGarbage( ++ this, static_cast(space), ++ "failed to reserve space in paged or large object space"); + } ++ gc_performed = true; ++ break; // Abort for-loop over spaces and retry. + } + } + } +diff --git a/src/heap/heap.h b/src/heap/heap.h +index 956b859..87b939a 100644 +--- node/deps/v8/src/heap/heap.h ++++ node/deps/v8/src/heap/heap.h +@@ -2021,6 +2021,7 @@ class Heap { + int gc_callbacks_depth_; + + friend class AlwaysAllocateScope; ++ friend class Deserializer; + friend class Factory; + friend class GCCallbacksScope; + friend class GCTracer; +diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc +index f8d340f..ae4048f 100644 +--- node/deps/v8/src/heap/spaces.cc ++++ node/deps/v8/src/heap/spaces.cc +@@ -2840,9 +2840,7 @@ AllocationResult LargeObjectSpace::AllocateRaw(int object_size, + return AllocationResult::Retry(identity()); + } + +- if (Size() + object_size > max_capacity_) { +- return AllocationResult::Retry(identity()); +- } ++ if (!CanAllocateSize(object_size)) return AllocationResult::Retry(identity()); + + LargePage* page = heap()->isolate()->memory_allocator()->AllocateLargePage( + object_size, this, executable); +diff --git a/src/heap/spaces.h b/src/heap/spaces.h +index 9ecb3c4..1a89449 100644 +--- node/deps/v8/src/heap/spaces.h ++++ node/deps/v8/src/heap/spaces.h +@@ -2728,6 +2728,8 @@ class LargeObjectSpace : public Space { + MUST_USE_RESULT AllocationResult + AllocateRaw(int object_size, Executability executable); + ++ bool CanAllocateSize(int size) { return Size() + size <= max_capacity_; } ++ + // Available bytes for objects in this space. + inline intptr_t Available(); + +diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc +index b4a4018..eacd098 100644 +--- node/deps/v8/src/mksnapshot.cc ++++ node/deps/v8/src/mksnapshot.cc +@@ -84,10 +84,10 @@ class SnapshotWriter { + i::List startup_blob; + i::ListSnapshotSink sink(&startup_blob); + +- int spaces[] = { +- i::NEW_SPACE, i::OLD_POINTER_SPACE, i::OLD_DATA_SPACE, i::CODE_SPACE, +- i::MAP_SPACE, i::CELL_SPACE, i::PROPERTY_CELL_SPACE +- }; ++ int spaces[] = {i::NEW_SPACE, i::OLD_POINTER_SPACE, ++ i::OLD_DATA_SPACE, i::CODE_SPACE, ++ i::MAP_SPACE, i::CELL_SPACE, ++ i::PROPERTY_CELL_SPACE, i::LO_SPACE}; + + i::byte* snapshot_bytes = snapshot_data.begin(); + sink.PutBlob(snapshot_bytes, snapshot_data.length(), "snapshot"); +@@ -197,6 +197,7 @@ class SnapshotWriter { + WriteSizeVar(ser, prefix, "map", i::MAP_SPACE); + WriteSizeVar(ser, prefix, "cell", i::CELL_SPACE); + WriteSizeVar(ser, prefix, "property_cell", i::PROPERTY_CELL_SPACE); ++ WriteSizeVar(ser, prefix, "lo", i::LO_SPACE); + fprintf(fp_, "\n"); + } + +diff --git a/src/serialize.cc b/src/serialize.cc +index 843f976..894a1be 100644 +--- node/deps/v8/src/serialize.cc ++++ node/deps/v8/src/serialize.cc +@@ -596,8 +596,9 @@ Deserializer::Deserializer(SnapshotByteSource* source) + : isolate_(NULL), + attached_objects_(NULL), + source_(source), +- external_reference_decoder_(NULL) { +- for (int i = 0; i < LAST_SPACE + 1; i++) { ++ external_reference_decoder_(NULL), ++ deserialized_large_objects_(0) { ++ for (int i = 0; i < kNumberOfSpaces; i++) { + reservations_[i] = kUninitializedReservation; + } + } +@@ -615,7 +616,7 @@ void Deserializer::FlushICacheForNewCodeObjects() { + void Deserializer::Deserialize(Isolate* isolate) { + isolate_ = isolate; + DCHECK(isolate_ != NULL); +- isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]); ++ isolate_->heap()->ReserveSpace(reservations_, high_water_); + // No active threads. + DCHECK_EQ(NULL, isolate_->thread_manager()->FirstThreadStateInUse()); + // No active handles. +@@ -662,7 +663,8 @@ void Deserializer::DeserializePartial(Isolate* isolate, Object** root) { + for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) { + DCHECK(reservations_[i] != kUninitializedReservation); + } +- isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]); ++ Heap* heap = isolate->heap(); ++ heap->ReserveSpace(reservations_, high_water_); + if (external_reference_decoder_ == NULL) { + external_reference_decoder_ = new ExternalReferenceDecoder(isolate); + } +@@ -798,11 +800,40 @@ void Deserializer::ReadObject(int space_number, + + *write_back = obj; + #ifdef DEBUG +- bool is_codespace = (space_number == CODE_SPACE); +- DCHECK(obj->IsCode() == is_codespace); ++ if (obj->IsCode()) { ++ DCHECK(space_number == CODE_SPACE || space_number == LO_SPACE); ++ } else { ++ DCHECK(space_number != CODE_SPACE); ++ } + #endif + } + ++ ++// We know the space requirements before deserialization and can ++// pre-allocate that reserved space. During deserialization, all we need ++// to do is to bump up the pointer for each space in the reserved ++// space. This is also used for fixing back references. ++// Since multiple large objects cannot be folded into one large object ++// space allocation, we have to do an actual allocation when deserializing ++// each large object. Instead of tracking offset for back references, we ++// reference large objects by index. ++Address Deserializer::Allocate(int space_index, int size) { ++ if (space_index == LO_SPACE) { ++ AlwaysAllocateScope scope(isolate_); ++ LargeObjectSpace* lo_space = isolate_->heap()->lo_space(); ++ Executability exec = static_cast(source_->GetInt()); ++ AllocationResult result = lo_space->AllocateRaw(size, exec); ++ HeapObject* obj = HeapObject::cast(result.ToObjectChecked()); ++ deserialized_large_objects_.Add(obj); ++ return obj->address(); ++ } else { ++ DCHECK(space_index < kNumberOfPreallocatedSpaces); ++ Address address = high_water_[space_index]; ++ high_water_[space_index] = address + size; ++ return address; ++ } ++} ++ + void Deserializer::ReadChunk(Object** current, + Object** limit, + int source_space, +@@ -925,15 +956,16 @@ void Deserializer::ReadChunk(Object** current, + // This generates a case and a body for the new space (which has to do extra + // write barrier handling) and handles the other spaces with 8 fall-through + // cases and one body. +-#define ALL_SPACES(where, how, within) \ +- CASE_STATEMENT(where, how, within, NEW_SPACE) \ +- CASE_BODY(where, how, within, NEW_SPACE) \ +- CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \ +- CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \ +- CASE_STATEMENT(where, how, within, CODE_SPACE) \ +- CASE_STATEMENT(where, how, within, CELL_SPACE) \ +- CASE_STATEMENT(where, how, within, PROPERTY_CELL_SPACE) \ +- CASE_STATEMENT(where, how, within, MAP_SPACE) \ ++#define ALL_SPACES(where, how, within) \ ++ CASE_STATEMENT(where, how, within, NEW_SPACE) \ ++ CASE_BODY(where, how, within, NEW_SPACE) \ ++ CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \ ++ CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \ ++ CASE_STATEMENT(where, how, within, CODE_SPACE) \ ++ CASE_STATEMENT(where, how, within, MAP_SPACE) \ ++ CASE_STATEMENT(where, how, within, CELL_SPACE) \ ++ CASE_STATEMENT(where, how, within, PROPERTY_CELL_SPACE) \ ++ CASE_STATEMENT(where, how, within, LO_SPACE) \ + CASE_BODY(where, how, within, kAnyOldSpace) + + #define FOUR_CASES(byte_code) \ +@@ -1184,12 +1216,11 @@ Serializer::Serializer(Isolate* isolate, SnapshotByteSink* sink) + sink_(sink), + external_reference_encoder_(new ExternalReferenceEncoder(isolate)), + root_index_wave_front_(0), +- code_address_map_(NULL) { ++ code_address_map_(NULL), ++ seen_large_objects_index_(0) { + // The serializer is meant to be used only to generate initial heap images + // from a context in which there is only one isolate. +- for (int i = 0; i <= LAST_SPACE; i++) { +- fullness_[i] = 0; +- } ++ for (int i = 0; i < kNumberOfSpaces; i++) fullness_[i] = 0; + } + + +@@ -1324,10 +1355,7 @@ void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object, + WhereToPoint where_to_point, + int skip) { + int space = SpaceOfObject(heap_object); +- int address = address_mapper_.MappedTo(heap_object); +- int offset = CurrentAllocationAddress(space) - address; +- // Shift out the bits that are always 0. +- offset >>= kObjectAlignmentBits; ++ + if (skip == 0) { + sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRefSer"); + } else { +@@ -1335,7 +1363,17 @@ void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object, + "BackRefSerWithSkip"); + sink_->PutInt(skip, "BackRefSkipDistance"); + } +- sink_->PutInt(offset, "offset"); ++ ++ if (space == LO_SPACE) { ++ int index = address_mapper_.MappedTo(heap_object); ++ sink_->PutInt(index, "large object index"); ++ } else { ++ int address = address_mapper_.MappedTo(heap_object); ++ int offset = CurrentAllocationAddress(space) - address; ++ // Shift out the bits that are always 0. ++ offset >>= kObjectAlignmentBits; ++ sink_->PutInt(offset, "offset"); ++ } + } + + +@@ -1494,8 +1532,18 @@ void Serializer::ObjectSerializer::Serialize() { + } + + // Mark this object as already serialized. +- int offset = serializer_->Allocate(space, size); +- serializer_->address_mapper()->AddMapping(object_, offset); ++ if (space == LO_SPACE) { ++ if (object_->IsCode()) { ++ sink_->PutInt(EXECUTABLE, "executable large object"); ++ } else { ++ sink_->PutInt(NOT_EXECUTABLE, "not executable large object"); ++ } ++ int index = serializer_->AllocateLargeObject(size); ++ serializer_->address_mapper()->AddMapping(object_, index); ++ } else { ++ int offset = serializer_->Allocate(space, size); ++ serializer_->address_mapper()->AddMapping(object_, offset); ++ } + + // Serialize the map (first word of the object). + serializer_->SerializeObject(object_->map(), kPlain, kStartOfObject, 0); +@@ -1747,8 +1795,14 @@ int Serializer::SpaceOfObject(HeapObject* object) { + } + + ++int Serializer::AllocateLargeObject(int size) { ++ fullness_[LO_SPACE] += size; ++ return seen_large_objects_index_++; ++} ++ ++ + int Serializer::Allocate(int space, int size) { +- CHECK(space >= 0 && space < kNumberOfSpaces); ++ CHECK(space >= 0 && space < kNumberOfPreallocatedSpaces); + int allocation_address = fullness_[space]; + fullness_[space] = allocation_address + size; + return allocation_address; +@@ -1840,11 +1894,11 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, + + if (heap_object->IsCode()) { + Code* code_object = Code::cast(heap_object); ++ DCHECK(!code_object->is_optimized_code()); + if (code_object->kind() == Code::BUILTIN) { + SerializeBuiltin(code_object, how_to_code, where_to_point, skip); + return; +- } +- if (code_object->IsCodeStubOrIC()) { ++ } else if (code_object->IsCodeStubOrIC()) { + SerializeCodeStub(code_object, how_to_code, where_to_point, skip); + return; + } +@@ -1991,7 +2045,7 @@ Handle CodeSerializer::Deserialize(Isolate* isolate, + SnapshotByteSource payload(scd.Payload(), scd.PayloadLength()); + Deserializer deserializer(&payload); + STATIC_ASSERT(NEW_SPACE == 0); +- for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) { ++ for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) { + deserializer.set_reservation(i, scd.GetReservation(i)); + } + +@@ -2041,7 +2095,7 @@ SerializedCodeData::SerializedCodeData(List* payload, CodeSerializer* cs) + SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys); + SetHeaderValue(kPayloadLengthOffset, payload->length()); + STATIC_ASSERT(NEW_SPACE == 0); +- for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) { ++ for (int i = 0; i < SerializerDeserializer::kNumberOfSpaces; i++) { + SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i)); + } + +diff --git a/src/serialize.h b/src/serialize.h +index 71b274b..7831536 100644 +--- node/deps/v8/src/serialize.h ++++ node/deps/v8/src/serialize.h +@@ -148,11 +148,15 @@ class SerializerDeserializer: public ObjectVisitor { + + static int nop() { return kNop; } + ++ // No reservation for large object space necessary. ++ static const int kNumberOfPreallocatedSpaces = LO_SPACE; ++ static const int kNumberOfSpaces = INVALID_SPACE; ++ + protected: + // Where the pointed-to object can be found: + enum Where { + kNewObject = 0, // Object is next in snapshot. +- // 1-6 One per space. ++ // 1-7 One per space. + kRootArray = 0x9, // Object is found in root array. + kPartialSnapshotCache = 0xa, // Object is in the cache. + kExternalReference = 0xb, // Pointer to an external reference. +@@ -161,9 +165,9 @@ class SerializerDeserializer: public ObjectVisitor { + kAttachedReference = 0xe, // Object is described in an attached list. + kNop = 0xf, // Does nothing, used to pad. + kBackref = 0x10, // Object is described relative to end. +- // 0x11-0x16 One per space. ++ // 0x11-0x17 One per space. + kBackrefWithSkip = 0x18, // Object is described relative to end. +- // 0x19-0x1e One per space. ++ // 0x19-0x1f One per space. + // 0x20-0x3f Used by misc. tags below. + kPointedToMask = 0x3f + }; +@@ -225,11 +229,11 @@ class SerializerDeserializer: public ObjectVisitor { + return byte_code & 0x1f; + } + +- static const int kNumberOfSpaces = LO_SPACE; + static const int kAnyOldSpace = -1; + + // A bitmask for getting the space out of an instruction. + static const int kSpaceMask = 7; ++ STATIC_ASSERT(kNumberOfSpaces <= kSpaceMask + 1); + }; + + +@@ -249,7 +253,7 @@ class Deserializer: public SerializerDeserializer { + + void set_reservation(int space_number, int reservation) { + DCHECK(space_number >= 0); +- DCHECK(space_number <= LAST_SPACE); ++ DCHECK(space_number < kNumberOfSpaces); + reservations_[space_number] = reservation; + } + +@@ -282,24 +286,18 @@ class Deserializer: public SerializerDeserializer { + void ReadChunk( + Object** start, Object** end, int space, Address object_address); + void ReadObject(int space_number, Object** write_back); ++ Address Allocate(int space_index, int size); + + // 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 +- // fix back references when deserializing. +- Address Allocate(int space_index, int size) { +- Address address = high_water_[space_index]; +- high_water_[space_index] = address + size; +- return address; +- } +- + // This returns the address of an object that has been described in the + // snapshot as being offset bytes back in a particular space. + HeapObject* GetAddressFromEnd(int space) { + int offset = source_->GetInt(); ++ if (space == LO_SPACE) return deserialized_large_objects_[offset]; ++ DCHECK(space < kNumberOfPreallocatedSpaces); + offset <<= kObjectAlignmentBits; + return HeapObject::FromAddress(high_water_[space] - offset); + } +@@ -313,13 +311,15 @@ class Deserializer: public SerializerDeserializer { + SnapshotByteSource* source_; + // This is the address of the next object that will be allocated in each + // space. It is used to calculate the addresses of back-references. +- Address high_water_[LAST_SPACE + 1]; ++ Address high_water_[kNumberOfPreallocatedSpaces]; + +- int reservations_[LAST_SPACE + 1]; ++ int reservations_[kNumberOfSpaces]; + static const intptr_t kUninitializedReservation = -1; + + ExternalReferenceDecoder* external_reference_decoder_; + ++ List deserialized_large_objects_; ++ + DISALLOW_COPY_AND_ASSIGN(Deserializer); + }; + +@@ -466,6 +466,7 @@ class Serializer : public SerializerDeserializer { + void InitializeAllocators(); + // This will return the space for an object. + static int SpaceOfObject(HeapObject* object); ++ int AllocateLargeObject(int size); + int Allocate(int space, int size); + int EncodeExternalReference(Address addr) { + return external_reference_encoder_->Encode(addr); +@@ -480,7 +481,7 @@ class Serializer : public SerializerDeserializer { + Isolate* isolate_; + // Keep track of the fullness of each space in order to generate + // relative addresses for back references. +- int fullness_[LAST_SPACE + 1]; ++ int fullness_[kNumberOfSpaces]; + SnapshotByteSink* sink_; + ExternalReferenceEncoder* external_reference_encoder_; + +@@ -497,6 +498,8 @@ class Serializer : public SerializerDeserializer { + + private: + CodeAddressMap* code_address_map_; ++ // We map serialized large objects to indexes for back-referencing. ++ int seen_large_objects_index_; + DISALLOW_COPY_AND_ASSIGN(Serializer); + }; + +@@ -691,8 +694,8 @@ class SerializedCodeData { + static const int kPayloadLengthOffset = 2; + static const int kReservationsOffset = 3; + +- static const int kNumSpaces = PROPERTY_CELL_SPACE - NEW_SPACE + 1; +- static const int kHeaderEntries = kReservationsOffset + kNumSpaces; ++ static const int kHeaderEntries = ++ kReservationsOffset + SerializerDeserializer::kNumberOfSpaces; + static const int kHeaderSize = kHeaderEntries * kIntSize; + + // Following the header, we store, in sequential order +diff --git a/src/snapshot-common.cc b/src/snapshot-common.cc +index a2d5213..4e90ce1 100644 +--- node/deps/v8/src/snapshot-common.cc ++++ node/deps/v8/src/snapshot-common.cc +@@ -21,8 +21,8 @@ void Snapshot::ReserveSpaceForLinkedInSnapshot(Deserializer* deserializer) { + deserializer->set_reservation(CODE_SPACE, code_space_used_); + deserializer->set_reservation(MAP_SPACE, map_space_used_); + deserializer->set_reservation(CELL_SPACE, cell_space_used_); +- deserializer->set_reservation(PROPERTY_CELL_SPACE, +- property_cell_space_used_); ++ deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_space_used_); ++ deserializer->set_reservation(LO_SPACE, lo_space_used_); + } + + +@@ -67,6 +67,7 @@ Handle Snapshot::NewContextFromSnapshot(Isolate* isolate) { + deserializer.set_reservation(CELL_SPACE, context_cell_space_used_); + deserializer.set_reservation(PROPERTY_CELL_SPACE, + context_property_cell_space_used_); ++ deserializer.set_reservation(LO_SPACE, context_lo_space_used_); + deserializer.DeserializePartial(isolate, &root); + CHECK(root->IsContext()); + return Handle(Context::cast(root)); +diff --git a/src/snapshot-empty.cc b/src/snapshot-empty.cc +index 65207bf..e8673e5 100644 +--- node/deps/v8/src/snapshot-empty.cc ++++ node/deps/v8/src/snapshot-empty.cc +@@ -27,6 +27,7 @@ const int Snapshot::code_space_used_ = 0; + const int Snapshot::map_space_used_ = 0; + const int Snapshot::cell_space_used_ = 0; + const int Snapshot::property_cell_space_used_ = 0; ++const int Snapshot::lo_space_used_ = 0; + + const int Snapshot::context_new_space_used_ = 0; + const int Snapshot::context_pointer_space_used_ = 0; +@@ -35,5 +36,5 @@ const int Snapshot::context_code_space_used_ = 0; + const int Snapshot::context_map_space_used_ = 0; + const int Snapshot::context_cell_space_used_ = 0; + const int Snapshot::context_property_cell_space_used_ = 0; +- ++const int Snapshot::context_lo_space_used_ = 0; + } } // namespace v8::internal +diff --git a/src/snapshot-external.cc b/src/snapshot-external.cc +index ee1a8f4..9b8bc1b 100644 +--- node/deps/v8/src/snapshot-external.cc ++++ node/deps/v8/src/snapshot-external.cc +@@ -25,6 +25,7 @@ struct SnapshotImpl { + int map_space_used; + int cell_space_used; + int property_cell_space_used; ++ int lo_space_used; + + const byte* context_data; + int context_size; +@@ -35,6 +36,7 @@ struct SnapshotImpl { + int context_map_space_used; + int context_cell_space_used; + int context_property_cell_space_used; ++ int context_lo_space_used; + }; + + +@@ -66,6 +68,7 @@ bool Snapshot::Initialize(Isolate* isolate) { + deserializer.set_reservation(CELL_SPACE, snapshot_impl_->cell_space_used); + deserializer.set_reservation(PROPERTY_CELL_SPACE, + snapshot_impl_->property_cell_space_used); ++ deserializer.set_reservation(LO_SPACE, snapshot_impl_->lo_space_used); + bool success = V8::Initialize(&deserializer); + if (FLAG_profile_deserialization) { + double ms = timer.Elapsed().InMillisecondsF(); +@@ -97,6 +100,7 @@ Handle Snapshot::NewContextFromSnapshot(Isolate* isolate) { + deserializer.set_reservation(PROPERTY_CELL_SPACE, + snapshot_impl_-> + context_property_cell_space_used); ++ deserializer.set_reservation(LO_SPACE, snapshot_impl_->context_lo_space_used); + Object* root; + deserializer.DeserializePartial(isolate, &root); + CHECK(root->IsContext()); +@@ -123,6 +127,7 @@ void SetSnapshotFromFile(StartupData* snapshot_blob) { + snapshot_impl_->map_space_used = source.GetInt(); + snapshot_impl_->cell_space_used = source.GetInt(); + snapshot_impl_->property_cell_space_used = source.GetInt(); ++ snapshot_impl_->lo_space_used = source.GetInt(); + + success &= source.GetBlob(&snapshot_impl_->context_data, + &snapshot_impl_->context_size); +diff --git a/src/snapshot-source-sink.cc b/src/snapshot-source-sink.cc +index 44f8706..29bad33 100644 +--- node/deps/v8/src/snapshot-source-sink.cc ++++ node/deps/v8/src/snapshot-source-sink.cc +@@ -39,15 +39,17 @@ void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) { + + + void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) { +- DCHECK(integer < 1 << 22); ++ DCHECK(integer < 1 << 30); + integer <<= 2; + int bytes = 1; + if (integer > 0xff) bytes = 2; + if (integer > 0xffff) bytes = 3; +- integer |= bytes; ++ if (integer > 0xffffff) bytes = 4; ++ integer |= (bytes - 1); + Put(static_cast(integer & 0xff), "IntPart1"); + if (bytes > 1) Put(static_cast((integer >> 8) & 0xff), "IntPart2"); + if (bytes > 2) Put(static_cast((integer >> 16) & 0xff), "IntPart3"); ++ if (bytes > 3) Put(static_cast((integer >> 24) & 0xff), "IntPart4"); + } + + void SnapshotByteSink::PutRaw(byte* data, int number_of_bytes, +diff --git a/src/snapshot-source-sink.h b/src/snapshot-source-sink.h +index 3c64bca..c1a31b5 100644 +--- node/deps/v8/src/snapshot-source-sink.h ++++ node/deps/v8/src/snapshot-source-sink.h +@@ -39,7 +39,7 @@ class SnapshotByteSource FINAL { + // This way of variable-length encoding integers does not suffer from branch + // mispredictions. + uint32_t answer = GetUnalignedInt(); +- int bytes = answer & 3; ++ int bytes = (answer & 3) + 1; + Advance(bytes); + uint32_t mask = 0xffffffffu; + mask >>= 32 - (bytes << 3); +diff --git a/src/snapshot.h b/src/snapshot.h +index 3d752a7..590ecf1 100644 +--- node/deps/v8/src/snapshot.h ++++ node/deps/v8/src/snapshot.h +@@ -48,6 +48,7 @@ class Snapshot { + static const int map_space_used_; + static const int cell_space_used_; + static const int property_cell_space_used_; ++ static const int lo_space_used_; + static const int context_new_space_used_; + static const int context_pointer_space_used_; + static const int context_data_space_used_; +@@ -55,6 +56,7 @@ class Snapshot { + static const int context_map_space_used_; + static const int context_cell_space_used_; + static const int context_property_cell_space_used_; ++ static const int context_lo_space_used_; + static const int size_; + static const int raw_size_; + static const int context_size_; +diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc +index c277011..ed9419d 100644 +--- node/deps/v8/test/cctest/test-serialize.cc ++++ node/deps/v8/test/cctest/test-serialize.cc +@@ -137,14 +137,10 @@ class FileByteSink : public SnapshotByteSink { + virtual int Position() { + return ftell(fp_); + } +- void WriteSpaceUsed( +- int new_space_used, +- int pointer_space_used, +- int data_space_used, +- int code_space_used, +- int map_space_used, +- int cell_space_used, +- int property_cell_space_used); ++ void WriteSpaceUsed(int new_space_used, int pointer_space_used, ++ int data_space_used, int code_space_used, ++ int map_space_used, int cell_space_used, ++ int property_cell_space_used, int lo_space_used); + + private: + FILE* fp_; +@@ -152,14 +148,11 @@ class FileByteSink : public SnapshotByteSink { + }; + + +-void FileByteSink::WriteSpaceUsed( +- int new_space_used, +- int pointer_space_used, +- int data_space_used, +- int code_space_used, +- int map_space_used, +- int cell_space_used, +- int property_cell_space_used) { ++void FileByteSink::WriteSpaceUsed(int new_space_used, int pointer_space_used, ++ int data_space_used, int code_space_used, ++ int map_space_used, int cell_space_used, ++ int property_cell_space_used, ++ int lo_space_used) { + int file_name_length = StrLength(file_name_) + 10; + Vector name = Vector::New(file_name_length + 1); + SNPrintF(name, "%s.size", file_name_); +@@ -172,6 +165,7 @@ void FileByteSink::WriteSpaceUsed( + fprintf(fp, "map %d\n", map_space_used); + fprintf(fp, "cell %d\n", cell_space_used); + fprintf(fp, "property cell %d\n", property_cell_space_used); ++ fprintf(fp, "lo %d\n", lo_space_used); + fclose(fp); + } + +@@ -181,14 +175,14 @@ static bool WriteToFile(Isolate* isolate, const char* snapshot_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)); ++ 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), ++ ser.CurrentAllocationAddress(LO_SPACE)); + + return true; + } +@@ -246,7 +240,7 @@ static void ReserveSpaceForSnapshot(Deserializer* deserializer, + FILE* fp = v8::base::OS::FOpen(name.start(), "r"); + name.Dispose(); + int new_size, pointer_size, data_size, code_size, map_size, cell_size, +- property_cell_size; ++ property_cell_size, lo_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. +@@ -259,6 +253,7 @@ static void ReserveSpaceForSnapshot(Deserializer* deserializer, + 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, "property cell %d\n", &property_cell_size)); ++ CHECK_EQ(1, fscanf(fp, "lo %d\n", &lo_size)); + #ifdef _MSC_VER + #undef fscanf + #endif +@@ -270,6 +265,7 @@ static void ReserveSpaceForSnapshot(Deserializer* deserializer, + deserializer->set_reservation(MAP_SPACE, map_size); + deserializer->set_reservation(CELL_SPACE, cell_size); + deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size); ++ deserializer->set_reservation(LO_SPACE, lo_size); + } + + diff --git a/patches/backport.R24262.patch b/patches/backport.R24262.patch new file mode 100644 index 0000000..64bd784 --- /dev/null +++ b/patches/backport.R24262.patch @@ -0,0 +1,88 @@ +commit 667f15a1047eeadf4cbadbb50dafe6541745cdc3 +Author: yangguo@chromium.org +Date: Mon Sep 29 07:14:05 2014 +0000 + + Fix serializing ICs. + + R=mvstanton@chromium.org + + Review URL: https://codereview.chromium.org/587213002 + + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24262 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/serialize.cc b/src/serialize.cc +index 894a1be..a2dde9b 100644 +--- node/deps/v8/src/serialize.cc ++++ node/deps/v8/src/serialize.cc +@@ -1894,15 +1894,26 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, + + if (heap_object->IsCode()) { + Code* code_object = Code::cast(heap_object); +- DCHECK(!code_object->is_optimized_code()); +- if (code_object->kind() == Code::BUILTIN) { +- SerializeBuiltin(code_object, how_to_code, where_to_point, skip); +- return; +- } else if (code_object->IsCodeStubOrIC()) { +- SerializeCodeStub(code_object, how_to_code, where_to_point, skip); +- return; ++ switch (code_object->kind()) { ++ case Code::OPTIMIZED_FUNCTION: // No optimized code compiled yet. ++ case Code::HANDLER: // No handlers patched in yet. ++ case Code::REGEXP: // No regexp literals initialized yet. ++ case Code::NUMBER_OF_KINDS: // Pseudo enum value. ++ CHECK(false); ++ case Code::BUILTIN: ++ SerializeBuiltin(code_object, how_to_code, where_to_point, skip); ++ return; ++ case Code::STUB: ++ SerializeCodeStub(code_object, how_to_code, where_to_point, skip); ++ return; ++#define IC_KIND_CASE(KIND) case Code::KIND: ++ IC_KIND_LIST(IC_KIND_CASE) ++#undef IC_KIND_CASE ++ // TODO(yangguo): add special handling to canonicalize ICs. ++ case Code::FUNCTION: ++ SerializeHeapObject(code_object, how_to_code, where_to_point, skip); ++ return; + } +- code_object->ClearInlineCaches(); + } + + if (heap_object == source_) { +@@ -1967,20 +1978,13 @@ void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code, + } + + +-void CodeSerializer::SerializeCodeStub(Code* code, HowToCode how_to_code, ++void CodeSerializer::SerializeCodeStub(Code* stub, HowToCode how_to_code, + WhereToPoint where_to_point, int skip) { + DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) || + (how_to_code == kPlain && where_to_point == kInnerPointer) || + (how_to_code == kFromCode && where_to_point == kInnerPointer)); +- uint32_t stub_key = code->stub_key(); +- +- if (CodeStub::MajorKeyFromKey(stub_key) == CodeStub::NoCacheKey()) { +- if (FLAG_trace_code_serializer) { +- PrintF("Encoding uncacheable code stub as heap object\n"); +- } +- SerializeHeapObject(code, how_to_code, where_to_point, skip); +- return; +- } ++ uint32_t stub_key = stub->stub_key(); ++ DCHECK(CodeStub::MajorKeyFromKey(stub_key) != CodeStub::NoCache); + + if (skip != 0) { + sink_->Put(kSkip, "SkipFromSerializeCodeStub"); +diff --git a/src/serialize.h b/src/serialize.h +index 7831536..b6ad82c 100644 +--- node/deps/v8/src/serialize.h ++++ node/deps/v8/src/serialize.h +@@ -607,7 +607,7 @@ class CodeSerializer : public Serializer { + private: + void SerializeBuiltin(Code* builtin, HowToCode how_to_code, + WhereToPoint where_to_point, int skip); +- void SerializeCodeStub(Code* code, HowToCode how_to_code, ++ void SerializeCodeStub(Code* stub, HowToCode how_to_code, + WhereToPoint where_to_point, int skip); + void SerializeSourceObject(HowToCode how_to_code, WhereToPoint where_to_point, + int skip); diff --git a/patches/backport.R24266.patch b/patches/backport.R24266.patch new file mode 100644 index 0000000..8f725cd --- /dev/null +++ b/patches/backport.R24266.patch @@ -0,0 +1,238 @@ +commit ad24cdae728fc34b23e74a22543702de3ae477d1 +Author: yangguo@chromium.org +Date: Mon Sep 29 07:53:22 2014 +0000 + + Do not serialize non-lazy compiled function literals. + + ... and some small refactorings. + + R=mvstanton@chromium.org + + Review URL: https://codereview.chromium.org/594513002 + + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24266 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/serialize.cc b/src/serialize.cc +index a2dde9b..9d59b6f 100644 +--- node/deps/v8/src/serialize.cc ++++ node/deps/v8/src/serialize.cc +@@ -1846,7 +1846,7 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate, + SnapshotByteSink* sink = FLAG_trace_code_serializer + ? static_cast(&debug_sink) + : static_cast(&list_sink); +- CodeSerializer cs(isolate, sink, *source); ++ CodeSerializer cs(isolate, sink, *source, info->code()); + DisallowHeapAllocation no_gc; + Object** location = Handle::cast(info).location(); + cs.VisitPointer(location); +@@ -1867,31 +1867,25 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate, + + void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, + WhereToPoint where_to_point, int skip) { +- CHECK(o->IsHeapObject()); + HeapObject* heap_object = HeapObject::cast(o); + +- // The code-caches link to context-specific code objects, which +- // the startup and context serializes cannot currently handle. +- DCHECK(!heap_object->IsMap() || +- Map::cast(heap_object)->code_cache() == +- heap_object->GetHeap()->empty_fixed_array()); +- + int root_index; + if ((root_index = RootIndex(heap_object, how_to_code)) != kInvalidRootIndex) { + PutRoot(root_index, heap_object, how_to_code, where_to_point, skip); + return; + } + +- // TODO(yangguo) wire up global object. +- // TODO(yangguo) We cannot deal with different hash seeds yet. +- DCHECK(!heap_object->IsHashTable()); +- + if (address_mapper_.IsMapped(heap_object)) { + SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point, + skip); + return; + } + ++ if (skip != 0) { ++ sink_->Put(kSkip, "SkipFromSerializeObject"); ++ sink_->PutInt(skip, "SkipDistanceFromSerializeObject"); ++ } ++ + if (heap_object->IsCode()) { + Code* code_object = Code::cast(heap_object); + switch (code_object->kind()) { +@@ -1901,34 +1895,42 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, + case Code::NUMBER_OF_KINDS: // Pseudo enum value. + CHECK(false); + case Code::BUILTIN: +- SerializeBuiltin(code_object, how_to_code, where_to_point, skip); ++ SerializeBuiltin(code_object, how_to_code, where_to_point); + return; + case Code::STUB: +- SerializeCodeStub(code_object, how_to_code, where_to_point, skip); ++ SerializeCodeStub(code_object, how_to_code, where_to_point); + return; + #define IC_KIND_CASE(KIND) case Code::KIND: + IC_KIND_LIST(IC_KIND_CASE) + #undef IC_KIND_CASE ++ SerializeHeapObject(code_object, how_to_code, where_to_point); ++ return; + // TODO(yangguo): add special handling to canonicalize ICs. + case Code::FUNCTION: +- SerializeHeapObject(code_object, how_to_code, where_to_point, skip); ++ SerializeHeapObject(code_object, how_to_code, where_to_point); + return; + } + } + + if (heap_object == source_) { +- SerializeSourceObject(how_to_code, where_to_point, skip); ++ SerializeSourceObject(how_to_code, where_to_point); + return; + } + +- SerializeHeapObject(heap_object, how_to_code, where_to_point, skip); ++ // Past this point we should not see any (context-specific) maps anymore. ++ CHECK(!heap_object->IsMap()); ++ // There should be no references to the global object embedded. ++ CHECK(!heap_object->IsJSGlobalProxy() && !heap_object->IsGlobalObject()); ++ // There should be no hash table embedded. They would require rehashing. ++ CHECK(!heap_object->IsHashTable()); ++ ++ SerializeHeapObject(heap_object, how_to_code, where_to_point); + } + + + void CodeSerializer::SerializeHeapObject(HeapObject* heap_object, + HowToCode how_to_code, +- WhereToPoint where_to_point, +- int skip) { ++ WhereToPoint where_to_point) { + if (heap_object->IsScript()) { + // The wrapper cache uses a Foreign object to point to a global handle. + // However, the object visitor expects foreign objects to point to external +@@ -1936,11 +1946,6 @@ void CodeSerializer::SerializeHeapObject(HeapObject* heap_object, + Script::cast(heap_object)->ClearWrapperCache(); + } + +- if (skip != 0) { +- sink_->Put(kSkip, "SkipFromSerializeObject"); +- sink_->PutInt(skip, "SkipDistanceFromSerializeObject"); +- } +- + if (FLAG_trace_code_serializer) { + PrintF("Encoding heap object: "); + heap_object->ShortPrint(); +@@ -1955,12 +1960,7 @@ void CodeSerializer::SerializeHeapObject(HeapObject* heap_object, + + + void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code, +- WhereToPoint where_to_point, int skip) { +- if (skip != 0) { +- sink_->Put(kSkip, "SkipFromSerializeBuiltin"); +- sink_->PutInt(skip, "SkipDistanceFromSerializeBuiltin"); +- } +- ++ WhereToPoint where_to_point) { + DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) || + (how_to_code == kPlain && where_to_point == kInnerPointer) || + (how_to_code == kFromCode && where_to_point == kInnerPointer)); +@@ -1979,18 +1979,13 @@ void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code, + + + void CodeSerializer::SerializeCodeStub(Code* stub, HowToCode how_to_code, +- WhereToPoint where_to_point, int skip) { ++ WhereToPoint where_to_point) { + DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) || + (how_to_code == kPlain && where_to_point == kInnerPointer) || + (how_to_code == kFromCode && where_to_point == kInnerPointer)); + uint32_t stub_key = stub->stub_key(); + DCHECK(CodeStub::MajorKeyFromKey(stub_key) != CodeStub::NoCache); + +- if (skip != 0) { +- sink_->Put(kSkip, "SkipFromSerializeCodeStub"); +- sink_->PutInt(skip, "SkipDistanceFromSerializeCodeStub"); +- } +- + int index = AddCodeStubKey(stub_key) + kCodeStubsBaseIndex; + + if (FLAG_trace_code_serializer) { +@@ -2017,16 +2012,8 @@ int CodeSerializer::AddCodeStubKey(uint32_t stub_key) { + + + void CodeSerializer::SerializeSourceObject(HowToCode how_to_code, +- WhereToPoint where_to_point, +- int skip) { +- if (skip != 0) { +- sink_->Put(kSkip, "SkipFromSerializeSourceObject"); +- sink_->PutInt(skip, "SkipDistanceFromSerializeSourceObject"); +- } +- +- if (FLAG_trace_code_serializer) { +- PrintF("Encoding source object\n"); +- } ++ WhereToPoint where_to_point) { ++ if (FLAG_trace_code_serializer) PrintF("Encoding source object\n"); + + DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject); + sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source"); +diff --git a/src/serialize.h b/src/serialize.h +index b6ad82c..616f8f1 100644 +--- node/deps/v8/src/serialize.h ++++ node/deps/v8/src/serialize.h +@@ -577,19 +577,10 @@ class StartupSerializer : public Serializer { + + class CodeSerializer : public Serializer { + public: +- CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source) +- : Serializer(isolate, sink), source_(source) { +- set_root_index_wave_front(Heap::kStrongRootListLength); +- InitializeCodeAddressMap(); +- } +- + static ScriptData* Serialize(Isolate* isolate, + Handle info, + Handle source); + +- virtual void SerializeObject(Object* o, HowToCode how_to_code, +- WhereToPoint where_to_point, int skip); +- + static Handle Deserialize(Isolate* isolate, + ScriptData* data, + Handle source); +@@ -605,18 +596,29 @@ class CodeSerializer : public Serializer { + List* stub_keys() { return &stub_keys_; } + + private: ++ CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source, ++ Code* main_code) ++ : Serializer(isolate, sink), source_(source), main_code_(main_code) { ++ set_root_index_wave_front(Heap::kStrongRootListLength); ++ InitializeCodeAddressMap(); ++ } ++ ++ virtual void SerializeObject(Object* o, HowToCode how_to_code, ++ WhereToPoint where_to_point, int skip); ++ + void SerializeBuiltin(Code* builtin, HowToCode how_to_code, +- WhereToPoint where_to_point, int skip); ++ WhereToPoint where_to_point); + void SerializeCodeStub(Code* stub, HowToCode how_to_code, +- WhereToPoint where_to_point, int skip); +- void SerializeSourceObject(HowToCode how_to_code, WhereToPoint where_to_point, +- int skip); ++ WhereToPoint where_to_point); ++ void SerializeSourceObject(HowToCode how_to_code, ++ WhereToPoint where_to_point); + void SerializeHeapObject(HeapObject* heap_object, HowToCode how_to_code, +- WhereToPoint where_to_point, int skip); ++ WhereToPoint where_to_point); + int AddCodeStubKey(uint32_t stub_key); + + DisallowHeapAllocation no_gc_; + String* source_; ++ Code* main_code_; + List stub_keys_; + DISALLOW_COPY_AND_ASSIGN(CodeSerializer); + }; diff --git a/patches/backport.R24523.patch b/patches/backport.R24523.patch new file mode 100644 index 0000000..d8b267d --- /dev/null +++ b/patches/backport.R24523.patch @@ -0,0 +1,53 @@ +commit 6ca8f782aac4df7530d9fd460ec0fabd46628e1d +Author: yangguo@chromium.org +Date: Fri Oct 10 10:51:34 2014 +0000 + + Reset code age when serializing code objects. + + R=mvstanton@chromium.org + + Review URL: https://codereview.chromium.org/642283002 + + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24523 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/objects.cc b/src/objects.cc +index 9f25145..3eedfe9 100644 +--- node/deps/v8/src/objects.cc ++++ node/deps/v8/src/objects.cc +@@ -10463,6 +10463,12 @@ static Code::Age EffectiveAge(Code::Age age) { + } + + ++void Code::MakeYoung() { ++ byte* sequence = FindCodeAgeSequence(); ++ if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, GetIsolate()); ++} ++ ++ + void Code::MakeOlder(MarkingParity current_parity) { + byte* sequence = FindCodeAgeSequence(); + if (sequence != NULL) { +diff --git a/src/objects.h b/src/objects.h +index bcbea12..1faae86 100644 +--- node/deps/v8/src/objects.h ++++ node/deps/v8/src/objects.h +@@ -5310,6 +5310,7 @@ class Code: public HeapObject { + // compilation stub. + static void MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate); + static void MarkCodeAsExecuted(byte* sequence, Isolate* isolate); ++ void MakeYoung(); + void MakeOlder(MarkingParity); + static bool IsYoungSequence(Isolate* isolate, byte* sequence); + bool IsOld(); +diff --git a/src/serialize.cc b/src/serialize.cc +index 0cc629d..c287219 100644 +--- node/deps/v8/src/serialize.cc ++++ node/deps/v8/src/serialize.cc +@@ -1991,6 +1991,7 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, + return; + // TODO(yangguo): add special handling to canonicalize ICs. + case Code::FUNCTION: ++ code_object->MakeYoung(); + SerializeHeapObject(code_object, how_to_code, where_to_point); + return; + } diff --git a/patches/backport.R24543.patch b/patches/backport.R24543.patch new file mode 100644 index 0000000..6b95170 --- /dev/null +++ b/patches/backport.R24543.patch @@ -0,0 +1,38 @@ +commit 33dc53f9cc709862de641d32c9a412cf7cfce953 +Author: yangguo@chromium.org +Date: Mon Oct 13 07:50:21 2014 +0000 + + Always include full reloc info to stubs for serialization. + + R=mvstanton@chromium.org + + Review URL: https://codereview.chromium.org/641643006 + + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24543 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc +index 80fff3f..63488dc 100644 +--- node/deps/v8/src/code-stubs-hydrogen.cc ++++ node/deps/v8/src/code-stubs-hydrogen.cc +@@ -233,6 +233,8 @@ Handle HydrogenCodeStub::GenerateLightweightMissCode( + + // Generate the code for the stub. + masm.set_generating_stub(true); ++ // TODO(yangguo): remove this once we can serialize IC stubs. ++ masm.enable_serializer(); + NoCurrentFrameScope scope(&masm); + GenerateLightweightMiss(&masm, miss); + } +diff --git a/src/code-stubs.cc b/src/code-stubs.cc +index 357324b..9832650 100644 +--- node/deps/v8/src/code-stubs.cc ++++ node/deps/v8/src/code-stubs.cc +@@ -111,6 +111,8 @@ Handle PlatformCodeStub::GenerateCode() { + + // Generate the code for the stub. + masm.set_generating_stub(true); ++ // TODO(yangguo): remove this once we can serialize IC stubs. ++ masm.enable_serializer(); + NoCurrentFrameScope scope(&masm); + Generate(&masm); + } diff --git a/patches/backport.R24639.patch b/patches/backport.R24639.patch new file mode 100644 index 0000000..800337b --- /dev/null +++ b/patches/backport.R24639.patch @@ -0,0 +1,1062 @@ +commit 4f9fd83d854d3f9a6eb5237ca4bc41e046044e9e +Author: yangguo@chromium.org +Date: Wed Oct 15 14:04:53 2014 +0000 + + Break deserializer reservations into chunks that fit onto a page. + + R=mvstanton@chromium.org + + Review URL: https://codereview.chromium.org/653033002 + + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24639 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/compiler.cc b/src/compiler.cc +index 244ed8b..4250529 100644 +--- node/deps/v8/src/compiler.cc ++++ node/deps/v8/src/compiler.cc +@@ -1177,6 +1177,11 @@ Handle Compiler::CompileScript( + compile_options == ScriptCompiler::kConsumeCodeCache && + !isolate->debug()->is_loaded()) { +- return CodeSerializer::Deserialize(isolate, *cached_data, source); ++ Handle result; ++ if (CodeSerializer::Deserialize(isolate, *cached_data, source) ++ .ToHandle(&result)) { ++ return result; ++ } ++ // Deserializer failed. Fall through to compile. + } else { + maybe_result = compilation_cache->LookupScript( + source, script_name, line_offset, column_offset, +diff --git a/src/heap/heap.cc b/src/heap/heap.cc +index 65b3bed..7c1b2b2 100644 +--- node/deps/v8/src/heap/heap.cc ++++ node/deps/v8/src/heap/heap.cc +@@ -28,6 +28,7 @@ + #include "src/natives.h" + #include "src/runtime-profiler.h" + #include "src/scopeinfo.h" ++#include "src/serialize.h" + #include "src/snapshot.h" + #include "src/utils.h" + #include "src/v8threads.h" +@@ -919,33 +920,42 @@ static bool AbortIncrementalMarkingAndCollectGarbage( + } + + +-void Heap::ReserveSpace(int* sizes, Address* locations_out) { ++bool Heap::ReserveSpace(Reservation* reservations) { + bool gc_performed = true; + int counter = 0; + static const int kThreshold = 20; + while (gc_performed && counter++ < kThreshold) { + gc_performed = false; + for (int space = NEW_SPACE; space < Serializer::kNumberOfSpaces; space++) { +- if (sizes[space] == 0) continue; ++ Reservation* reservation = &reservations[space]; ++ DCHECK_LE(1, reservation->length()); ++ if (reservation->at(0).size == 0) continue; + bool perform_gc = false; + if (space == LO_SPACE) { +- perform_gc = !lo_space()->CanAllocateSize(sizes[space]); ++ DCHECK_EQ(1, reservation->length()); ++ perform_gc = !lo_space()->CanAllocateSize(reservation->at(0).size); + } else { +- AllocationResult allocation; +- if (space == NEW_SPACE) { +- allocation = new_space()->AllocateRaw(sizes[space]); +- } else { +- allocation = paged_space(space)->AllocateRaw(sizes[space]); +- } +- FreeListNode* node; +- if (allocation.To(&node)) { +- // Mark with a free list node, in case we have a GC before +- // deserializing. +- node->set_size(this, sizes[space]); +- DCHECK(space < Serializer::kNumberOfPreallocatedSpaces); +- locations_out[space] = node->address(); +- } else { +- perform_gc = true; ++ for (int j = 0; j < reservation->length(); j++) { ++ AllocationResult allocation; ++ Chunk& chunk = reservation->at(j); ++ int size = chunk.size; ++ if (space == NEW_SPACE) { ++ allocation = new_space()->AllocateRaw(size); ++ } else { ++ allocation = paged_space(space)->AllocateRaw(size); ++ } ++ FreeListNode* node; ++ if (allocation.To(&node)) { ++ // Mark with a free list node, in case we have a GC before ++ // deserializing. ++ node->set_size(this, size); ++ DCHECK(space < Serializer::kNumberOfPreallocatedSpaces); ++ chunk.start = node->address(); ++ chunk.end = node->address() + size; ++ } else { ++ perform_gc = true; ++ break; ++ } + } + } + if (perform_gc) { +@@ -963,10 +972,7 @@ void Heap::ReserveSpace(int* sizes, Address* locations_out) { + } + } + +- if (gc_performed) { +- // Failed to reserve the space after several attempts. +- V8::FatalProcessOutOfMemory("Heap::ReserveSpace"); +- } ++ return !gc_performed; + } + + +diff --git a/src/heap/heap.h b/src/heap/heap.h +index 7186bb6..842a2c1 100644 +--- node/deps/v8/src/heap/heap.h ++++ node/deps/v8/src/heap/heap.h +@@ -1009,7 +1009,16 @@ class Heap { + + // Support for partial snapshots. After calling this we have a linear + // space to write objects in each space. +- void ReserveSpace(int* sizes, Address* addresses); ++ struct Chunk { ++ uint32_t size; ++ Address start; ++ Address end; ++ }; ++ ++ typedef List Reservation; ++ ++ // Returns false if not able to reserve. ++ bool ReserveSpace(Reservation* reservations); + + // + // Support for the API. +diff --git a/src/list.h b/src/list.h +index ea5fd1e..c17c4ec 100644 +--- node/deps/v8/src/list.h ++++ node/deps/v8/src/list.h +@@ -80,7 +80,9 @@ class List { + + Vector ToVector() const { return Vector(data_, length_); } + +- Vector ToConstVector() { return Vector(data_, length_); } ++ Vector ToConstVector() const { ++ return Vector(data_, length_); ++ } + + // Adds a copy of the given 'element' to the end of the list, + // expanding the list if necessary. +diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc +index 58e8669..0737c9e 100644 +--- node/deps/v8/src/mksnapshot.cc ++++ node/deps/v8/src/mksnapshot.cc +@@ -91,14 +91,25 @@ class SnapshotWriter { + + i::byte* snapshot_bytes = snapshot_data.begin(); + sink.PutBlob(snapshot_bytes, snapshot_data.length(), "snapshot"); +- for (size_t i = 0; i < ARRAY_SIZE(spaces); ++i) +- sink.PutInt(serializer.CurrentAllocationAddress(spaces[i]), "spaces"); ++ for (size_t i = 0; i < ARRAY_SIZE(spaces); ++i) { ++ i::Vector chunks = ++ serializer.FinalAllocationChunks(spaces[i]); ++ // For the start-up snapshot, none of the reservations has more than ++ // one chunk (reservation for each space fits onto a single page). ++ CHECK_EQ(1, chunks.length()); ++ sink.PutInt(chunks[0], "spaces"); ++ } + + i::byte* context_bytes = context_snapshot_data.begin(); + sink.PutBlob(context_bytes, context_snapshot_data.length(), "context"); +- for (size_t i = 0; i < ARRAY_SIZE(spaces); ++i) +- sink.PutInt(context_serializer.CurrentAllocationAddress(spaces[i]), +- "spaces"); ++ for (size_t i = 0; i < ARRAY_SIZE(spaces); ++i) { ++ i::Vector chunks = ++ context_serializer.FinalAllocationChunks(spaces[i]); ++ // For the context snapshot, none of the reservations has more than ++ // one chunk (reservation for each space fits onto a single page). ++ CHECK_EQ(1, chunks.length()); ++ sink.PutInt(chunks[0], "spaces"); ++ } + + size_t written = fwrite(startup_blob.begin(), 1, startup_blob.length(), + startup_blob_file_); +@@ -203,8 +214,12 @@ class SnapshotWriter { + + void WriteSizeVar(const i::Serializer& ser, const char* prefix, + const char* name, int space) const { +- fprintf(fp_, "const int Snapshot::%s%s_space_used_ = %d;\n", +- prefix, name, ser.CurrentAllocationAddress(space)); ++ i::Vector chunks = ser.FinalAllocationChunks(space); ++ // For the start-up snapshot, none of the reservations has more than ++ // one chunk (total reservation fits into a single page). ++ CHECK_EQ(1, chunks.length()); ++ fprintf(fp_, "const int Snapshot::%s%s_space_used_ = %d;\n", prefix, name, ++ chunks[0]); + } + + void WriteSnapshotData(const i::List* data) const { +@@ -416,6 +431,9 @@ int main(int argc, char** argv) { + context_ser.Serialize(&raw_context); + ser.SerializeWeakReferences(); + ++ context_ser.FinalizeAllocation(); ++ ser.FinalizeAllocation(); ++ + { + SnapshotWriter writer(argv[1]); + if (i::FLAG_raw_file && i::FLAG_raw_context_file) +diff --git a/src/serialize.cc b/src/serialize.cc +index 42ca6b9..4c9675e 100644 +--- node/deps/v8/src/serialize.cc ++++ node/deps/v8/src/serialize.cc +@@ -598,9 +598,7 @@ Deserializer::Deserializer(SnapshotByteSource* source) + source_(source), + external_reference_decoder_(NULL), + deserialized_large_objects_(0) { +- for (int i = 0; i < kNumberOfSpaces; i++) { +- reservations_[i] = kUninitializedReservation; +- } ++ for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) current_chunk_[i] = 0; + } + + +@@ -613,10 +611,19 @@ void Deserializer::FlushICacheForNewCodeObjects() { + } + + ++bool Deserializer::ReserveSpace() { ++ if (!isolate_->heap()->ReserveSpace(reservations_)) return false; ++ for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) { ++ high_water_[i] = reservations_[i][0].start; ++ } ++ return true; ++} ++ ++ + void Deserializer::Deserialize(Isolate* isolate) { + isolate_ = isolate; + DCHECK(isolate_ != NULL); +- isolate_->heap()->ReserveSpace(reservations_, high_water_); ++ if (!ReserveSpace()) FatalProcessOutOfMemory("deserializing context"); + // No active threads. + DCHECK_EQ(NULL, isolate_->thread_manager()->FirstThreadStateInUse()); + // No active handles. +@@ -658,13 +665,17 @@ void Deserializer::Deserialize(Isolate* isolate) { + } + + +-void Deserializer::DeserializePartial(Isolate* isolate, Object** root) { ++void Deserializer::DeserializePartial(Isolate* isolate, Object** root, ++ OnOOM on_oom) { + isolate_ = isolate; + for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) { +- DCHECK(reservations_[i] != kUninitializedReservation); ++ DCHECK(reservations_[i].length() > 0); ++ } ++ if (!ReserveSpace()) { ++ if (on_oom == FATAL_ON_OOM) FatalProcessOutOfMemory("deserialize context"); ++ *root = NULL; ++ return; + } +- Heap* heap = isolate->heap(); +- heap->ReserveSpace(reservations_, high_water_); + if (external_reference_decoder_ == NULL) { + external_reference_decoder_ = new ExternalReferenceDecoder(isolate); + } +@@ -700,7 +711,7 @@ Deserializer::~Deserializer() { + void Deserializer::VisitPointers(Object** start, Object** end) { + // The space must be new space. Any other space would cause ReadChunk to try + // to update the remembered using NULL as the address. +- ReadChunk(start, end, NEW_SPACE, NULL); ++ ReadData(start, end, NEW_SPACE, NULL); + } + + +@@ -788,7 +799,7 @@ void Deserializer::ReadObject(int space_number, + if (FLAG_log_snapshot_positions) { + LOG(isolate_, SnapshotPositionEvent(address, source_->position())); + } +- ReadChunk(current, limit, space_number, address); ++ ReadData(current, limit, space_number, address); + + // TODO(mvstanton): consider treating the heap()->allocation_sites_list() + // as a (weak) root. If this root is relocated correctly, +@@ -813,6 +824,9 @@ void Deserializer::ReadObject(int space_number, + // pre-allocate that reserved space. During deserialization, all we need + // to do is to bump up the pointer for each space in the reserved + // space. This is also used for fixing back references. ++// We may have to split up the pre-allocation into several chunks ++// because it would not fit onto a single page, we have to keep track ++// of when to move to the next chunk. + // Since multiple large objects cannot be folded into one large object + // space allocation, we have to do an actual allocation when deserializing + // each large object. Instead of tracking offset for back references, we +@@ -821,7 +835,7 @@ Address Deserializer::Allocate(int space_index, int size) { + if (space_index == LO_SPACE) { + AlwaysAllocateScope scope(isolate_); + LargeObjectSpace* lo_space = isolate_->heap()->lo_space(); +- Executability exec = static_cast(source_->GetInt()); ++ Executability exec = static_cast(source_->Get()); + AllocationResult result = lo_space->AllocateRaw(size, exec); + HeapObject* obj = HeapObject::cast(result.ToObjectChecked()); + deserialized_large_objects_.Add(obj); +@@ -829,15 +843,27 @@ Address Deserializer::Allocate(int space_index, int size) { + } else { + DCHECK(space_index < kNumberOfPreallocatedSpaces); + Address address = high_water_[space_index]; ++ DCHECK_NE(NULL, address); ++ const Heap::Reservation& reservation = reservations_[space_index]; ++ int chunk_index = current_chunk_[space_index]; ++ if (address + size > reservation[chunk_index].end) { ++ // The last chunk size matches exactly the already deserialized data. ++ DCHECK_EQ(address, reservation[chunk_index].end); ++ // Move to next reserved chunk. ++ chunk_index = ++current_chunk_[space_index]; ++ DCHECK_LT(chunk_index, reservation.length()); ++ // Prepare for next allocation in the next chunk. ++ address = reservation[chunk_index].start; ++ } else { ++ high_water_[space_index] = address + size; ++ } + high_water_[space_index] = address + size; + return address; + } + } + +-void Deserializer::ReadChunk(Object** current, +- Object** limit, +- int source_space, +- Address current_object_address) { ++void Deserializer::ReadData(Object** current, Object** limit, int source_space, ++ Address current_object_address) { + Isolate* const isolate = isolate_; + // Write barrier support costs around 1% in startup time. In fact there + // are no new space objects in current boot snapshots, so it's not needed, +@@ -890,7 +916,7 @@ void Deserializer::ReadChunk(Object** current, + new_object = reinterpret_cast(address); \ + } else if (where == kBackref) { \ + emit_write_barrier = (space_number == NEW_SPACE); \ +- new_object = GetAddressFromEnd(data & kSpaceMask); \ ++ new_object = GetBackReferencedObject(data & kSpaceMask); \ + if (deserializing_user_code()) { \ + new_object = ProcessBackRefInSerializedCode(new_object); \ + } \ +@@ -913,7 +939,7 @@ void Deserializer::ReadChunk(Object** current, + current = reinterpret_cast( \ + reinterpret_cast
(current) + skip); \ + emit_write_barrier = (space_number == NEW_SPACE); \ +- new_object = GetAddressFromEnd(data & kSpaceMask); \ ++ new_object = GetBackReferencedObject(data & kSpaceMask); \ + if (deserializing_user_code()) { \ + new_object = ProcessBackRefInSerializedCode(new_object); \ + } \ +@@ -1221,7 +1247,7 @@ Serializer::Serializer(Isolate* isolate, SnapshotByteSink* sink) + seen_large_objects_index_(0) { + // The serializer is meant to be used only to generate initial heap images + // from a context in which there is only one isolate. +- for (int i = 0; i < kNumberOfSpaces; i++) fullness_[i] = 0; ++ for (int i = 0; i < kNumberOfSpaces; i++) pending_chunk_[i] = 0; + } + + +@@ -1283,6 +1309,19 @@ void Serializer::VisitPointers(Object** start, Object** end) { + } + + ++void Serializer::FinalizeAllocation() { ++ DCHECK_EQ(0, completed_chunks_[LO_SPACE].length()); // Not yet finalized. ++ for (int i = 0; i < kNumberOfSpaces; i++) { ++ // Complete the last pending chunk and if there are no completed chunks, ++ // make sure there is at least one empty chunk. ++ if (pending_chunk_[i] > 0 || completed_chunks_[i].length() == 0) { ++ completed_chunks_[i].Add(pending_chunk_[i]); ++ pending_chunk_[i] = 0; ++ } ++ } ++} ++ ++ + // This ensures that the partial snapshot cache keeps things alive during GC and + // tracks their movement. When it is called during serialization of the startup + // snapshot nothing happens. When the partial (context) snapshot is created, +@@ -1369,11 +1408,10 @@ void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object, + int index = address_mapper_.MappedTo(heap_object); + sink_->PutInt(index, "large object index"); + } else { +- int address = address_mapper_.MappedTo(heap_object); +- int offset = CurrentAllocationAddress(space) - address; ++ uint32_t existing_allocation = address_mapper_.MappedTo(heap_object); + // Shift out the bits that are always 0. +- offset >>= kObjectAlignmentBits; +- sink_->PutInt(offset, "offset"); ++ existing_allocation >>= kObjectAlignmentBits; ++ sink_->PutInt(existing_allocation, "allocation"); + } + } + +@@ -1533,15 +1571,15 @@ void Serializer::ObjectSerializer::SerializePrologue(int space, int size, + // Mark this object as already serialized. + if (space == LO_SPACE) { + if (object_->IsCode()) { +- sink_->PutInt(EXECUTABLE, "executable large object"); ++ sink_->Put(EXECUTABLE, "executable large object"); + } else { +- sink_->PutInt(NOT_EXECUTABLE, "not executable large object"); ++ sink_->Put(NOT_EXECUTABLE, "not executable large object"); + } + int index = serializer_->AllocateLargeObject(size); + serializer_->address_mapper()->AddMapping(object_, index); + } else { +- int offset = serializer_->Allocate(space, size); +- serializer_->address_mapper()->AddMapping(object_, offset); ++ int allocation = serializer_->Allocate(space, size); ++ serializer_->address_mapper()->AddMapping(object_, allocation); + } + + // Serialize the map (first word of the object). +@@ -1867,17 +1905,32 @@ int Serializer::SpaceOfObject(HeapObject* object) { + } + + +-int Serializer::AllocateLargeObject(int size) { +- fullness_[LO_SPACE] += size; ++uint32_t Serializer::AllocateLargeObject(int size) { ++ // Large objects are allocated one-by-one when deserializing. We do not ++ // have to keep track of multiple chunks. ++ pending_chunk_[LO_SPACE] += size; + return seen_large_objects_index_++; + } + + +-int Serializer::Allocate(int space, int size) { ++uint32_t Serializer::Allocate(int space, int size) { + CHECK(space >= 0 && space < kNumberOfPreallocatedSpaces); +- int allocation_address = fullness_[space]; +- fullness_[space] = allocation_address + size; +- return allocation_address; ++ DCHECK(size > 0 && size < Page::kMaxRegularHeapObjectSize); ++ uint32_t new_chunk_size = pending_chunk_[space] + size; ++ uint32_t allocation; ++ if (new_chunk_size > Page::kMaxRegularHeapObjectSize) { ++ // The new chunk size would not fit onto a single page. Complete the ++ // current chunk and start a new one. ++ completed_chunks_[space].Add(pending_chunk_[space]); ++ pending_chunk_[space] = 0; ++ new_chunk_size = size; ++ } ++ // For back-referencing, each allocation is encoded as a combination ++ // of chunk index and offset inside the chunk. ++ allocation = ChunkIndexBits::encode(completed_chunks_[space].length()) | ++ OffsetBits::encode(pending_chunk_[space]); ++ pending_chunk_[space] = new_chunk_size; ++ return allocation; + } + + +@@ -1923,6 +1976,7 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate, + Object** location = Handle::cast(info).location(); + cs.VisitPointer(location); + cs.Pad(); ++ cs.FinalizeAllocation(); + + SerializedCodeData data(&payload, &cs); + ScriptData* script_data = data.GetScriptData(); +@@ -2093,9 +2147,8 @@ void CodeSerializer::SerializeSourceObject(HowToCode how_to_code, + } + + +-Handle CodeSerializer::Deserialize(Isolate* isolate, +- ScriptData* data, +- Handle source) { ++MaybeHandle CodeSerializer::Deserialize( ++ Isolate* isolate, ScriptData* data, Handle source) { + base::ElapsedTimer timer; + if (FLAG_profile_deserialization) timer.Start(); + +@@ -2107,10 +2160,15 @@ Handle CodeSerializer::Deserialize(Isolate* isolate, + SerializedCodeData scd(data, *source); + SnapshotByteSource payload(scd.Payload(), scd.PayloadLength()); + Deserializer deserializer(&payload); ++ + STATIC_ASSERT(NEW_SPACE == 0); +- for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) { +- deserializer.set_reservation(i, scd.GetReservation(i)); ++ int current_space = NEW_SPACE; ++ Vector res = scd.Reservations(); ++ for (int j = 0; j < res.length(); j++) { ++ deserializer.AddReservation(current_space, res[j].chunk_size()); ++ if (res[j].is_last_chunk()) current_space++; + } ++ DCHECK_EQ(kNumberOfSpaces, current_space); + + // Prepare and register list of attached objects. + Vector code_stub_keys = scd.CodeStubKeys(); +@@ -2124,7 +2182,12 @@ Handle CodeSerializer::Deserialize(Isolate* isolate, + deserializer.SetAttachedObjects(&attached_objects); + + // Deserialize. +- deserializer.DeserializePartial(isolate, &root); ++ deserializer.DeserializePartial(isolate, &root, Deserializer::NULL_ON_OOM); ++ if (root == NULL) { ++ // Deserializing may fail if the reservations cannot be fulfilled. ++ if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n"); ++ return MaybeHandle(); ++ } + deserializer.FlushICacheForNewCodeObjects(); + } + +@@ -2144,10 +2207,25 @@ SerializedCodeData::SerializedCodeData(List* payload, CodeSerializer* cs) + DisallowHeapAllocation no_gc; + List* stub_keys = cs->stub_keys(); + ++ // Gather reservation chunk sizes. ++ List reservations(SerializerDeserializer::kNumberOfSpaces); ++ STATIC_ASSERT(NEW_SPACE == 0); ++ for (int i = 0; i < SerializerDeserializer::kNumberOfSpaces; i++) { ++ Vector chunks = cs->FinalAllocationChunks(i); ++ for (int j = 0; j < chunks.length(); j++) { ++ DCHECK(i == LO_SPACE || chunks[j] < Page::kMaxRegularHeapObjectSize); ++ uint32_t chunk = ChunkSizeBits::encode(chunks[j]) | ++ IsLastChunkBits::encode(j == chunks.length() - 1); ++ reservations.Add(chunk); ++ } ++ } ++ + // Calculate sizes. ++ int reservation_size = reservations.length() * kInt32Size; + int num_stub_keys = stub_keys->length(); + int stub_keys_size = stub_keys->length() * kInt32Size; +- int data_length = kHeaderSize + stub_keys_size + payload->length(); ++ int data_length = ++ kHeaderSize + reservation_size + stub_keys_size + payload->length(); + + // Allocate backing store and create result data. + byte* data = NewArray(data_length); +@@ -2157,20 +2235,21 @@ SerializedCodeData::SerializedCodeData(List* payload, CodeSerializer* cs) + + // Set header values. + SetHeaderValue(kCheckSumOffset, CheckSum(cs->source())); ++ SetHeaderValue(kReservationsOffset, reservations.length()); + SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys); + SetHeaderValue(kPayloadLengthOffset, payload->length()); +- STATIC_ASSERT(NEW_SPACE == 0); +- for (int i = 0; i < SerializerDeserializer::kNumberOfSpaces; i++) { +- SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i)); +- } ++ ++ // Copy reservation chunk sizes. ++ CopyBytes(data + kHeaderSize, reinterpret_cast(reservations.begin()), ++ reservation_size); + + // Copy code stub keys. +- CopyBytes(data + kHeaderSize, reinterpret_cast(stub_keys->begin()), +- stub_keys_size); ++ CopyBytes(data + kHeaderSize + reservation_size, ++ reinterpret_cast(stub_keys->begin()), stub_keys_size); + + // Copy serialized data. +- CopyBytes(data + kHeaderSize + stub_keys_size, payload->begin(), +- static_cast(payload->length())); ++ CopyBytes(data + kHeaderSize + reservation_size + stub_keys_size, ++ payload->begin(), static_cast(payload->length())); + } + + +diff --git a/src/serialize.h b/src/serialize.h +index 6fa7a34..6e1f651 100644 +--- node/deps/v8/src/serialize.h ++++ node/deps/v8/src/serialize.h +@@ -152,6 +152,11 @@ class SerializerDeserializer: public ObjectVisitor { + static const int kNumberOfPreallocatedSpaces = LO_SPACE; + static const int kNumberOfSpaces = INVALID_SPACE; + ++ // To encode object for back-references. ++ class OffsetBits : public BitField {}; ++ class ChunkIndexBits ++ : public BitField {}; ++ + protected: + // Where the pointed-to object can be found: + enum Where { +@@ -248,13 +253,18 @@ class Deserializer: public SerializerDeserializer { + // Deserialize the snapshot into an empty heap. + void Deserialize(Isolate* isolate); + ++ enum OnOOM { FATAL_ON_OOM, NULL_ON_OOM }; ++ + // Deserialize a single object and the objects reachable from it. +- void DeserializePartial(Isolate* isolate, Object** root); ++ // We may want to abort gracefully even if deserialization fails. ++ void DeserializePartial(Isolate* isolate, Object** root, ++ OnOOM on_oom = FATAL_ON_OOM); + +- void set_reservation(int space_number, int reservation) { +- DCHECK(space_number >= 0); +- DCHECK(space_number < kNumberOfSpaces); +- reservations_[space_number] = reservation; ++ void AddReservation(int space, uint32_t chunk) { ++ DCHECK(space >= 0); ++ DCHECK(space < kNumberOfSpaces); ++ DCHECK(space == LO_SPACE || chunk < Page::kMaxRegularHeapObjectSize); ++ Heap::Chunk c = { chunk, NULL, NULL }; reservations_[space].Add(c); + } + + void FlushICacheForNewCodeObjects(); +@@ -274,6 +284,8 @@ class Deserializer: public SerializerDeserializer { + UNREACHABLE(); + } + ++ bool ReserveSpace(); ++ + // Allocation sites are present in the snapshot, and must be linked into + // a list at deserialization time. + void RelinkAllocationSite(AllocationSite* site); +@@ -283,8 +295,8 @@ class Deserializer: public SerializerDeserializer { + // of the object we are writing into, or NULL if we are not writing into an + // object, i.e. if we are writing a series of tagged values that are not on + // the heap. +- void ReadChunk( +- Object** start, Object** end, int space, Address object_address); ++ void ReadData(Object** start, Object** end, int space, ++ Address object_address); + void ReadObject(int space_number, Object** write_back); + Address Allocate(int space_index, int size); + +@@ -293,13 +305,20 @@ class Deserializer: public SerializerDeserializer { + Object* ProcessBackRefInSerializedCode(Object* obj); + + // This returns the address of an object that has been described in the +- // snapshot as being offset bytes back in a particular space. +- HeapObject* GetAddressFromEnd(int space) { +- int offset = source_->GetInt(); +- if (space == LO_SPACE) return deserialized_large_objects_[offset]; +- DCHECK(space < kNumberOfPreallocatedSpaces); +- offset <<= kObjectAlignmentBits; +- return HeapObject::FromAddress(high_water_[space] - offset); ++ // snapshot by chunk index and offset. ++ HeapObject* GetBackReferencedObject(int space) { ++ if (space == LO_SPACE) { ++ uint32_t index = source_->GetInt(); ++ return deserialized_large_objects_[index]; ++ } else { ++ uint32_t allocation = source_->GetInt() << kObjectAlignmentBits; ++ DCHECK(space < kNumberOfPreallocatedSpaces); ++ uint32_t chunk_index = ChunkIndexBits::decode(allocation); ++ uint32_t offset = OffsetBits::decode(allocation); ++ DCHECK_LE(chunk_index, current_chunk_[space]); ++ return HeapObject::FromAddress(reservations_[space][chunk_index].start + ++ offset); ++ } + } + + // Cached current isolate. +@@ -309,13 +328,14 @@ class Deserializer: public SerializerDeserializer { + Vector >* attached_objects_; + + SnapshotByteSource* source_; +- // This is the address of the next object that will be allocated in each +- // space. It is used to calculate the addresses of back-references. ++ // The address of the next object that will be allocated in each space. ++ // Each space has a number of chunks reserved by the GC, with each chunk ++ // fitting into a page. Deserialized objects are allocated into the ++ // current chunk of the target space by bumping up high water mark. ++ Heap::Reservation reservations_[kNumberOfSpaces]; ++ uint32_t current_chunk_[kNumberOfPreallocatedSpaces]; + Address high_water_[kNumberOfPreallocatedSpaces]; + +- int reservations_[kNumberOfSpaces]; +- static const intptr_t kUninitializedReservation = -1; +- + ExternalReferenceDecoder* external_reference_decoder_; + + List deserialized_large_objects_; +@@ -380,11 +400,13 @@ class Serializer : public SerializerDeserializer { + Serializer(Isolate* isolate, SnapshotByteSink* sink); + ~Serializer(); + void VisitPointers(Object** start, Object** end); +- // You can call this after serialization to find out how much space was used +- // in each space. +- int CurrentAllocationAddress(int space) const { +- DCHECK(space < kNumberOfSpaces); +- return fullness_[space]; ++ ++ void FinalizeAllocation(); ++ ++ Vector FinalAllocationChunks(int space) const { ++ DCHECK_EQ(1, completed_chunks_[LO_SPACE].length()); // Already finalized. ++ DCHECK_EQ(0, pending_chunk_[space]); // No pending chunks. ++ return completed_chunks_[space].ToConstVector(); + } + + Isolate* isolate() const { return isolate_; } +@@ -470,8 +492,8 @@ class Serializer : public SerializerDeserializer { + void InitializeAllocators(); + // This will return the space for an object. + static int SpaceOfObject(HeapObject* object); +- int AllocateLargeObject(int size); +- int Allocate(int space, int size); ++ uint32_t AllocateLargeObject(int size); ++ uint32_t Allocate(int space, int size); + int EncodeExternalReference(Address addr) { + return external_reference_encoder_->Encode(addr); + } +@@ -483,9 +505,14 @@ class Serializer : public SerializerDeserializer { + bool ShouldBeSkipped(Object** current); + + Isolate* isolate_; +- // Keep track of the fullness of each space in order to generate +- // relative addresses for back references. +- int fullness_[kNumberOfSpaces]; ++ ++ // Objects from the same space are put into chunks for bulk-allocation ++ // when deserializing. We have to make sure that each chunk fits into a ++ // page. So we track the chunk size in pending_chunk_ of a space, but ++ // when it exceeds a page, we complete the current chunk and start a new one. ++ uint32_t pending_chunk_[kNumberOfSpaces]; ++ List completed_chunks_[kNumberOfSpaces]; ++ + SnapshotByteSink* sink_; + ExternalReferenceEncoder* external_reference_encoder_; + +@@ -503,7 +530,7 @@ class Serializer : public SerializerDeserializer { + private: + CodeAddressMap* code_address_map_; + // We map serialized large objects to indexes for back-referencing. +- int seen_large_objects_index_; ++ uint32_t seen_large_objects_index_; + DISALLOW_COPY_AND_ASSIGN(Serializer); + }; + +@@ -585,9 +612,8 @@ class CodeSerializer : public Serializer { + Handle info, + Handle source); + +- static Handle Deserialize(Isolate* isolate, +- ScriptData* data, +- Handle source); ++ MUST_USE_RESULT static MaybeHandle Deserialize( ++ Isolate* isolate, ScriptData* data, Handle source); + + static const int kSourceObjectIndex = 0; + static const int kCodeStubsBaseIndex = 1; +@@ -654,15 +680,35 @@ class SerializedCodeData { + return result; + } + ++ class Reservation { ++ public: ++ uint32_t chunk_size() const { return ChunkSizeBits::decode(reservation); } ++ bool is_last_chunk() const { return IsLastChunkBits::decode(reservation); } ++ ++ private: ++ uint32_t reservation; ++ ++ DISALLOW_COPY_AND_ASSIGN(Reservation); ++ }; ++ ++ Vector Reservations() const { ++ return Vector(reinterpret_cast( ++ script_data_->data() + kHeaderSize), ++ GetHeaderValue(kReservationsOffset)); ++ } ++ + Vector CodeStubKeys() const { +- return Vector( +- reinterpret_cast(script_data_->data() + kHeaderSize), +- GetHeaderValue(kNumCodeStubKeysOffset)); ++ int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size; ++ const byte* start = script_data_->data() + kHeaderSize + reservations_size; ++ return Vector(reinterpret_cast(start), ++ GetHeaderValue(kNumCodeStubKeysOffset)); + } + + const byte* Payload() const { ++ int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size; + int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size; +- return script_data_->data() + kHeaderSize + code_stubs_size; ++ return script_data_->data() + kHeaderSize + reservations_size + ++ code_stubs_size; + } + + int PayloadLength() const { +@@ -672,10 +718,6 @@ class SerializedCodeData { + return payload_length; + } + +- int GetReservation(int space) const { +- return GetHeaderValue(kReservationsOffset + space); +- } +- + private: + void SetHeaderValue(int offset, int value) { + reinterpret_cast(const_cast(script_data_->data()))[offset] = +@@ -696,13 +738,13 @@ class SerializedCodeData { + // [2] payload length + // [3..9] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE. + static const int kCheckSumOffset = 0; +- static const int kNumCodeStubKeysOffset = 1; +- static const int kPayloadLengthOffset = 2; +- static const int kReservationsOffset = 3; ++ static const int kReservationsOffset = 1; ++ static const int kNumCodeStubKeysOffset = 2; ++ static const int kPayloadLengthOffset = 3; ++ static const int kHeaderSize = (kPayloadLengthOffset + 1) * kIntSize; + +- static const int kHeaderEntries = +- kReservationsOffset + SerializerDeserializer::kNumberOfSpaces; +- static const int kHeaderSize = kHeaderEntries * kIntSize; ++ class ChunkSizeBits : public BitField {}; ++ class IsLastChunkBits : public BitField {}; + + // Following the header, we store, in sequential order + // - code stub keys +diff --git a/src/snapshot-common.cc b/src/snapshot-common.cc +index 4e90ce1..b152ad3 100644 +--- node/deps/v8/src/snapshot-common.cc ++++ node/deps/v8/src/snapshot-common.cc +@@ -15,14 +15,14 @@ namespace v8 { + namespace internal { + + void Snapshot::ReserveSpaceForLinkedInSnapshot(Deserializer* deserializer) { +- deserializer->set_reservation(NEW_SPACE, new_space_used_); +- deserializer->set_reservation(OLD_POINTER_SPACE, pointer_space_used_); +- deserializer->set_reservation(OLD_DATA_SPACE, data_space_used_); +- deserializer->set_reservation(CODE_SPACE, code_space_used_); +- deserializer->set_reservation(MAP_SPACE, map_space_used_); +- deserializer->set_reservation(CELL_SPACE, cell_space_used_); +- deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_space_used_); +- deserializer->set_reservation(LO_SPACE, lo_space_used_); ++ deserializer->AddReservation(NEW_SPACE, new_space_used_); ++ deserializer->AddReservation(OLD_POINTER_SPACE, pointer_space_used_); ++ deserializer->AddReservation(OLD_DATA_SPACE, data_space_used_); ++ deserializer->AddReservation(CODE_SPACE, code_space_used_); ++ deserializer->AddReservation(MAP_SPACE, map_space_used_); ++ deserializer->AddReservation(CELL_SPACE, cell_space_used_); ++ deserializer->AddReservation(PROPERTY_CELL_SPACE, property_cell_space_used_); ++ deserializer->AddReservation(LO_SPACE, lo_space_used_); + } + + +@@ -59,15 +59,15 @@ Handle Snapshot::NewContextFromSnapshot(Isolate* isolate) { + context_raw_size_); + Deserializer deserializer(&source); + Object* root; +- deserializer.set_reservation(NEW_SPACE, context_new_space_used_); +- deserializer.set_reservation(OLD_POINTER_SPACE, context_pointer_space_used_); +- deserializer.set_reservation(OLD_DATA_SPACE, context_data_space_used_); +- deserializer.set_reservation(CODE_SPACE, context_code_space_used_); +- deserializer.set_reservation(MAP_SPACE, context_map_space_used_); +- deserializer.set_reservation(CELL_SPACE, context_cell_space_used_); +- deserializer.set_reservation(PROPERTY_CELL_SPACE, +- context_property_cell_space_used_); +- deserializer.set_reservation(LO_SPACE, context_lo_space_used_); ++ deserializer.AddReservation(NEW_SPACE, context_new_space_used_); ++ deserializer.AddReservation(OLD_POINTER_SPACE, context_pointer_space_used_); ++ deserializer.AddReservation(OLD_DATA_SPACE, context_data_space_used_); ++ deserializer.AddReservation(CODE_SPACE, context_code_space_used_); ++ deserializer.AddReservation(MAP_SPACE, context_map_space_used_); ++ deserializer.AddReservation(CELL_SPACE, context_cell_space_used_); ++ deserializer.AddReservation(PROPERTY_CELL_SPACE, ++ context_property_cell_space_used_); ++ deserializer.AddReservation(LO_SPACE, context_lo_space_used_); + deserializer.DeserializePartial(isolate, &root); + CHECK(root->IsContext()); + return Handle(Context::cast(root)); +diff --git a/src/snapshot-external.cc b/src/snapshot-external.cc +index 9b8bc1b..838e93f 100644 +--- node/deps/v8/src/snapshot-external.cc ++++ node/deps/v8/src/snapshot-external.cc +@@ -58,17 +58,17 @@ bool Snapshot::Initialize(Isolate* isolate) { + } + SnapshotByteSource source(snapshot_impl_->data, snapshot_impl_->size); + Deserializer deserializer(&source); +- deserializer.set_reservation(NEW_SPACE, snapshot_impl_->new_space_used); +- deserializer.set_reservation(OLD_POINTER_SPACE, +- snapshot_impl_->pointer_space_used); +- deserializer.set_reservation(OLD_DATA_SPACE, +- snapshot_impl_->data_space_used); +- deserializer.set_reservation(CODE_SPACE, snapshot_impl_->code_space_used); +- deserializer.set_reservation(MAP_SPACE, snapshot_impl_->map_space_used); +- deserializer.set_reservation(CELL_SPACE, snapshot_impl_->cell_space_used); +- deserializer.set_reservation(PROPERTY_CELL_SPACE, +- snapshot_impl_->property_cell_space_used); +- deserializer.set_reservation(LO_SPACE, snapshot_impl_->lo_space_used); ++ deserializer.AddReservation(NEW_SPACE, snapshot_impl_->new_space_used); ++ deserializer.AddReservation(OLD_POINTER_SPACE, ++ snapshot_impl_->pointer_space_used); ++ deserializer.AddReservation(OLD_DATA_SPACE, ++ snapshot_impl_->data_space_used); ++ deserializer.AddReservation(CODE_SPACE, snapshot_impl_->code_space_used); ++ deserializer.AddReservation(MAP_SPACE, snapshot_impl_->map_space_used); ++ deserializer.AddReservation(CELL_SPACE, snapshot_impl_->cell_space_used); ++ deserializer.AddReservation(PROPERTY_CELL_SPACE, ++ snapshot_impl_->property_cell_space_used); ++ deserializer.AddReservation(LO_SPACE, snapshot_impl_->lo_space_used); + bool success = V8::Initialize(&deserializer); + if (FLAG_profile_deserialization) { + double ms = timer.Elapsed().InMillisecondsF(); +@@ -85,22 +84,21 @@ Handle Snapshot::NewContextFromSnapshot(Isolate* isolate) { + SnapshotByteSource source(snapshot_impl_->context_data, + snapshot_impl_->context_size); + Deserializer deserializer(&source); +- deserializer.set_reservation(NEW_SPACE, +- snapshot_impl_->context_new_space_used); +- deserializer.set_reservation(OLD_POINTER_SPACE, +- snapshot_impl_->context_pointer_space_used); +- deserializer.set_reservation(OLD_DATA_SPACE, +- snapshot_impl_->context_data_space_used); +- deserializer.set_reservation(CODE_SPACE, +- snapshot_impl_->context_code_space_used); +- deserializer.set_reservation(MAP_SPACE, +- snapshot_impl_->context_map_space_used); +- deserializer.set_reservation(CELL_SPACE, +- snapshot_impl_->context_cell_space_used); +- deserializer.set_reservation(PROPERTY_CELL_SPACE, +- snapshot_impl_-> +- context_property_cell_space_used); +- deserializer.set_reservation(LO_SPACE, snapshot_impl_->context_lo_space_used); ++ deserializer.AddReservation(NEW_SPACE, ++ snapshot_impl_->context_new_space_used); ++ deserializer.AddReservation(OLD_POINTER_SPACE, ++ snapshot_impl_->context_pointer_space_used); ++ deserializer.AddReservation(OLD_DATA_SPACE, ++ snapshot_impl_->context_data_space_used); ++ deserializer.AddReservation(CODE_SPACE, ++ snapshot_impl_->context_code_space_used); ++ deserializer.AddReservation(MAP_SPACE, ++ snapshot_impl_->context_map_space_used); ++ deserializer.AddReservation(CELL_SPACE, ++ snapshot_impl_->context_cell_space_used); ++ deserializer.AddReservation(PROPERTY_CELL_SPACE, ++ snapshot_impl_->context_property_cell_space_used); ++ deserializer.AddReservation(LO_SPACE, snapshot_impl_->context_lo_space_used); + Object* root; + deserializer.DeserializePartial(isolate, &root); + CHECK(root->IsContext()); +diff --git a/src/vector.h b/src/vector.h +index d3ba775..a4fdb10 100644 +--- node/deps/v8/src/vector.h ++++ node/deps/v8/src/vector.h +@@ -58,6 +58,10 @@ class Vector { + + T& last() { return start_[length_ - 1]; } + ++ typedef T* iterator; ++ inline iterator begin() const { return &start_[0]; } ++ inline iterator end() const { return &start_[length_]; } ++ + // Returns a clone of this vector with a new backing store. + Vector Clone() const { + T* result = NewArray(length_); +diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc +index 8ba5c79..15c587b 100644 +--- node/deps/v8/test/cctest/test-serialize.cc ++++ node/deps/v8/test/cctest/test-serialize.cc +@@ -137,10 +137,7 @@ class FileByteSink : public SnapshotByteSink { + virtual int Position() { + return ftell(fp_); + } +- void WriteSpaceUsed(int new_space_used, int pointer_space_used, +- int data_space_used, int code_space_used, +- int map_space_used, int cell_space_used, +- int property_cell_space_used, int lo_space_used); ++ void WriteSpaceUsed(Serializer* serializer); + + private: + FILE* fp_; +@@ -148,24 +145,37 @@ class FileByteSink : public SnapshotByteSink { + }; + + +-void FileByteSink::WriteSpaceUsed(int new_space_used, int pointer_space_used, +- int data_space_used, int code_space_used, +- int map_space_used, int cell_space_used, +- int property_cell_space_used, +- int lo_space_used) { ++void FileByteSink::WriteSpaceUsed(Serializer* ser) { + int file_name_length = StrLength(file_name_) + 10; + Vector name = Vector::New(file_name_length + 1); + 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); +- fprintf(fp, "data %d\n", data_space_used); +- 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, "property cell %d\n", property_cell_space_used); +- fprintf(fp, "lo %d\n", lo_space_used); ++ ++ Vector chunks = ser->FinalAllocationChunks(NEW_SPACE); ++ CHECK_EQ(1, chunks.length()); ++ fprintf(fp, "new %d\n", chunks[0]); ++ chunks = ser->FinalAllocationChunks(OLD_POINTER_SPACE); ++ CHECK_EQ(1, chunks.length()); ++ fprintf(fp, "pointer %d\n", chunks[0]); ++ chunks = ser->FinalAllocationChunks(OLD_DATA_SPACE); ++ CHECK_EQ(1, chunks.length()); ++ fprintf(fp, "data %d\n", chunks[0]); ++ chunks = ser->FinalAllocationChunks(CODE_SPACE); ++ CHECK_EQ(1, chunks.length()); ++ fprintf(fp, "code %d\n", chunks[0]); ++ chunks = ser->FinalAllocationChunks(MAP_SPACE); ++ CHECK_EQ(1, chunks.length()); ++ fprintf(fp, "map %d\n", chunks[0]); ++ chunks = ser->FinalAllocationChunks(CELL_SPACE); ++ CHECK_EQ(1, chunks.length()); ++ fprintf(fp, "cell %d\n", chunks[0]); ++ chunks = ser->FinalAllocationChunks(PROPERTY_CELL_SPACE); ++ CHECK_EQ(1, chunks.length()); ++ fprintf(fp, "property cell %d\n", chunks[0]); ++ chunks = ser->FinalAllocationChunks(LO_SPACE); ++ CHECK_EQ(1, chunks.length()); ++ fprintf(fp, "lo %d\n", chunks[0]); + fclose(fp); + } + +@@ -174,15 +184,9 @@ static bool WriteToFile(Isolate* isolate, const char* snapshot_file) { + FileByteSink file(snapshot_file); + StartupSerializer ser(isolate, &file); + ser.Serialize(); ++ ser.FinalizeAllocation(); + +- 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), +- ser.CurrentAllocationAddress(LO_SPACE)); ++ file.WriteSpaceUsed(&ser); + + return true; + } +@@ -258,14 +262,14 @@ static void ReserveSpaceForSnapshot(Deserializer* deserializer, + #undef fscanf + #endif + fclose(fp); +- 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); +- deserializer->set_reservation(LO_SPACE, lo_size); ++ deserializer->AddReservation(NEW_SPACE, new_size); ++ deserializer->AddReservation(OLD_POINTER_SPACE, pointer_size); ++ deserializer->AddReservation(OLD_DATA_SPACE, data_size); ++ deserializer->AddReservation(CODE_SPACE, code_size); ++ deserializer->AddReservation(MAP_SPACE, map_size); ++ deserializer->AddReservation(CELL_SPACE, cell_size); ++ deserializer->AddReservation(PROPERTY_CELL_SPACE, property_cell_size); ++ deserializer->AddReservation(LO_SPACE, lo_size); + } + + diff --git a/patches/backport.R24642.patch b/patches/backport.R24642.patch new file mode 100644 index 0000000..9287231 --- /dev/null +++ b/patches/backport.R24642.patch @@ -0,0 +1,25 @@ +commit d7acb9148b6407526c257eceaec16c358655a3d5 +Author: jkummerow@chromium.org +Date: Wed Oct 15 14:27:26 2014 +0000 + + Fix compilation after r24639 + + TBR=yangguo@chromium.org + + Review URL: https://codereview.chromium.org/661473002 + + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24642 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/serialize.cc b/src/serialize.cc +index 4c9675e..b980940 100644 +--- node/deps/v8/src/serialize.cc ++++ node/deps/v8/src/serialize.cc +@@ -1918,7 +1918,7 @@ uint32_t Serializer::Allocate(int space, int size) { + DCHECK(size > 0 && size < Page::kMaxRegularHeapObjectSize); + uint32_t new_chunk_size = pending_chunk_[space] + size; + uint32_t allocation; +- if (new_chunk_size > Page::kMaxRegularHeapObjectSize) { ++ if (new_chunk_size > static_cast(Page::kMaxRegularHeapObjectSize)) { + // The new chunk size would not fit onto a single page. Complete the + // current chunk and start a new one. + completed_chunks_[space].Add(pending_chunk_[space]); diff --git a/patches/backport.R24643.patch b/patches/backport.R24643.patch new file mode 100644 index 0000000..7489233 --- /dev/null +++ b/patches/backport.R24643.patch @@ -0,0 +1,26 @@ +commit 2577d6c261da26d6fbc97669a3ef8f4b61027c7e +Author: sigurds@chromium.org +Date: Wed Oct 15 14:42:32 2014 +0000 + + Fix compilation after r24639 + + TBR=yangguo@chromium.org + + Review URL: https://codereview.chromium.org/653353003 + + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24643 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/serialize.h b/src/serialize.h +index 6e1f651..482bc34 100644 +--- node/deps/v8/src/serialize.h ++++ node/deps/v8/src/serialize.h +@@ -263,7 +263,8 @@ class Deserializer: public SerializerDeserializer { + void AddReservation(int space, uint32_t chunk) { + DCHECK(space >= 0); + DCHECK(space < kNumberOfSpaces); +- DCHECK(space == LO_SPACE || chunk < Page::kMaxRegularHeapObjectSize); ++ DCHECK(space == LO_SPACE || ++ chunk < static_cast(Page::kMaxRegularHeapObjectSize)); + Heap::Chunk c = { chunk, NULL, NULL }; reservations_[space].Add(c); + } + diff --git a/patches/backport.R24644.patch b/patches/backport.R24644.patch new file mode 100644 index 0000000..945533e --- /dev/null +++ b/patches/backport.R24644.patch @@ -0,0 +1,29 @@ +commit 8949d5f58002c5d058064e9047a6247119e725bf +Author: jkummerow@chromium.org +Date: Wed Oct 15 15:04:09 2014 +0000 + + Fix compilation some more after r24639 + + Third time's a charm... + + TBR=yangguo@chromium.org + + Review URL: https://codereview.chromium.org/655223003 + + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24644 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/serialize.cc b/src/serialize.cc +index b980940..4933a19 100644 +--- node/deps/v8/src/serialize.cc ++++ node/deps/v8/src/serialize.cc +@@ -2213,7 +2213,9 @@ SerializedCodeData::SerializedCodeData(List* payload, CodeSerializer* cs) + for (int i = 0; i < SerializerDeserializer::kNumberOfSpaces; i++) { + Vector chunks = cs->FinalAllocationChunks(i); + for (int j = 0; j < chunks.length(); j++) { +- DCHECK(i == LO_SPACE || chunks[j] < Page::kMaxRegularHeapObjectSize); ++ DCHECK(i == LO_SPACE || ++ chunks[j] < ++ static_cast(Page::kMaxRegularHeapObjectSize)); + uint32_t chunk = ChunkSizeBits::encode(chunks[j]) | + IsLastChunkBits::encode(j == chunks.length() - 1); + reservations.Add(chunk); diff --git a/patches/backport.R24824.patch b/patches/backport.R24824.patch new file mode 100644 index 0000000..52dd02c --- /dev/null +++ b/patches/backport.R24824.patch @@ -0,0 +1,177 @@ +commit 7753ace1354ac231374da0446a5057b6b40780db +Author: yangguo@chromium.org +Date: Thu Oct 23 08:25:42 2014 +0000 + + Small fixes for the code serializer. + - assertions regarding max heap object size. + - ensure string table capacity upfront. + + R=mvstanton@chromium.org + + Review URL: https://codereview.chromium.org/671843003 + + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24824 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/objects.cc b/src/objects.cc +index 2685a5c..371931c 100644 +--- node/deps/v8/src/objects.cc ++++ node/deps/v8/src/objects.cc +@@ -14769,6 +14769,16 @@ MaybeHandle StringTable::LookupTwoCharsStringIfExists( + } + + ++void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, ++ int expected) { ++ Handle table = isolate->factory()->string_table(); ++ // We need a key instance for the virtual hash function. ++ InternalizedStringKey dummy_key(Handle::null()); ++ table = StringTable::EnsureCapacity(table, expected, &dummy_key); ++ isolate->factory()->set_string_table(table); ++} ++ ++ + Handle StringTable::LookupString(Isolate* isolate, + Handle string) { + InternalizedStringKey key(string); +diff --git a/src/objects.h b/src/objects.h +index 7e509e7..b2b64c2 100644 +--- node/deps/v8/src/objects.h ++++ node/deps/v8/src/objects.h +@@ -3446,6 +3446,8 @@ class StringTable: public HashTable= 0 && space < kNumberOfPreallocatedSpaces); +- DCHECK(size > 0 && size < Page::kMaxRegularHeapObjectSize); ++ DCHECK(size > 0 && size <= Page::kMaxRegularHeapObjectSize); + uint32_t new_chunk_size = pending_chunk_[space] + size; + uint32_t allocation; + if (new_chunk_size > static_cast(Page::kMaxRegularHeapObjectSize)) { +@@ -2081,6 +2084,8 @@ void CodeSerializer::SerializeHeapObject(HeapObject* heap_object, + PrintF("\n"); + } + ++ if (heap_object->IsInternalizedString()) num_internalized_strings_++; ++ + // Object has not yet been serialized. Serialize it here. + ObjectSerializer serializer(this, heap_object, sink_, how_to_code, + where_to_point); +@@ -2201,6 +2206,11 @@ MaybeHandle CodeSerializer::Deserialize( + SnapshotByteSource payload(scd.Payload(), scd.PayloadLength()); + Deserializer deserializer(&payload); + ++ // Eagerly expand string table to avoid allocations during deserialization. ++ StringTable::EnsureCapacityForDeserialization(isolate, ++ scd.NumInternalizedStrings()); ++ ++ // Set reservations. + STATIC_ASSERT(NEW_SPACE == 0); + int current_space = NEW_SPACE; + Vector res = scd.Reservations(); +@@ -2254,7 +2264,7 @@ SerializedCodeData::SerializedCodeData(List* payload, CodeSerializer* cs) + Vector chunks = cs->FinalAllocationChunks(i); + for (int j = 0; j < chunks.length(); j++) { + DCHECK(i == LO_SPACE || +- chunks[j] < ++ chunks[j] <= + static_cast(Page::kMaxRegularHeapObjectSize)); + uint32_t chunk = ChunkSizeBits::encode(chunks[j]) | + IsLastChunkBits::encode(j == chunks.length() - 1); +@@ -2277,6 +2287,7 @@ SerializedCodeData::SerializedCodeData(List* payload, CodeSerializer* cs) + + // Set header values. + SetHeaderValue(kCheckSumOffset, CheckSum(cs->source())); ++ SetHeaderValue(kNumInternalizedStringsOffset, cs->num_internalized_strings()); + SetHeaderValue(kReservationsOffset, reservations.length()); + SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys); + SetHeaderValue(kPayloadLengthOffset, payload->length()); +diff --git a/src/serialize.h b/src/serialize.h +index 47a244f..df6723c 100644 +--- node/deps/v8/src/serialize.h ++++ node/deps/v8/src/serialize.h +@@ -264,7 +264,7 @@ class Deserializer: public SerializerDeserializer { + DCHECK(space >= 0); + DCHECK(space < kNumberOfSpaces); + DCHECK(space == LO_SPACE || +- chunk < static_cast(Page::kMaxRegularHeapObjectSize)); ++ chunk <= static_cast(Page::kMaxRegularHeapObjectSize)); + Heap::Chunk c = { chunk, NULL, NULL }; reservations_[space].Add(c); + } + +@@ -619,17 +619,21 @@ class CodeSerializer : public Serializer { + static const int kSourceObjectIndex = 0; + static const int kCodeStubsBaseIndex = 1; + +- String* source() { ++ String* source() const { + DCHECK(!AllowHeapAllocation::IsAllowed()); + return source_; + } + + List* stub_keys() { return &stub_keys_; } ++ int num_internalized_strings() const { return num_internalized_strings_; } + + private: + CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source, + Code* main_code) +- : Serializer(isolate, sink), source_(source), main_code_(main_code) { ++ : Serializer(isolate, sink), ++ source_(source), ++ main_code_(main_code), ++ num_internalized_strings_(0) { + set_root_index_wave_front(Heap::kStrongRootListLength); + InitializeCodeAddressMap(); + } +@@ -652,6 +656,7 @@ class CodeSerializer : public Serializer { + DisallowHeapAllocation no_gc_; + String* source_; + Code* main_code_; ++ int num_internalized_strings_; + List stub_keys_; + DISALLOW_COPY_AND_ASSIGN(CodeSerializer); + }; +@@ -694,6 +699,10 @@ class SerializedCodeData { + DISALLOW_COPY_AND_ASSIGN(Reservation); + }; + ++ int NumInternalizedStrings() const { ++ return GetHeaderValue(kNumInternalizedStringsOffset); ++ } ++ + Vector Reservations() const { + return Vector(reinterpret_cast( + script_data_->data() + kHeaderSize), +@@ -737,13 +746,15 @@ class SerializedCodeData { + + // The data header consists of int-sized entries: + // [0] version hash +- // [1] number of code stub keys +- // [2] payload length +- // [3..9] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE. ++ // [1] number of internalized strings ++ // [2] number of code stub keys ++ // [3] payload length ++ // [4..10] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE. + static const int kCheckSumOffset = 0; +- static const int kReservationsOffset = 1; +- static const int kNumCodeStubKeysOffset = 2; +- static const int kPayloadLengthOffset = 3; ++ static const int kNumInternalizedStringsOffset = 1; ++ static const int kReservationsOffset = 2; ++ static const int kNumCodeStubKeysOffset = 3; ++ static const int kPayloadLengthOffset = 4; + static const int kHeaderSize = (kPayloadLengthOffset + 1) * kIntSize; + + class ChunkSizeBits : public BitField {}; diff --git a/patches/backport.R25039.patch b/patches/backport.R25039.patch new file mode 100644 index 0000000..3e1e5ef --- /dev/null +++ b/patches/backport.R25039.patch @@ -0,0 +1,217 @@ +commit 3a3d5e741a4329641fa45f7293220e8dfd7a8f15 +Author: yangguo@chromium.org +Date: Fri Oct 31 14:43:21 2014 +0000 + + Break allocations in the code serializer into correct chunk sizes. + + This change has been inspired by Slava Chigrin (https://codereview.chromium.org/689663002/) + + R=mvstanton@chromium.org, vchigrin@yandex-team.ru + + Review URL: https://codereview.chromium.org/686103004 + + Cr-Commit-Position: refs/heads/master@{#25039} + git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25039 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 + +diff --git a/src/heap/heap.cc b/src/heap/heap.cc +index 94c8937..93e00d2 100644 +--- node/deps/v8/src/heap/heap.cc ++++ node/deps/v8/src/heap/heap.cc +@@ -939,6 +939,8 @@ bool Heap::ReserveSpace(Reservation* reservations) { + for (auto& chunk : *reservation) { + AllocationResult allocation; + int size = chunk.size; ++ DCHECK_LE(size, MemoryAllocator::PageAreaSize( ++ static_cast(space))); + if (space == NEW_SPACE) { + allocation = new_space()->AllocateRaw(size); + } else { +diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc +index 85281aa..430f31d 100644 +--- node/deps/v8/src/heap/spaces.cc ++++ node/deps/v8/src/heap/spaces.cc +@@ -892,19 +892,15 @@ void MemoryChunk::IncrementLiveBytesFromMutator(Address address, int by) { + // ----------------------------------------------------------------------------- + // PagedSpace implementation + +-PagedSpace::PagedSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id, ++PagedSpace::PagedSpace(Heap* heap, intptr_t max_capacity, AllocationSpace space, + Executability executable) +- : Space(heap, id, executable), ++ : Space(heap, space, executable), + free_list_(this), + swept_precisely_(true), + unswept_free_bytes_(0), + end_of_unswept_pages_(NULL), + emergency_memory_(NULL) { +- if (id == CODE_SPACE) { +- area_size_ = heap->isolate()->memory_allocator()->CodePageAreaSize(); +- } else { +- area_size_ = Page::kPageSize - Page::kObjectStartOffset; +- } ++ area_size_ = MemoryAllocator::PageAreaSize(space); + max_capacity_ = + (RoundDown(max_capacity, Page::kPageSize) / Page::kPageSize) * AreaSize(); + accounting_stats_.Clear(); +diff --git a/src/heap/spaces.h b/src/heap/spaces.h +index 5be9c3a..1944464 100644 +--- node/deps/v8/src/heap/spaces.h ++++ node/deps/v8/src/heap/spaces.h +@@ -1104,6 +1104,12 @@ class MemoryAllocator { + return CodePageAreaEndOffset() - CodePageAreaStartOffset(); + } + ++ static int PageAreaSize(AllocationSpace space) { ++ DCHECK_NE(LO_SPACE, space); ++ return (space == CODE_SPACE) ? CodePageAreaSize() ++ : Page::kMaxRegularHeapObjectSize; ++ } ++ + MUST_USE_RESULT bool CommitExecutableMemory(base::VirtualMemory* vm, + Address start, size_t commit_size, + size_t reserved_size); +diff --git a/src/serialize.cc b/src/serialize.cc +index 86045d3..df62adb 100644 +--- node/deps/v8/src/serialize.cc ++++ node/deps/v8/src/serialize.cc +@@ -1258,10 +1258,15 @@ Serializer::Serializer(Isolate* isolate, SnapshotByteSink* sink) + external_reference_encoder_(new ExternalReferenceEncoder(isolate)), + root_index_map_(isolate), + code_address_map_(NULL), ++ large_objects_total_size_(0), + seen_large_objects_index_(0) { + // The serializer is meant to be used only to generate initial heap images + // from a context in which there is only one isolate. +- for (int i = 0; i < kNumberOfSpaces; i++) pending_chunk_[i] = 0; ++ for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) { ++ pending_chunk_[i] = 0; ++ max_chunk_size_[i] = static_cast( ++ MemoryAllocator::PageAreaSize(static_cast(i))); ++ } + } + + +@@ -1336,8 +1341,7 @@ void Serializer::VisitPointers(Object** start, Object** end) { + + + void Serializer::FinalizeAllocation() { +- DCHECK_EQ(0, completed_chunks_[LO_SPACE].length()); // Not yet finalized. +- for (int i = 0; i < kNumberOfSpaces; i++) { ++ for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) { + // Complete the last pending chunk and if there are no completed chunks, + // make sure there is at least one empty chunk. + if (pending_chunk_[i] > 0 || completed_chunks_[i].length() == 0) { +@@ -1906,17 +1910,17 @@ AllocationSpace Serializer::SpaceOfObject(HeapObject* object) { + uint32_t Serializer::AllocateLargeObject(int size) { + // Large objects are allocated one-by-one when deserializing. We do not + // have to keep track of multiple chunks. +- pending_chunk_[LO_SPACE] += size; ++ large_objects_total_size_ += size; + return seen_large_objects_index_++; + } + + + uint32_t Serializer::Allocate(int space, int size) { + CHECK(space >= 0 && space < kNumberOfPreallocatedSpaces); +- DCHECK(size > 0 && size <= Page::kMaxRegularHeapObjectSize); ++ DCHECK(size > 0 && size <= static_cast(max_chunk_size(space))); + uint32_t new_chunk_size = pending_chunk_[space] + size; + uint32_t allocation; +- if (new_chunk_size > static_cast(Page::kMaxRegularHeapObjectSize)) { ++ if (new_chunk_size > max_chunk_size(space)) { + // The new chunk size would not fit onto a single page. Complete the + // current chunk and start a new one. + completed_chunks_[space].Add(pending_chunk_[space]); +@@ -1929,15 +1933,6 @@ BackReference Serializer::Allocate(AllocationSpace space, int size) { + } + + +-int Serializer::SpaceAreaSize(int space) { +- if (space == CODE_SPACE) { +- return isolate_->memory_allocator()->CodePageAreaSize(); +- } else { +- return Page::kPageSize - Page::kObjectStartOffset; +- } +-} +- +- + void Serializer::Pad() { + // The non-branching GetInt will read up to 3 bytes too far, so we need + // to pad the snapshot to make sure we don't read over the end. +@@ -2273,9 +2268,6 @@ SerializedCodeData::SerializedCodeData(const List& payload, + for (int i = 0; i < SerializerDeserializer::kNumberOfSpaces; i++) { + Vector chunks = cs->FinalAllocationChunks(i); + for (int j = 0; j < chunks.length(); j++) { +- DCHECK(i == LO_SPACE || +- chunks[j] <= +- static_cast(Page::kMaxRegularHeapObjectSize)); + uint32_t chunk = ChunkSizeBits::encode(chunks[j]) | + IsLastChunkBits::encode(j == chunks.length() - 1); + reservations.Add(chunk); +diff --git a/src/serialize.h b/src/serialize.h +index 2aa55ea..9c56118 100644 +--- node/deps/v8/src/serialize.h ++++ node/deps/v8/src/serialize.h +@@ -404,8 +404,6 @@ class Deserializer: public SerializerDeserializer { + void AddReservation(int space, uint32_t chunk) { + DCHECK(space >= 0); + DCHECK(space < kNumberOfSpaces); +- DCHECK(space == LO_SPACE || +- chunk <= static_cast(Page::kMaxRegularHeapObjectSize)); + Heap::Chunk c = { chunk, NULL, NULL }; reservations_[space].Add(c); + } + +@@ -498,9 +496,12 @@ class Serializer : public SerializerDeserializer { + void FinalizeAllocation(); + + Vector FinalAllocationChunks(int space) const { +- DCHECK_EQ(1, completed_chunks_[LO_SPACE].length()); // Already finalized. +- DCHECK_EQ(0, pending_chunk_[space]); // No pending chunks. +- return completed_chunks_[space].ToConstVector(); ++ if (space == LO_SPACE) { ++ return Vector(&large_objects_total_size_, 1); ++ } else { ++ DCHECK_EQ(0, pending_chunk_[space]); // No pending chunks. ++ return completed_chunks_[space].ToConstVector(); ++ } + } + + Isolate* isolate() const { return isolate_; } +@@ -496,20 +496,25 @@ + return external_reference_encoder_->Encode(addr); + } + +- int SpaceAreaSize(int space); +- + // Some roots should not be serialized, because their actual value depends on + // absolute addresses and they are reset after deserialization, anyway. + bool ShouldBeSkipped(Object** current); + ++ uint32_t max_chunk_size(int space) const { ++ DCHECK_LE(0, space); ++ DCHECK_LT(space, kNumberOfSpaces); ++ return max_chunk_size_[space]; ++ } ++ + Isolate* isolate_; + + // Objects from the same space are put into chunks for bulk-allocation + // when deserializing. We have to make sure that each chunk fits into a + // page. So we track the chunk size in pending_chunk_ of a space, but + // when it exceeds a page, we complete the current chunk and start a new one. +- uint32_t pending_chunk_[kNumberOfSpaces]; +- List completed_chunks_[kNumberOfSpaces]; ++ uint32_t pending_chunk_[kNumberOfPreallocatedSpaces]; ++ List completed_chunks_[kNumberOfPreallocatedSpaces]; ++ uint32_t max_chunk_size_[kNumberOfPreallocatedSpaces]; + + SnapshotByteSink* sink_; + ExternalReferenceEncoder* external_reference_encoder_; +@@ -529,6 +534,7 @@ + CodeAddressMap* code_address_map_; + // We map serialized large objects to indexes for back-referencing. + uint32_t seen_large_objects_index_; ++ uint32_t large_objects_total_size_; + DISALLOW_COPY_AND_ASSIGN(Serializer); + }; + diff --git a/patches/backport.R25444.patch b/patches/backport.R25444.patch new file mode 100644 index 0000000..4477a57 --- /dev/null +++ b/patches/backport.R25444.patch @@ -0,0 +1,117 @@ +commit c64b47f55237a78b6d74baa1503e7218b94811e4 +Author: yangguo +Date: Thu Nov 20 08:20:48 2014 -0800 + + When optimizing deserialized code, make sure IC state is preserved. + + R=jkummerow@chromium.org + + Review URL: https://codereview.chromium.org/737373003 + + Cr-Commit-Position: refs/heads/master@{#25444} + +diff --git a/src/compiler.cc b/src/compiler.cc +index 3b612c1..33d88d7 100644 +--- node/deps/v8/src/compiler.cc ++++ node/deps/v8/src/compiler.cc +@@ -384,13 +384,21 @@ + if (FLAG_hydrogen_stats) { + timer.Start(); + } +- CompilationInfoWithZone unoptimized(info()->shared_info()); ++ Handle shared = info()->shared_info(); ++ CompilationInfoWithZone unoptimized(shared); + // Note that we use the same AST that we will use for generating the + // optimized code. + unoptimized.SetFunction(info()->function()); + unoptimized.PrepareForCompilation(info()->scope()); + unoptimized.SetContext(info()->context()); + if (should_recompile) unoptimized.EnableDeoptimizationSupport(); ++ // If the current code has reloc info for serialization, also include ++ // reloc info for serialization for the new code, so that deopt support ++ // can be added without losing IC state. ++ if (shared->code()->kind() == Code::FUNCTION && ++ shared->code()->has_reloc_info_for_serialization()) { ++ unoptimized.PrepareForSerializing(); ++ } + bool succeeded = FullCodeGenerator::MakeCode(&unoptimized); + if (should_recompile) { + if (!succeeded) return SetLastStatus(FAILED); +diff --git a/src/flag-definitions.h b/src/flag-definitions.h +index 535dcd2..0d7363e 100644 +--- node/deps/v8/src/flag-definitions.h ++++ node/deps/v8/src/flag-definitions.h +@@ -427,7 +427,8 @@ + DEFINE_BOOL(trace_stub_failures, false, + "trace deoptimization of generated code stubs") + +-DEFINE_BOOL(serialize_toplevel, false, "enable caching of toplevel scripts") ++DEFINE_BOOL(serialize_toplevel, true, "enable caching of toplevel scripts") ++DEFINE_BOOL(serialize_inner, true, "enable caching of inner functions") + DEFINE_BOOL(trace_code_serializer, false, "trace code serializer") + + // compiler.cc +diff --git a/src/full-codegen.cc b/src/full-codegen.cc +index e32c59f..cb8f4aa 100644 +--- node/deps/v8/src/full-codegen.cc ++++ node/deps/v8/src/full-codegen.cc +@@ -321,6 +321,7 @@ + cgen.PopulateDeoptimizationData(code); + cgen.PopulateTypeFeedbackInfo(code); + code->set_has_deoptimization_support(info->HasDeoptimizationSupport()); ++ code->set_has_reloc_info_for_serialization(info->will_serialize()); + code->set_handler_table(*cgen.handler_table()); + code->set_compiled_optimizable(info->IsOptimizable()); + code->set_allow_osr_at_loop_nesting_level(0); +diff --git a/src/objects-inl.h b/src/objects-inl.h +index 3dd6fed..108f9f6 100644 +--- node/deps/v8/src/objects-inl.h ++++ node/deps/v8/src/objects-inl.h +@@ -4794,6 +4794,21 @@ + } + + ++bool Code::has_reloc_info_for_serialization() { ++ DCHECK_EQ(FUNCTION, kind()); ++ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags); ++ return FullCodeFlagsHasRelocInfoForSerialization::decode(flags); ++} ++ ++ ++void Code::set_has_reloc_info_for_serialization(bool value) { ++ DCHECK_EQ(FUNCTION, kind()); ++ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags); ++ flags = FullCodeFlagsHasRelocInfoForSerialization::update(flags, value); ++ WRITE_BYTE_FIELD(this, kFullCodeFlags, flags); ++} ++ ++ + int Code::allow_osr_at_loop_nesting_level() { + DCHECK_EQ(FUNCTION, kind()); + int fields = READ_UINT32_FIELD(this, kKindSpecificFlags2Offset); +diff --git a/src/objects.h b/src/objects.h +index 678dcb2..9569de9 100644 +--- node/deps/v8/src/objects.h ++++ node/deps/v8/src/objects.h +@@ -5597,6 +5597,12 @@ + inline bool is_compiled_optimizable(); + inline void set_compiled_optimizable(bool value); + ++ // [has_reloc_info_for_serialization]: For FUNCTION kind, tells if its ++ // reloc info includes runtime and external references to support ++ // serialization/deserialization. ++ inline bool has_reloc_info_for_serialization(); ++ inline void set_has_reloc_info_for_serialization(bool value); ++ + // [allow_osr_at_loop_nesting_level]: For FUNCTION kind, tells for + // how long the function has been marked for OSR and therefore which + // level of loop nesting we are willing to do on-stack replacement +@@ -5873,6 +5879,8 @@ + public BitField {}; // NOLINT + class FullCodeFlagsHasDebugBreakSlotsField: public BitField {}; + class FullCodeFlagsIsCompiledOptimizable: public BitField {}; ++ class FullCodeFlagsHasRelocInfoForSerialization ++ : public BitField {}; + + static const int kProfilerTicksOffset = kFullCodeFlags + 1; + diff --git a/patches/node.v0.12.15.patch b/patches/node.v0.12.15.patch new file mode 100644 index 0000000..065bffe --- /dev/null +++ b/patches/node.v0.12.15.patch @@ -0,0 +1,1060 @@ +--- node/deps/v8/include/v8.h ++++ node/deps/v8/include/v8.h +@@ -1117,10 +1117,12 @@ + + // Support the previous API for a transition period. + kProduceDataToCache + }; + ++ static Local EncloseParseToAst(Isolate* isolate, Local code); ++ + /** + * Compiles the specified script (context-independent). + * Cached data as part of the source object can be optionally produced to be + * consumed later to speed up compilation of identical source scripts. + * +@@ -4826,10 +4828,14 @@ + */ + static void SetFlagsFromCommandLine(int* argc, + char** argv, + bool remove_flags); + ++ static void EncloseReadBytecode(const FunctionCallbackInfo& args); ++ static void EncloseWriteBytecode(); ++ static void CpuFeaturesProbeTrue(); ++ + /** Get the version string. */ + static const char* GetVersion(); + + /** Callback function for reporting failed access checks.*/ + static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback); +--- node/deps/v8/src/api.cc ++++ node/deps/v8/src/api.cc +@@ -10,10 +10,11 @@ + #endif // V8_USE_ADDRESS_SANITIZER + #include // For isnan. + #include "include/v8-debug.h" + #include "include/v8-profiler.h" + #include "include/v8-testing.h" ++#include "include/libplatform/libplatform.h" + #include "src/assert-scope.h" + #include "src/base/platform/platform.h" + #include "src/base/platform/time.h" + #include "src/base/utils/random-number-generator.h" + #include "src/bootstrapper.h" +@@ -31,24 +32,30 @@ + #include "src/icu_util.h" + #include "src/json-parser.h" + #include "src/messages.h" + #include "src/natives.h" + #include "src/parser.h" ++#include "src/prettyprinter.h" + #include "src/profile-generator-inl.h" + #include "src/property.h" + #include "src/property-details.h" + #include "src/prototype.h" ++#include "src/rewriter.h" + #include "src/runtime.h" + #include "src/runtime-profiler.h" + #include "src/scanner-character-streams.h" + #include "src/simulator.h" + #include "src/snapshot.h" + #include "src/unicode-inl.h" + #include "src/v8threads.h" + #include "src/version.h" + #include "src/vm-state-inl.h" + ++#ifdef V8_OS_WIN ++#include // For _setmode ++#include // For _setmode ++#endif + + #define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr)) + + #define ENTER_V8(isolate) \ + DCHECK((isolate)->IsInitialized()); \ +@@ -391,10 +398,235 @@ + void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) { + i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags); + } + + ++void DumpException(Local message) { ++ String::Utf8Value message_string(message->Get()); ++ String::Utf8Value message_line(message->GetSourceLine()); ++ base::OS::PrintError("%s at line %d\n", *message_string, message->GetLineNumber()); ++ base::OS::PrintError("%s\n", *message_line); ++ for (int i = 0; i <= message->GetEndColumn(); ++i) { ++ base::OS::PrintError("%c", i < message->GetStartColumn() ? ' ' : '^'); ++ } ++ base::OS::PrintError("\n"); ++} ++ ++ ++void FixScript(Isolate* v8_isolate, Local script) { ++ i::Isolate* isolate = reinterpret_cast(v8_isolate); ++ i::Handle obj = i::Handle::cast(Utils::OpenHandle(*script)); ++ i::Handle function_info( ++ i::SharedFunctionInfo::cast(*obj), obj->GetIsolate()); ++ i::Script* s = reinterpret_cast(function_info->script()); ++ s->set_source(isolate->heap()->undefined_value()); ++} ++ ++ ++uint8_t* GetExtraFromStdin(uint8_t** pbuffer, int* psize) { ++ ++#ifdef V8_OS_WIN ++ _setmode(_fileno(stdin), _O_BINARY); ++#endif ++ ++ int read; ++ uint32_t length; ++ ++ read = static_cast(fread(&length, 1, sizeof(length), stdin)); ++ if (read != sizeof(length)) { ++ base::OS::PrintError("EncloseJS: Invalid stdin provided.\n"); ++ exit(1); ++ } ++ ++ *psize = static_cast(length); ++ uint8_t* dispose_me = i::NewArray(*psize); ++ ++ for (int i = 0; i < *psize;) { ++ read = static_cast(fread(&dispose_me[i], 1, *psize - i, stdin)); ++ if (ferror(stdin) != 0) { ++ base::OS::PrintError("EncloseJS: Error reading from stdin.\n"); ++ exit(1); ++ } ++ i += read; ++ } ++ ++ *pbuffer = dispose_me; ++ return dispose_me; ++ ++} ++ ++ ++void PutBytecodeToStdout(const uint8_t* buffer, int size) { ++ ++#ifdef V8_OS_WIN ++ _setmode(_fileno(stdout), _O_BINARY); ++#endif ++ ++ int written; ++ ++ for (int i = 0; i < size;) { ++ written = static_cast(fwrite(&buffer[i], 1, size - i, stdout)); ++ if (ferror(stdout) != 0) { ++ base::OS::PrintError("EncloseJS: Error writing to stdout.\n"); ++ exit(1); ++ } ++ i += written; ++ } ++ ++ fflush(stdout); ++ ++} ++ ++ ++uint8_t* GetBytecodeFromFileOverlay(FILE* file, uint8_t** pbuffer, int* psize) { ++ ++ int read; ++ uint32_t sentinel, length; ++ ++ // start of search. WARNING! THIS VALUE DIFFERS IN NODE BRANCHES ++ if (file == NULL || fseek(file, 6 * 1024 * 1024, SEEK_SET) != 0) { ++ base::OS::PrintError("EncloseJS: Error reading file.\n"); ++ exit(1); ++ } ++ ++ while (true) { ++ read = static_cast(fread(&sentinel, 1, sizeof(sentinel), file)); ++ if (read != sizeof(length)) { ++ base::OS::PrintError("EncloseJS: Invalid file provided.\n"); ++ exit(1); ++ } ++ if (sentinel != 0x26e0c928) continue; ++ fread(&length, 1, sizeof(length), file); ++ if ((sentinel^length) != 0x6713e24e) continue; // 0x26e0c928^0x41f32b66 ++ fread(&sentinel, 1, sizeof(sentinel), file); ++ if (sentinel != 0x3ea13ccf) continue; ++ break; ++ } ++ ++ fread(&length, 1, sizeof(length), file); ++ *psize = static_cast(length); ++ uint8_t* dispose_me = i::NewArray(*psize); ++ ++ for (int i = 0; i < *psize;) { ++ read = static_cast(fread(&dispose_me[i], 1, *psize - i, file)); ++ if (ferror(file) != 0) { ++ base::OS::PrintError("EncloseJS: Error reading from file.\n"); ++ exit(1); ++ } ++ i += read; ++ } ++ ++ *pbuffer = dispose_me; ++ return dispose_me; ++ ++} ++ ++ ++// from v8\src\base\platform\platform-win32.cc ++int wfopen_s(FILE** pFile, const char* filename, const char* mode) { ++#ifdef V8_OS_WIN ++ WCHAR filename_w[32768]; ++ WCHAR mode_w[16]; ++ if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filename_w, sizeof(filename_w)) && ++ MultiByteToWideChar(CP_UTF8, 0, mode, -1, mode_w, sizeof(mode_w))) { ++ *pFile = _wfopen(filename_w, mode_w); ++ if (*pFile != NULL) return 0; ++ } ++#endif ++ *pFile = fopen(filename, mode); ++ return *pFile != NULL ? 0 : 1; ++} ++ ++ ++// from v8\src\base\platform\platform-win32.cc ++FILE* WFOpen(const char* path, const char* mode) { ++ FILE* result; ++ if (wfopen_s(&result, path, mode) == 0) { ++ return result; ++ } else { ++ return NULL; ++ } ++} ++ ++ ++void V8::EncloseReadBytecode(const FunctionCallbackInfo& args) { ++ ++ String::Utf8Value filename(args[0]); ++ FILE* file = WFOpen(*filename, "rb"); ++ uint8_t* buffer; int size; ++ uint8_t* dispose_me = GetBytecodeFromFileOverlay(file, &buffer, &size); ++ Isolate* iso = Isolate::GetCurrent(); ++ ++ { ++ ++ Isolate::Scope iscope(iso); ++ HandleScope hscope(iso); ++ Local context = iso->GetCurrentContext(); ++ Context::Scope cscope(context); ++ ++ ScriptCompiler::CachedData::BufferPolicy bp = ScriptCompiler::CachedData::BufferNotOwned; ++ ScriptCompiler::CachedData* data = new ScriptCompiler::CachedData(buffer, size, bp); ++ Local source_string = String::NewFromUtf8(iso, "e"); ++ ScriptCompiler::Source source(source_string, data); ++ Local script = ScriptCompiler::CompileUnbound(iso, &source, ++ ScriptCompiler::kConsumeCodeCache); ++ // DCHECK(!data->rejected); ++ ++ FixScript(iso, script); ++ Local result = script->BindToCurrentContext()->Run(); ++ args.GetReturnValue().Set(result); ++ ++ } ++ ++ i::DeleteArray(dispose_me); ++ fclose(file); ++ ++} ++ ++ ++void V8::EncloseWriteBytecode() { ++ ++ // KLOPOV: dont log ++ i::FLAG_log_code = false; ++ // KLOPOV: no harmony in 0.12.x ++ // i::FLAG_harmony_shipping = true; ++ i::FLAG_logfile_per_isolate = false; ++ i::FLAG_serialize_inner = true; ++ i::FLAG_serialize_toplevel = true; ++ i::FLAG_lazy = false; ++ ++ uint8_t* buffer; int size; ++ uint8_t* dispose_me = GetExtraFromStdin(&buffer, &size); ++ Isolate* iso = Isolate::GetCurrent(); ++ ++ TryCatch try_catch; ++ ++ Local source_string = String::NewFromUtf8(iso, (char*) buffer, ++ String::kNormalString, size); ++ Local origin_string = String::NewFromUtf8(iso, "e"); ++ ScriptCompiler::Source source(source_string, ScriptOrigin(origin_string)); ++ ScriptCompiler::CompileUnbound(iso, &source, ++ ScriptCompiler::kProduceCodeCache); ++ ++ if (try_catch.HasCaught()) { ++ base::OS::PrintError("EncloseJS: compilation failed.\n"); ++ DumpException(try_catch.Message()); ++ exit(1); ++ } ++ ++ const ScriptCompiler::CachedData* data = source.GetCachedData(); ++ PutBytecodeToStdout(data->data, data->length); ++ i::DeleteArray(dispose_me); ++ ++} ++ ++ ++void V8::CpuFeaturesProbeTrue() { ++ i::CpuFeatures::Probe(true); ++} ++ ++ + RegisteredExtension* RegisteredExtension::first_extension_ = NULL; + + + RegisteredExtension::RegisteredExtension(Extension* extension) + : extension_(extension) { } +@@ -1831,10 +2066,40 @@ + ScriptOrigin origin(file_name); + return Compile(source, &origin); + } + + ++Local ScriptCompiler::EncloseParseToAst(Isolate* v8_isolate, Local code) { ++ ++ i::Isolate* isolate = reinterpret_cast(v8_isolate); ++ i::Factory* factory = isolate->factory(); ++ i::Handle string = Utils::OpenHandle(*code); // TODO NewStringFromUtf8 ++ i::Handle script = factory->NewScript(string); ++ ++ i::CompilationInfoWithZone parse_info(script); ++ i::Parser parser(&parse_info); ++ // parser.set_allow_harmony_arrow_functions(true); ++ // parser.set_allow_harmony_sloppy(true); ++ // parser.set_global(); ++ // parser.set_lazy(false); ++ parser.set_allow_lazy(false); ++ // parser.set_toplevel(); ++ ++ if (!parser.Parse()) { ++ return String::Empty(v8_isolate); ++ } ++ ++ i::AstPrinter ap(parse_info.zone()); ++ const char* output = ap.PrintProgram(parse_info.function()); ++ Local result = String::NewFromUtf8( ++ v8_isolate, output, String::kNormalString, -1); ++ ++ return result; ++ ++} ++ ++ + // --- E x c e p t i o n s --- + + + v8::TryCatch::TryCatch() + : isolate_(i::Isolate::Current()), +--- node/deps/v8/src/codegen.cc ++++ node/deps/v8/src/codegen.cc +@@ -125,15 +125,10 @@ + #ifdef DEBUG + if (!info->IsStub() && print_source) { + PrintF("--- Source from AST ---\n%s\n", + PrettyPrinter(info->zone()).PrintProgram(info->function())); + } +- +- if (!info->IsStub() && print_ast) { +- PrintF("--- AST ---\n%s\n", +- AstPrinter(info->zone()).PrintProgram(info->function())); +- } + #endif // DEBUG + } + + + Handle CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm, +--- node/deps/v8/src/parser.cc ++++ node/deps/v8/src/parser.cc +@@ -4838,10 +4838,11 @@ + return !parser.failed(); + } + + + bool Parser::Parse() { ++ if (info()->script()->source()->IsUndefined()) return false; + DCHECK(info()->function() == NULL); + FunctionLiteral* result = NULL; + ast_value_factory_ = info()->ast_value_factory(); + if (ast_value_factory_ == NULL) { + ast_value_factory_ = +--- node/deps/v8/src/prettyprinter.cc ++++ node/deps/v8/src/prettyprinter.cc +@@ -12,12 +12,10 @@ + #include "src/scopes.h" + + namespace v8 { + namespace internal { + +-#ifdef DEBUG +- + PrettyPrinter::PrettyPrinter(Zone* zone) { + output_ = NULL; + size_ = 0; + pos_ = 0; + InitializeAstVisitor(zone); +@@ -547,40 +545,64 @@ + + void PrettyPrinter::PrintLiteral(Handle value, bool quote) { + Object* object = *value; + if (object->IsString()) { + String* string = String::cast(object); +- if (quote) Print("\""); ++ Print("\""); + for (int i = 0; i < string->length(); i++) { +- Print("%c", string->Get(i)); ++ uint16_t c16 = string->Get(i); ++ if (c16 == 34) { ++ Print("\\\""); // escape quote ++ } else ++ if (c16 == 92) { ++ Print("\\\\"); // escape left slash ++ } else ++ if ((c16 >= 32) && (c16 <= 127)) { ++ Print("%c", c16); ++ } else { ++ Print("?"); ++ } + } +- if (quote) Print("\""); ++ Print("\""); + } else if (object->IsNull()) { + Print("null"); + } else if (object->IsTrue()) { + Print("true"); + } else if (object->IsFalse()) { + Print("false"); + } else if (object->IsUndefined()) { +- Print("undefined"); ++ Print("null"); + } else if (object->IsNumber()) { +- Print("%g", object->Number()); ++ EmbeddedVector buf; ++ int pos = SNPrintF(buf, "%g", object->Number()); ++ quote = false; ++ for (int i = 0; i < pos; i++) { ++ if ((buf[i] == 'N') || (buf[i] == 'n')) { // 1.#INF or inf or nan ++ quote = true; ++ break; ++ } ++ } ++ if (quote) Print("\""); ++ Print("%s", buf.start()); ++ if (quote) Print("\""); + } else if (object->IsJSObject()) { + // regular expression ++ Print("\""); + if (object->IsJSFunction()) { + Print("JS-Function"); + } else if (object->IsJSArray()) { + Print("JS-array[%u]", JSArray::cast(object)->length()); + } else if (object->IsJSObject()) { + Print("JS-Object"); + } else { + Print("?UNKNOWN?"); + } ++ Print("\""); + } else if (object->IsFixedArray()) { +- Print("FixedArray"); ++ Print("\"FixedArray\""); + } else { +- Print("", object); ++ Print("\"\"", object); + } + } + + + void PrettyPrinter::PrintLiteral(const AstRawString* value, bool quote) { +@@ -638,57 +660,73 @@ + + + //----------------------------------------------------------------------------- + + +-AstPrinter::AstPrinter(Zone* zone) : PrettyPrinter(zone), indent_(0) { ++AstPrinter::AstPrinter(Zone* zone) : PrettyPrinter(zone), indent_(0), just_indented_(true) { + } + + + AstPrinter::~AstPrinter() { + DCHECK(indent_ == 0); + } + + +-void AstPrinter::PrintIndented(const char* txt) { +- for (int i = 0; i < indent_; i++) { +- Print(". "); ++void AstPrinter::PrintIndented(const char* txt, int bracket) { ++// for (int i = 0; i < indent_; i++) { ++// Print(" "); ++// } ++ char temp[1024]; ++ int pos = 0; ++ if ((bracket == 0) || (bracket == 1)) { ++ if (just_indented_) { ++ just_indented_ = false; ++ } else { ++ temp[pos++] = ','; ++ temp[pos++] = ' '; ++ } ++ } ++ int length = (int) strlen(txt); ++ if (bracket == 0) { ++ temp[pos++] = '\"'; ++ } ++ for (int j = 0; j < length; j++) { ++ if (txt[j] == ' ') { ++ temp[pos++] = '_'; ++ } else { ++ temp[pos++] = txt[j]; ++ } ++ } ++ if (bracket == 0) { ++ temp[pos++] = '\"'; + } +- Print(txt); ++ temp[pos++] = '\0'; ++ Print(temp); + } + + + void AstPrinter::PrintLiteralIndented(const char* info, + Handle value, + bool quote) { + PrintIndented(info); +- Print(" "); ++ Print(", "); + PrintLiteral(value, quote); + Print("\n"); + } + + + void AstPrinter::PrintLiteralWithModeIndented(const char* info, + Variable* var, + Handle value) { +- if (var == NULL) { +- PrintLiteralIndented(info, value, true); +- } else { +- EmbeddedVector buf; +- int pos = SNPrintF(buf, "%s (mode = %s", info, +- Variable::Mode2String(var->mode())); +- SNPrintF(buf + pos, ")"); +- PrintLiteralIndented(buf.start(), value, true); +- } ++ PrintLiteralIndented(info, value, true); + } + + + void AstPrinter::PrintLabelsIndented(ZoneList* labels) { + if (labels == NULL || labels->length() == 0) return; + PrintIndented("LABELS "); +- PrintLabels(labels); +- Print("\n"); ++ Print(", []\n"); + } + + + void AstPrinter::PrintIndentedVisit(const char* s, AstNode* node) { + IndentedScope indent(this, s); +@@ -696,17 +734,19 @@ + } + + + const char* AstPrinter::PrintProgram(FunctionLiteral* program) { + Init(); ++ Print("[\n"); + { IndentedScope indent(this, "FUNC"); + PrintLiteralIndented("NAME", program->name(), true); + PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true); + PrintParameters(program->scope()); + PrintDeclarations(program->scope()->declarations()); + PrintStatements(program->body()); + } ++ Print("]\n"); + return Output(); + } + + + void AstPrinter::PrintDeclarations(ZoneList* declarations) { +@@ -752,22 +792,17 @@ + + + // TODO(svenpanne) Start with IndentedScope. + void AstPrinter::VisitVariableDeclaration(VariableDeclaration* node) { + PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()), +- node->proxy()->var(), +- node->proxy()->name()); ++ NULL, node->proxy()->name()); + } + + + // TODO(svenpanne) Start with IndentedScope. + void AstPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) { +- PrintIndented("FUNCTION "); +- PrintLiteral(node->proxy()->name(), true); +- Print(" = function "); +- PrintLiteral(node->fun()->name(), false); +- Print("\n"); ++ PrintIndentedVisit("FUNCTION", node->fun()); + } + + + void AstPrinter::VisitModuleDeclaration(ModuleDeclaration* node) { + IndentedScope indent(this, "MODULE"); +@@ -955,14 +990,14 @@ + void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) { + IndentedScope indent(this, "FUNC LITERAL"); + PrintLiteralIndented("NAME", node->name(), false); + PrintLiteralIndented("INFERRED NAME", node->inferred_name(), false); + PrintParameters(node->scope()); +- // We don't want to see the function literal in this case: it +- // will be printed via PrintProgram when the code for it is +- // generated. +- // PrintStatements(node->body()); ++ PrintDeclarations(node->scope()->declarations()); ++ if (node->body() != NULL) { ++ PrintStatements(node->body()); ++ } + } + + + void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) { + IndentedScope indent(this, "NATIVE FUNC LITERAL"); +@@ -1035,30 +1070,13 @@ + } + + + // TODO(svenpanne) Start with IndentedScope. + void AstPrinter::VisitVariableProxy(VariableProxy* node) { +- Variable* var = node->var(); + EmbeddedVector buf; +- int pos = SNPrintF(buf, "VAR PROXY"); +- switch (var->location()) { +- case Variable::UNALLOCATED: +- break; +- case Variable::PARAMETER: +- SNPrintF(buf + pos, " parameter[%d]", var->index()); +- break; +- case Variable::LOCAL: +- SNPrintF(buf + pos, " local[%d]", var->index()); +- break; +- case Variable::CONTEXT: +- SNPrintF(buf + pos, " context[%d]", var->index()); +- break; +- case Variable::LOOKUP: +- SNPrintF(buf + pos, " lookup"); +- break; +- } +- PrintLiteralWithModeIndented(buf.start(), var, node->name()); ++ SNPrintF(buf, "VAR PROXY"); ++ PrintLiteralWithModeIndented(buf.start(), NULL, node->name()); + } + + + void AstPrinter::VisitAssignment(Assignment* node) { + IndentedScope indent(this, Token::Name(node->op())); +@@ -1143,8 +1161,6 @@ + + void AstPrinter::VisitThisFunction(ThisFunction* node) { + IndentedScope indent(this, "THIS-FUNCTION"); + } + +-#endif // DEBUG +- + } } // namespace v8::internal +--- node/deps/v8/src/prettyprinter.h ++++ node/deps/v8/src/prettyprinter.h +@@ -9,12 +9,10 @@ + #include "src/ast.h" + + namespace v8 { + namespace internal { + +-#ifdef DEBUG +- + class PrettyPrinter: public AstVisitor { + public: + explicit PrettyPrinter(Zone* zone); + virtual ~PrettyPrinter(); + +@@ -70,11 +68,11 @@ + AST_NODE_LIST(DECLARE_VISIT) + #undef DECLARE_VISIT + + private: + friend class IndentedScope; +- void PrintIndented(const char* txt); ++ void PrintIndented(const char* txt, int bracket = 0); + void PrintIndentedVisit(const char* s, AstNode* node); + + void PrintStatements(ZoneList* statements); + void PrintDeclarations(ZoneList* declarations); + void PrintParameters(Scope* scope); +@@ -84,16 +82,15 @@ + void PrintLiteralWithModeIndented(const char* info, + Variable* var, + Handle value); + void PrintLabelsIndented(ZoneList* labels); + +- void inc_indent() { indent_++; } +- void dec_indent() { indent_--; } ++ void inc_indent() { PrintIndented("[", 1); indent_++; just_indented_ = true; } // "[\n" ++ void dec_indent() { indent_--; PrintIndented("]", 2); just_indented_ = false; } // "]\n" + + int indent_; ++ bool just_indented_; + }; + +-#endif // DEBUG +- + } } // namespace v8::internal + + #endif // V8_PRETTYPRINTER_H_ +--- node/deps/v8/src/serialize.cc ++++ node/deps/v8/src/serialize.cc +@@ -2167,12 +2167,11 @@ + payload->begin(), static_cast(payload->length())); + } + + + bool SerializedCodeData::IsSane(String* source) { +- return GetHeaderValue(kCheckSumOffset) == CheckSum(source) && +- PayloadLength() >= SharedFunctionInfo::kSize; ++ return true; + } + + + int SerializedCodeData::CheckSum(String* string) { + int checksum = Version::Hash(); +--- node/deps/v8/tools/gyp/v8.gyp ++++ node/deps/v8/tools/gyp/v8.gyp +@@ -287,10 +287,11 @@ + { + 'target_name': 'v8_base', + 'type': 'static_library', + 'dependencies': [ + 'v8_libbase', ++ 'v8_libplatform', ## KLOPOV my api.cc requires v8::platform::CreateDefaultPlatform + ], + 'variables': { + 'optimize': 'max', + }, + 'include_dirs+': [ +--- node/lib/child_process.js ++++ node/lib/child_process.js +@@ -579,11 +579,11 @@ + options.stdio = options.silent ? ['pipe', 'pipe', 'pipe', 'ipc'] : + [0, 1, 2, 'ipc']; + + options.execPath = options.execPath || process.execPath; + +- return spawn(options.execPath, args, options); ++ return exports.spawn(options.execPath, args, options); + }; + + + exports._forkChild = function(fd) { + // set process.send() +--- node/node.gyp ++++ node/node.gyp +@@ -325,13 +325,10 @@ + [ 'node_shared_libuv=="false"', { + 'dependencies': [ 'deps/uv/uv.gyp:libuv' ], + }], + + [ 'OS=="win"', { +- 'sources': [ +- 'src/res/node.rc', +- ], + 'defines': [ + 'FD_SETSIZE=1024', + # we need to use node's preferred "win32" rather than gyp's preferred "win" + 'PLATFORM="win32"', + '_UNICODE=1', +--- node/src/node.cc ++++ node/src/node.cc +@@ -2954,10 +2954,11 @@ + } + + static void PrintHelp(); + + static bool ParseDebugOpt(const char* arg) { ++ return false; + const char* port = NULL; + + if (!strcmp(arg, "--debug")) { + use_debug_agent = true; + } else if (!strncmp(arg, "--debug=", sizeof("--debug=") - 1)) { +@@ -3572,14 +3573,10 @@ + // Ignore SIGPIPE + RegisterSignalHandler(SIGPIPE, SIG_IGN); + RegisterSignalHandler(SIGINT, SignalExit, true); + RegisterSignalHandler(SIGTERM, SignalExit, true); + #endif // __POSIX__ +- +- if (!use_debug_agent) { +- RegisterDebugSignalHandler(); +- } + } + + + struct AtExitCallback { + AtExitCallback* next_; +@@ -3752,21 +3749,16 @@ + + return env; + } + + +-int Start(int argc, char** argv) { ++int Start(int argc, char** argv, bool ejs_write) { + const char* replaceInvalid = getenv("NODE_INVALID_UTF8"); + + if (replaceInvalid == NULL) + WRITE_UTF8_FLAGS |= String::REPLACE_INVALID_UTF8; + +-#if !defined(_WIN32) +- // Try hard not to lose SIGUSR1 signals during the bootstrap process. +- InstallEarlyDebugSignalHandler(); +-#endif +- + assert(argc > 0); + + // Hack around with the argv pointer. Used for process.title = "blah". + argv = uv_setup_args(argc, argv); + +@@ -3780,10 +3772,14 @@ + // V8 on Windows doesn't have a good source of entropy. Seed it from + // OpenSSL's pool. + V8::SetEntropySource(crypto::EntropySource); + #endif + ++if (ejs_write) { ++ V8::CpuFeaturesProbeTrue(); ++} ++ + int code; + V8::Initialize(); + node_is_initialized = true; + { + Locker locker(node_isolate); +@@ -3798,10 +3794,15 @@ + argv, + exec_argc, + exec_argv); + Context::Scope context_scope(context); + ++if (ejs_write) { ++ V8::EncloseWriteBytecode(); ++ code = 0; ++} else { ++ + // Start debug agent when argv has --debug + if (use_debug_agent) + StartDebug(env, debug_wait_connect); + + LoadEnvironment(env); +@@ -3828,10 +3829,12 @@ + } + + code = EmitExit(env); + RunAtExit(env); + ++} ++ + env->Dispose(); + env = NULL; + } + + CHECK_NE(node_isolate, NULL); +@@ -3843,7 +3846,26 @@ + exec_argv = NULL; + + return code; + } + ++void EncloseReadBytecode(const FunctionCallbackInfo& args) { ++ V8::EncloseReadBytecode(args); ++} ++ ++static void EncloseParseToAst(const FunctionCallbackInfo& args) { ++ Environment* env = Environment::GetCurrent(args.GetIsolate()); ++ Isolate* isolate = env->isolate(); ++ Local code = args[0]->ToString(); ++ Local s = v8::ScriptCompiler::EncloseParseToAst(isolate, code); ++ args.GetReturnValue().Set(s); ++} ++ ++void EncloseInitialize(Local target, Local unused, Local context, void* p) { ++ Environment* env = Environment::GetCurrent(context); ++ NODE_SET_METHOD(target, "read", EncloseReadBytecode); ++ NODE_SET_METHOD(target, "parse", EncloseParseToAst); ++}; + + } // namespace node ++ ++NODE_MODULE_CONTEXT_AWARE_BUILTIN(enclose, node::EncloseInitialize) +--- node/src/node.h ++++ node/src/node.h +@@ -170,11 +170,12 @@ + + namespace node { + + NODE_EXTERN extern bool no_deprecation; + +-NODE_EXTERN int Start(int argc, char *argv[]); ++void EncloseWriteBytecode(); ++NODE_EXTERN int Start(int argc, char *argv[], bool ejs_write); + NODE_EXTERN void Init(int* argc, + const char** argv, + int* exec_argc, + const char*** exec_argv); + +--- node/src/node.js ++++ node/src/node.js +@@ -69,15 +69,15 @@ + + if (NativeModule.exists('_third_party_main')) { + // To allow people to extend Node in different ways, this hook allows + // one to drop a file lib/_third_party_main.js into the build + // directory which will be executed instead of Node's normal loading. +- process.nextTick(function() { +- NativeModule.require('_third_party_main'); +- }); ++ NativeModule.require('_third_party_main'); ++ ++ } + +- } else if (process.argv[1] == 'debug') { ++ if (process.argv[1] == 'debug') { + // Start the debugger agent + var d = NativeModule.require('_debugger'); + d.start(); + + } else if (process.argv[1] == '--debug-agent') { +--- node/src/node_javascript.cc ++++ node/src/node_javascript.cc +@@ -53,8 +53,17 @@ + String::kNormalString, + natives[i].source_len); + target->Set(name, source); + } + } ++ ++ Local name = String::NewFromUtf8(env->isolate(), "_third_party_main"); ++ Local source = String::NewFromUtf8(env->isolate(), ++ "var binding = process.binding('enclose');\n" \ ++ "var result; try { result = binding.read(process.execPath); } catch(_) {}\n" \ ++ "if (!result) { console.error('EncloseJS: Failed to read bytecode.'); process.exit(2); }\n" \ ++ "result(process, require, console);\n" ++ ); ++ target->Set(name, source); + } + + } // namespace node +--- node/src/node_main.cc ++++ node/src/node_main.cc +@@ -19,10 +19,83 @@ + // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + // USE OR OTHER DEALINGS IN THE SOFTWARE. + + #include "node.h" + ++#include ++ ++const char* OPTION_RUNTIME = "--runtime"; ++const char* OPTION_ENTRYPOINT = "--entrypoint"; ++const char* OPTION_WRITE = "--fabricator"; ++ ++// for uv_setup_args ++int adjacent(int argc, char** argv, bool ejs_write) { ++ size_t size = 0; ++ for (int i = 0; i < argc; i++) { ++ size += strlen(argv[i]) + 1; ++ }; ++ char* args = new char[size]; ++ size_t pos = 0; ++ for (int i = 0; i < argc; i++) { ++ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1); ++ argv[i] = &args[pos]; ++ pos += strlen(argv[i]) + 1; ++ }; ++ return node::Start( ++ argc, argv, ejs_write ++ ); ++}; ++ ++int reorder(int argc, char** argv) { ++ int i; ++ int runtime_pos = argc; ++ for (i = 1; i < argc; i++) { ++ if (strcmp(argv[i], OPTION_RUNTIME) == 0) { ++ runtime_pos = i; ++ break; ++ }; ++ }; ++ int entrypoint_pos = -1; ++ for (i = 1 + 1; i < runtime_pos; i++) { ++ if (strcmp(argv[i - 1], OPTION_ENTRYPOINT) == 0) { ++ entrypoint_pos = i; ++ break; ++ } ++ } ++ char** nargv = new char*[argc + 1]; ++ int c = 0; ++ nargv[c++] = argv[0]; ++ for (i = runtime_pos + 1; i < argc; i++) { ++ if ((strcmp(argv[i], "--v8_options") == 0) || ++ (strcmp(argv[i], "--v8-options") == 0) || ++ (strcmp(argv[i], "--expose_gc") == 0) || ++ (strcmp(argv[i], "--expose-gc") == 0) || ++ (strncmp(argv[i], "--harmony", 9) == 0)) { // --harmony* ++ nargv[c++] = argv[i]; ++ }; ++ }; ++ if (entrypoint_pos != -1) { ++ nargv[c++] = argv[entrypoint_pos]; ++ } else { ++ nargv[c++] = "DEFAULT_ENTRYPOINT"; ++ }; ++ bool ejs_write = false; ++ for (i = 1; i < runtime_pos; i++) { ++ if ((i != entrypoint_pos) && ++ (i != entrypoint_pos - 1)) { ++ if (strcmp(argv[i], OPTION_WRITE) == 0) { ++ ejs_write = true; ++ } else { ++ nargv[c++] = argv[i]; ++ }; ++ }; ++ }; ++ return adjacent( ++ c, nargv, ejs_write ++ ); ++}; ++ + #ifdef _WIN32 + int wmain(int argc, wchar_t *wargv[]) { + // Convert argv to to UTF8 + char** argv = new char*[argc]; + for (int i = 0; i < argc; i++) { +@@ -55,13 +128,13 @@ + fprintf(stderr, "Could not convert arguments to utf8."); + exit(1); + } + } + // Now that conversion is done, we can finally start. +- return node::Start(argc, argv); ++ return reorder(argc, argv); + } + #else + // UNIX + int main(int argc, char *argv[]) { +- return node::Start(argc, argv); ++ return reorder(argc, argv); + } + #endif diff --git a/patches/patches.json b/patches/patches.json index 3143025..11665a5 100644 --- a/patches/patches.json +++ b/patches/patches.json @@ -1,4 +1,21 @@ { + "v0.12.5": [ + "backport.R00000.patch", + "backport.R24002.patch", + "backport.R24204.patch", + "backport.R24262.patch", + "backport.R24266.patch", + "backport.R24523.patch", + "backport.R24543.patch", + "backport.R24639.patch", + "backport.R24642.patch", + "backport.R24643.patch", + "backport.R24644.patch", + "backport.R24824.patch", + "backport.R25039.patch", + "backport.R25444.patch", + "node.v0.12.15.patch" + ], "v4.4.7": [ "backport.R32768.v8=4.5.patch", "node.v4.4.7.patch"