// Copyright 2006-2008 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #ifdef COMPRESS_STARTUP_DATA_BZ2 #include #endif #include #include "v8.h" #include "bootstrapper.h" #include "flags.h" #include "natives.h" #include "platform.h" #include "serialize.h" #include "list.h" using namespace v8; static const unsigned int kMaxCounters = 256; // A single counter in a counter collection. class Counter { public: static const int kMaxNameSize = 64; int32_t* Bind(const char* name) { int i; for (i = 0; i < kMaxNameSize - 1 && name[i]; i++) { name_[i] = name[i]; } name_[i] = '\0'; return &counter_; } private: int32_t counter_; uint8_t name_[kMaxNameSize]; }; // A set of counters and associated information. An instance of this // class is stored directly in the memory-mapped counters file if // the --save-counters options is used class CounterCollection { public: CounterCollection() { magic_number_ = 0xDEADFACE; max_counters_ = kMaxCounters; max_name_size_ = Counter::kMaxNameSize; counters_in_use_ = 0; } Counter* GetNextCounter() { if (counters_in_use_ == kMaxCounters) return NULL; return &counters_[counters_in_use_++]; } private: uint32_t magic_number_; uint32_t max_counters_; uint32_t max_name_size_; uint32_t counters_in_use_; Counter counters_[kMaxCounters]; }; class Compressor { public: virtual ~Compressor() {} virtual bool Compress(i::Vector input) = 0; virtual i::Vector* output() = 0; }; class PartialSnapshotSink : public i::SnapshotByteSink { public: PartialSnapshotSink() : data_(), raw_size_(-1) { } virtual ~PartialSnapshotSink() { data_.Free(); } virtual void Put(int byte, const char* description) { data_.Add(byte); } virtual int Position() { return data_.length(); } void Print(FILE* fp) { int length = Position(); for (int j = 0; j < length; j++) { if ((j & 0x1f) == 0x1f) { fprintf(fp, "\n"); } if (j != 0) { fprintf(fp, ","); } fprintf(fp, "%u", static_cast(at(j))); } } char at(int i) { return data_[i]; } bool Compress(Compressor* compressor) { ASSERT_EQ(-1, raw_size_); raw_size_ = data_.length(); if (!compressor->Compress(data_.ToVector())) return false; data_.Clear(); data_.AddAll(*compressor->output()); return true; } int raw_size() { return raw_size_; } private: i::List data_; int raw_size_; }; class CppByteSink : public PartialSnapshotSink { public: explicit CppByteSink(const char* snapshot_file) { fp_ = i::OS::FOpen(snapshot_file, "wb"); if (fp_ == NULL) { i::PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file); exit(1); } fprintf(fp_, "// Autogenerated snapshot file. Do not edit.\n\n"); fprintf(fp_, "#include \"v8.h\"\n"); fprintf(fp_, "#include \"platform.h\"\n\n"); fprintf(fp_, "#include \"snapshot.h\"\n\n"); fprintf(fp_, "namespace v8 {\nnamespace internal {\n\n"); fprintf(fp_, "const byte Snapshot::data_[] = {"); } virtual ~CppByteSink() { fprintf(fp_, "const int Snapshot::size_ = %d;\n", Position()); #ifdef COMPRESS_STARTUP_DATA_BZ2 fprintf(fp_, "const byte* Snapshot::raw_data_ = NULL;\n"); fprintf(fp_, "const int Snapshot::raw_size_ = %d;\n\n", raw_size()); #else fprintf(fp_, "const byte* Snapshot::raw_data_ = Snapshot::data_;\n"); fprintf(fp_, "const int Snapshot::raw_size_ = Snapshot::size_;\n\n"); #endif fprintf(fp_, "} } // namespace v8::internal\n"); fclose(fp_); } void WriteSpaceUsed( const char* prefix, 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) { fprintf(fp_, "const int Snapshot::%snew_space_used_ = %d;\n", prefix, new_space_used); fprintf(fp_, "const int Snapshot::%spointer_space_used_ = %d;\n", prefix, pointer_space_used); fprintf(fp_, "const int Snapshot::%sdata_space_used_ = %d;\n", prefix, data_space_used); fprintf(fp_, "const int Snapshot::%scode_space_used_ = %d;\n", prefix, code_space_used); fprintf(fp_, "const int Snapshot::%smap_space_used_ = %d;\n", prefix, map_space_used); fprintf(fp_, "const int Snapshot::%scell_space_used_ = %d;\n", prefix, cell_space_used); fprintf(fp_, "const int Snapshot::%sproperty_cell_space_used_ = %d;\n", prefix, property_cell_space_used); } void WritePartialSnapshot() { int length = partial_sink_.Position(); fprintf(fp_, "};\n\n"); fprintf(fp_, "const int Snapshot::context_size_ = %d;\n", length); #ifdef COMPRESS_STARTUP_DATA_BZ2 fprintf(fp_, "const int Snapshot::context_raw_size_ = %d;\n", partial_sink_.raw_size()); #else fprintf(fp_, "const int Snapshot::context_raw_size_ = " "Snapshot::context_size_;\n"); #endif fprintf(fp_, "const byte Snapshot::context_data_[] = {\n"); partial_sink_.Print(fp_); fprintf(fp_, "};\n\n"); #ifdef COMPRESS_STARTUP_DATA_BZ2 fprintf(fp_, "const byte* Snapshot::context_raw_data_ = NULL;\n"); #else fprintf(fp_, "const byte* Snapshot::context_raw_data_ =" " Snapshot::context_data_;\n"); #endif } void WriteSnapshot() { Print(fp_); } PartialSnapshotSink* partial_sink() { return &partial_sink_; } private: FILE* fp_; PartialSnapshotSink partial_sink_; }; #ifdef COMPRESS_STARTUP_DATA_BZ2 class BZip2Compressor : public Compressor { public: BZip2Compressor() : output_(NULL) {} virtual ~BZip2Compressor() { delete output_; } virtual bool Compress(i::Vector input) { delete output_; output_ = new i::ScopedVector((input.length() * 101) / 100 + 1000); unsigned int output_length_ = output_->length(); int result = BZ2_bzBuffToBuffCompress(output_->start(), &output_length_, input.start(), input.length(), 9, 1, 0); if (result == BZ_OK) { output_->Truncate(output_length_); return true; } else { fprintf(stderr, "bzlib error code: %d\n", result); return false; } } virtual i::Vector* output() { return output_; } private: i::ScopedVector* output_; }; class BZip2Decompressor : public StartupDataDecompressor { public: virtual ~BZip2Decompressor() { } protected: virtual int DecompressData(char* raw_data, int* raw_data_size, const char* compressed_data, int compressed_data_size) { ASSERT_EQ(StartupData::kBZip2, V8::GetCompressedStartupDataAlgorithm()); unsigned int decompressed_size = *raw_data_size; int result = BZ2_bzBuffToBuffDecompress(raw_data, &decompressed_size, const_cast(compressed_data), compressed_data_size, 0, 1); if (result == BZ_OK) { *raw_data_size = decompressed_size; } return result; } }; #endif void DumpException(Handle message) { String::Utf8Value message_string(message->Get()); String::Utf8Value message_line(message->GetSourceLine()); fprintf(stderr, "%s at line %d\n", *message_string, message->GetLineNumber()); fprintf(stderr, "%s\n", *message_line); for (int i = 0; i <= message->GetEndColumn(); ++i) { fprintf(stderr, "%c", i < message->GetStartColumn() ? ' ' : '^'); } fprintf(stderr, "\n"); } int main(int argc, char** argv) { V8::InitializeICU(); // By default, log code create information in the snapshot. i::FLAG_log_code = true; // Disable the i18n extension, as it doesn't support being snapshotted yet. i::FLAG_enable_i18n = false; // Print the usage if an error occurs when parsing the command line // flags or if the help flag is set. int result = i::FlagList::SetFlagsFromCommandLine(&argc, argv, true); if (result > 0 || argc != 2 || i::FLAG_help) { ::printf("Usage: %s [flag] ... outfile\n", argv[0]); i::FlagList::PrintHelp(); return !i::FLAG_help; } #ifdef COMPRESS_STARTUP_DATA_BZ2 BZip2Decompressor natives_decompressor; int bz2_result = natives_decompressor.Decompress(); if (bz2_result != BZ_OK) { fprintf(stderr, "bzip error code: %d\n", bz2_result); exit(1); } #endif i::Serializer::Enable(); Isolate* isolate = Isolate::GetCurrent(); Persistent context; { HandleScope handle_scope(isolate); context.Reset(isolate, Context::New(isolate)); } if (context.IsEmpty()) { fprintf(stderr, "\nException thrown while compiling natives - see above.\n\n"); exit(1); } if (i::FLAG_extra_code != NULL) { // Capture 100 frames if anything happens. V8::SetCaptureStackTraceForUncaughtExceptions(true, 100); HandleScope scope(isolate); v8::Context::Scope(v8::Local::New(isolate, context)); const char* name = i::FLAG_extra_code; FILE* file = i::OS::FOpen(name, "rb"); if (file == NULL) { fprintf(stderr, "Failed to open '%s': errno %d\n", name, errno); exit(1); } fseek(file, 0, SEEK_END); int size = ftell(file); rewind(file); char* chars = new char[size + 1]; chars[size] = '\0'; for (int i = 0; i < size;) { int read = static_cast(fread(&chars[i], 1, size - i, file)); if (read < 0) { fprintf(stderr, "Failed to read '%s': errno %d\n", name, errno); exit(1); } i += read; } fclose(file); Local source = String::New(chars); TryCatch try_catch; Local