From 6a3921fc0e1f013183cdc95400cd3a88a1385ceb Mon Sep 17 00:00:00 2001 From: "erik.corry@gmail.com" Date: Fri, 6 Nov 2009 13:48:33 +0000 Subject: [PATCH] Keep natives source code in external strings instead of putting it in regular flat strings that are part of the snapshot. After this change we don't need libraries-empty.cc any more. In this change libraries-empty.cc is just a the same as libraries.cc and the scons build builds it but does not use it. We can move in stages to a situation where it is not generated at all for all the build systems that we have. Review URL: http://codereview.chromium.org/360050 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3238 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/SConscript | 1 - src/bootstrapper.cc | 37 ++++++++++++++++++++++++++++++++++--- src/bootstrapper.h | 19 +++++++++++++++++++ src/objects-inl.h | 8 -------- src/objects.cc | 40 +++++++++++++++++++++++++++++++++------- src/objects.h | 14 ++++++++++++-- src/serialize.cc | 38 +++++++++++++++++++++++++++++++++++++- src/serialize.h | 11 ++++++++++- test/cctest/cctest.status | 6 +++--- tools/js2c.py | 2 +- 10 files changed, 149 insertions(+), 27 deletions(-) diff --git a/src/SConscript b/src/SConscript index 85fd724..cfa462f 100755 --- a/src/SConscript +++ b/src/SConscript @@ -264,7 +264,6 @@ def ConfigureObjectFiles(): else: snapshot_cc = Command('snapshot.cc', [], []) snapshot_obj = context.ConfigureObject(env, snapshot_cc, CPPPATH=['.']) - libraries_obj = context.ConfigureObject(env, libraries_empty_src, CPPPATH=['.']) else: snapshot_obj = empty_snapshot_obj library_objs = [non_snapshot_files, libraries_obj, snapshot_obj] diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 3436b50..e13277b 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -36,6 +36,7 @@ #include "global-handles.h" #include "macro-assembler.h" #include "natives.h" +#include "snapshot.h" namespace v8 { namespace internal { @@ -92,14 +93,34 @@ class SourceCodeCache BASE_EMBEDDED { static SourceCodeCache natives_cache(Script::TYPE_NATIVE); static SourceCodeCache extensions_cache(Script::TYPE_EXTENSION); +// This is for delete, not delete[]. +static List* delete_these_non_arrays_on_tear_down = NULL; Handle Bootstrapper::NativesSourceLookup(int index) { ASSERT(0 <= index && index < Natives::GetBuiltinsCount()); if (Heap::natives_source_cache()->get(index)->IsUndefined()) { - Handle source_code = - Factory::NewStringFromAscii(Natives::GetScriptSource(index)); - Heap::natives_source_cache()->set(index, *source_code); + if (!Snapshot::IsEnabled || FLAG_new_snapshot) { + if (delete_these_non_arrays_on_tear_down == NULL) { + delete_these_non_arrays_on_tear_down = new List(2); + } + // We can use external strings for the natives. + NativesExternalStringResource* resource = + new NativesExternalStringResource( + Natives::GetScriptSource(index).start()); + // The resources are small objects and we only make a fixed number of + // them, but lets clean them up on exit for neatness. + delete_these_non_arrays_on_tear_down-> + Add(reinterpret_cast(resource)); + Handle source_code = + Factory::NewExternalStringFromAscii(resource); + Heap::natives_source_cache()->set(index, *source_code); + } else { + // Old snapshot code can't cope with external strings at all. + Handle source_code = + Factory::NewStringFromAscii(Natives::GetScriptSource(index)); + Heap::natives_source_cache()->set(index, *source_code); + } } Handle cached_source(Heap::natives_source_cache()->get(index)); return Handle::cast(cached_source); @@ -125,6 +146,16 @@ void Bootstrapper::Initialize(bool create_heap_objects) { void Bootstrapper::TearDown() { + if (delete_these_non_arrays_on_tear_down != NULL) { + int len = delete_these_non_arrays_on_tear_down->length(); + ASSERT(len < 20); // Don't use this mechanism for unbounded allocations. + for (int i = 0; i < len; i++) { + delete delete_these_non_arrays_on_tear_down->at(i); + } + delete delete_these_non_arrays_on_tear_down; + delete_these_non_arrays_on_tear_down = NULL; + } + natives_cache.Initialize(false); // Yes, symmetrical extensions_cache.Initialize(false); } diff --git a/src/bootstrapper.h b/src/bootstrapper.h index 15fc88d..8fb4502 100644 --- a/src/bootstrapper.h +++ b/src/bootstrapper.h @@ -76,6 +76,25 @@ class Bootstrapper : public AllStatic { static void FreeThreadResources(); }; + +class NativesExternalStringResource + : public v8::String::ExternalAsciiStringResource { + public: + explicit NativesExternalStringResource(const char* source) + : data_(source), length_(strlen(source)) { } + + const char* data() const { + return data_; + } + + size_t length() const { + return length_; + } + private: + const char* data_; + size_t length_; +}; + }} // namespace v8::internal #endif // V8_BOOTSTRAPPER_H_ diff --git a/src/objects-inl.h b/src/objects-inl.h index cb48cbf..e03b3c4 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -163,11 +163,6 @@ bool Object::IsConsString() { } -#ifdef DEBUG -// These are for cast checks. If you need one of these in release -// mode you should consider using a StringShape before moving it out -// of the ifdef - bool Object::IsSeqString() { if (!IsString()) return false; return StringShape(String::cast(this)).IsSequential(); @@ -214,9 +209,6 @@ bool Object::IsSlicedString() { } -#endif // DEBUG - - StringShape::StringShape(String* str) : type_(str->map()->instance_type()) { set_valid(); diff --git a/src/objects.cc b/src/objects.cc index b14ec5c..3415266 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1138,6 +1138,15 @@ void HeapObject::IterateBody(InstanceType type, int object_size, case kSlicedStringTag: reinterpret_cast(this)->SlicedStringIterateBody(v); break; + case kExternalStringTag: + if ((type & kStringEncodingMask) == kAsciiStringTag) { + reinterpret_cast(this)-> + ExternalAsciiStringIterateBody(v); + } else { + reinterpret_cast(this)-> + ExternalTwoByteStringIterateBody(v); + } + break; } return; } @@ -4146,13 +4155,13 @@ void String::ReadBlockIntoBuffer(String* input, return; case kExternalStringTag: if (input->IsAsciiRepresentation()) { - ExternalAsciiString::cast(input)-> - ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); - } else { - ExternalTwoByteString::cast(input)-> - ExternalTwoByteStringReadBlockIntoBuffer(rbb, - offset_ptr, - max_chars); + ExternalAsciiString::cast(input)-> + ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); + } else { + ExternalTwoByteString::cast(input)-> + ExternalTwoByteStringReadBlockIntoBuffer(rbb, + offset_ptr, + max_chars); } return; default: @@ -4398,6 +4407,23 @@ void SlicedString::SlicedStringIterateBody(ObjectVisitor* v) { IteratePointer(v, kBufferOffset); } +#define FIELD_ADDR(p, offset) \ + (reinterpret_cast(p) + offset - kHeapObjectTag) + +void ExternalAsciiString::ExternalAsciiStringIterateBody(ObjectVisitor* v) { + typedef v8::String::ExternalAsciiStringResource Resource; + v->VisitExternalAsciiString( + reinterpret_cast(FIELD_ADDR(this, kResourceOffset))); +} + + +void ExternalTwoByteString::ExternalTwoByteStringIterateBody(ObjectVisitor* v) { + typedef v8::String::ExternalStringResource Resource; + v->VisitExternalTwoByteString( + reinterpret_cast(FIELD_ADDR(this, kResourceOffset))); +} + +#undef FIELD_ADDR uint16_t SlicedString::SlicedStringGet(int index) { ASSERT(index >= 0 && index < this->length()); diff --git a/src/objects.h b/src/objects.h index ee24b33..93769c9 100644 --- a/src/objects.h +++ b/src/objects.h @@ -790,7 +790,6 @@ class Object BASE_EMBEDDED { inline bool IsHeapNumber(); inline bool IsString(); inline bool IsSymbol(); -#ifdef DEBUG // See objects-inl.h for more details inline bool IsSeqString(); inline bool IsSlicedString(); @@ -799,7 +798,6 @@ class Object BASE_EMBEDDED { inline bool IsExternalAsciiString(); inline bool IsSeqTwoByteString(); inline bool IsSeqAsciiString(); -#endif // DEBUG inline bool IsConsString(); inline bool IsNumber(); @@ -4438,6 +4436,9 @@ class ExternalAsciiString: public ExternalString { // Casting. static inline ExternalAsciiString* cast(Object* obj); + // Garbage collection support. + void ExternalAsciiStringIterateBody(ObjectVisitor* v); + // Support for StringInputBuffer. const unibrow::byte* ExternalAsciiStringReadBlock(unsigned* remaining, unsigned* offset, @@ -4473,6 +4474,9 @@ class ExternalTwoByteString: public ExternalString { // Casting. static inline ExternalTwoByteString* cast(Object* obj); + // Garbage collection support. + void ExternalTwoByteStringIterateBody(ObjectVisitor* v); + // Support for StringInputBuffer. void ExternalTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* buffer, unsigned* offset_ptr, @@ -5104,6 +5108,12 @@ class ObjectVisitor BASE_EMBEDDED { // Visits a runtime entry in the instruction stream. virtual void VisitRuntimeEntry(RelocInfo* rinfo) {} + // Visits the resource of an ASCII or two-byte string. + virtual void VisitExternalAsciiString( + v8::String::ExternalAsciiStringResource** resource) {} + virtual void VisitExternalTwoByteString( + v8::String::ExternalStringResource** resource) {} + // Visits a debug call target in the instruction stream. virtual void VisitDebugTarget(RelocInfo* rinfo); diff --git a/src/serialize.cc b/src/serialize.cc index 98c4b6e..9ee434d 100644 --- a/src/serialize.cc +++ b/src/serialize.cc @@ -39,6 +39,7 @@ #include "stub-cache.h" #include "v8threads.h" #include "top.h" +#include "bootstrapper.h" namespace v8 { namespace internal { @@ -2062,6 +2063,14 @@ void Deserializer2::ReadChunk(Object** current, pages_[space].Add(last_object_address_); break; } + case NATIVES_STRING_RESOURCE: { + int index = source_->Get(); + Vector source_vector = Natives::GetScriptSource(index); + NativesExternalStringResource* resource = + new NativesExternalStringResource(source_vector.start()); + *current++ = reinterpret_cast(resource); + break; + } default: UNREACHABLE(); } @@ -2253,7 +2262,7 @@ void Serializer2::ObjectSerializer::VisitPointers(Object** start, Object** current = start; while (current < end) { while (current < end && (*current)->IsSmi()) current++; - OutputRawData(reinterpret_cast
(current)); + if (current < end) OutputRawData(reinterpret_cast
(current)); while (current < end && !(*current)->IsSmi()) { serializer_->SerializeObject(*current, TAGGED_REPRESENTATION); @@ -2300,6 +2309,33 @@ void Serializer2::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) { } +void Serializer2::ObjectSerializer::VisitExternalAsciiString( + v8::String::ExternalAsciiStringResource** resource_pointer) { + Address references_start = reinterpret_cast
(resource_pointer); + OutputRawData(references_start); + for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { + // Use raw_unchecked when maps are munged. + Object* source = Heap::raw_unchecked_natives_source_cache()->get(i); + if (!source->IsUndefined()) { + // Don't use cast when maps are munged. + ExternalAsciiString* string = + reinterpret_cast(source); + typedef v8::String::ExternalAsciiStringResource Resource; + Resource* resource = string->resource(); + if (resource == *resource_pointer) { + sink_->Put(NATIVES_STRING_RESOURCE, "NativesStringResource"); + sink_->PutSection(i, "NativesStringResourceEnd"); + bytes_processed_so_far_ += sizeof(resource); + return; + } + } + } + // One of the strings in the natives cache should match the resource. We + // can't serialize any other kinds of external strings. + UNREACHABLE(); +} + + void Serializer2::ObjectSerializer::OutputRawData(Address up_to) { Address object_start = object_->address(); int up_to_offset = up_to - object_start; diff --git a/src/serialize.h b/src/serialize.h index d634a80..430cb03 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -441,7 +441,8 @@ class SerDes: public GenericDeserializer { EXTERNAL_BRANCH_TARGET_SERIALIZATION = 35, SYNCHRONIZE = 36, START_NEW_PAGE_SERIALIZATION = 37, - // Free: 38-47. + NATIVES_STRING_RESOURCE = 38, + // Free: 39-47. BACKREF_SERIALIZATION = 48, // One per space, must be kSpaceMask aligned. // Free: 57-63. @@ -567,6 +568,14 @@ class Serializer2 : public SerDes { void VisitExternalReferences(Address* start, Address* end); void VisitCodeTarget(RelocInfo* target); void VisitRuntimeEntry(RelocInfo* reloc); + // Used for seralizing the external strings that hold the natives source. + void VisitExternalAsciiString( + v8::String::ExternalAsciiStringResource** resource); + // We can't serialize a heap with external two byte strings. + void VisitExternalTwoByteString( + v8::String::ExternalStringResource** resource) { + UNREACHABLE(); + } private: void OutputRawData(Address up_to); diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index fa61542..4f4d88d 100644 --- a/test/cctest/cctest.status +++ b/test/cctest/cctest.status @@ -35,9 +35,9 @@ test-api/ApplyInterruption: PASS || TIMEOUT # This is about to go away anyway since new snapshot code is on the way. test-serialize/Deserialize: FAIL -test-serialize/DeserializeAndRunScript: FAIL -test-serialize/DeserializeNatives: FAIL -test-serialize/DeserializeExtensions: FAIL +test-serialize/DeserializeAndRunScript: FAIL || CRASH +test-serialize/DeserializeNatives: FAIL || CRASH +test-serialize/DeserializeExtensions: FAIL || CRASH # These tests always fail. They are here to test test.py. If # they don't fail then test.py has failed. diff --git a/tools/js2c.py b/tools/js2c.py index 2b7dbdf..b889530 100755 --- a/tools/js2c.py +++ b/tools/js2c.py @@ -301,7 +301,7 @@ def JS2C(source, target, env): else: ids.append((id, len(lines))) source_lines.append(SOURCE_DECLARATION % { 'id': id, 'data': data }) - source_lines_empty.append(SOURCE_DECLARATION % { 'id': id, 'data': 0 }) + source_lines_empty.append(SOURCE_DECLARATION % { 'id': id, 'data': data }) # Build delay support functions get_index_cases = [ ] -- 2.7.4