Home | History | Annotate | Download | only in src
      1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifdef COMPRESS_STARTUP_DATA_BZ2
     29 #include <bzlib.h>
     30 #endif
     31 #include <signal.h>
     32 
     33 #include "v8.h"
     34 
     35 #include "bootstrapper.h"
     36 #include "natives.h"
     37 #include "platform.h"
     38 #include "serialize.h"
     39 #include "list.h"
     40 
     41 using namespace v8;
     42 
     43 static const unsigned int kMaxCounters = 256;
     44 
     45 // A single counter in a counter collection.
     46 class Counter {
     47  public:
     48   static const int kMaxNameSize = 64;
     49   int32_t* Bind(const char* name) {
     50     int i;
     51     for (i = 0; i < kMaxNameSize - 1 && name[i]; i++) {
     52       name_[i] = name[i];
     53     }
     54     name_[i] = '\0';
     55     return &counter_;
     56   }
     57  private:
     58   int32_t counter_;
     59   uint8_t name_[kMaxNameSize];
     60 };
     61 
     62 
     63 // A set of counters and associated information.  An instance of this
     64 // class is stored directly in the memory-mapped counters file if
     65 // the --save-counters options is used
     66 class CounterCollection {
     67  public:
     68   CounterCollection() {
     69     magic_number_ = 0xDEADFACE;
     70     max_counters_ = kMaxCounters;
     71     max_name_size_ = Counter::kMaxNameSize;
     72     counters_in_use_ = 0;
     73   }
     74   Counter* GetNextCounter() {
     75     if (counters_in_use_ == kMaxCounters) return NULL;
     76     return &counters_[counters_in_use_++];
     77   }
     78  private:
     79   uint32_t magic_number_;
     80   uint32_t max_counters_;
     81   uint32_t max_name_size_;
     82   uint32_t counters_in_use_;
     83   Counter counters_[kMaxCounters];
     84 };
     85 
     86 
     87 class Compressor {
     88  public:
     89   virtual ~Compressor() {}
     90   virtual bool Compress(i::Vector<char> input) = 0;
     91   virtual i::Vector<char>* output() = 0;
     92 };
     93 
     94 
     95 class PartialSnapshotSink : public i::SnapshotByteSink {
     96  public:
     97   PartialSnapshotSink() : data_(), raw_size_(-1) { }
     98   virtual ~PartialSnapshotSink() { data_.Free(); }
     99   virtual void Put(int byte, const char* description) {
    100     data_.Add(byte);
    101   }
    102   virtual int Position() { return data_.length(); }
    103   void Print(FILE* fp) {
    104     int length = Position();
    105     for (int j = 0; j < length; j++) {
    106       if ((j & 0x1f) == 0x1f) {
    107         fprintf(fp, "\n");
    108       }
    109       if (j != 0) {
    110         fprintf(fp, ",");
    111       }
    112       fprintf(fp, "%u", static_cast<unsigned char>(at(j)));
    113     }
    114   }
    115   char at(int i) { return data_[i]; }
    116   bool Compress(Compressor* compressor) {
    117     ASSERT_EQ(-1, raw_size_);
    118     raw_size_ = data_.length();
    119     if (!compressor->Compress(data_.ToVector())) return false;
    120     data_.Clear();
    121     data_.AddAll(*compressor->output());
    122     return true;
    123   }
    124   int raw_size() { return raw_size_; }
    125 
    126  private:
    127   i::List<char> data_;
    128   int raw_size_;
    129 };
    130 
    131 
    132 class CppByteSink : public PartialSnapshotSink {
    133  public:
    134   explicit CppByteSink(const char* snapshot_file) {
    135     fp_ = i::OS::FOpen(snapshot_file, "wb");
    136     if (fp_ == NULL) {
    137       i::PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file);
    138       exit(1);
    139     }
    140     fprintf(fp_, "// Autogenerated snapshot file. Do not edit.\n\n");
    141     fprintf(fp_, "#include \"v8.h\"\n");
    142     fprintf(fp_, "#include \"platform.h\"\n\n");
    143     fprintf(fp_, "#include \"snapshot.h\"\n\n");
    144     fprintf(fp_, "namespace v8 {\nnamespace internal {\n\n");
    145     fprintf(fp_, "const byte Snapshot::data_[] = {");
    146   }
    147 
    148   virtual ~CppByteSink() {
    149     fprintf(fp_, "const int Snapshot::size_ = %d;\n", Position());
    150 #ifdef COMPRESS_STARTUP_DATA_BZ2
    151     fprintf(fp_, "const byte* Snapshot::raw_data_ = NULL;\n");
    152     fprintf(fp_,
    153             "const int Snapshot::raw_size_ = %d;\n\n",
    154             raw_size());
    155 #else
    156     fprintf(fp_,
    157             "const byte* Snapshot::raw_data_ = Snapshot::data_;\n");
    158     fprintf(fp_,
    159             "const int Snapshot::raw_size_ = Snapshot::size_;\n\n");
    160 #endif
    161     fprintf(fp_, "} }  // namespace v8::internal\n");
    162     fclose(fp_);
    163   }
    164 
    165   void WriteSpaceUsed(
    166       int new_space_used,
    167       int pointer_space_used,
    168       int data_space_used,
    169       int code_space_used,
    170       int map_space_used,
    171       int cell_space_used,
    172       int large_space_used) {
    173     fprintf(fp_, "const int Snapshot::new_space_used_ = %d;\n", new_space_used);
    174     fprintf(fp_,
    175             "const int Snapshot::pointer_space_used_ = %d;\n",
    176             pointer_space_used);
    177     fprintf(fp_,
    178             "const int Snapshot::data_space_used_ = %d;\n",
    179             data_space_used);
    180     fprintf(fp_,
    181             "const int Snapshot::code_space_used_ = %d;\n",
    182             code_space_used);
    183     fprintf(fp_, "const int Snapshot::map_space_used_ = %d;\n", map_space_used);
    184     fprintf(fp_,
    185             "const int Snapshot::cell_space_used_ = %d;\n",
    186             cell_space_used);
    187     fprintf(fp_,
    188             "const int Snapshot::large_space_used_ = %d;\n",
    189             large_space_used);
    190   }
    191 
    192   void WritePartialSnapshot() {
    193     int length = partial_sink_.Position();
    194     fprintf(fp_, "};\n\n");
    195     fprintf(fp_, "const int Snapshot::context_size_ = %d;\n",  length);
    196 #ifdef COMPRESS_STARTUP_DATA_BZ2
    197     fprintf(fp_,
    198             "const int Snapshot::context_raw_size_ = %d;\n",
    199             partial_sink_.raw_size());
    200 #else
    201     fprintf(fp_,
    202             "const int Snapshot::context_raw_size_ = "
    203             "Snapshot::context_size_;\n");
    204 #endif
    205     fprintf(fp_, "const byte Snapshot::context_data_[] = {\n");
    206     partial_sink_.Print(fp_);
    207     fprintf(fp_, "};\n\n");
    208 #ifdef COMPRESS_STARTUP_DATA_BZ2
    209     fprintf(fp_, "const byte* Snapshot::context_raw_data_ = NULL;\n");
    210 #else
    211     fprintf(fp_, "const byte* Snapshot::context_raw_data_ ="
    212             " Snapshot::context_data_;\n");
    213 #endif
    214   }
    215 
    216   void WriteSnapshot() {
    217     Print(fp_);
    218   }
    219 
    220   PartialSnapshotSink* partial_sink() { return &partial_sink_; }
    221 
    222  private:
    223   FILE* fp_;
    224   PartialSnapshotSink partial_sink_;
    225 };
    226 
    227 
    228 #ifdef COMPRESS_STARTUP_DATA_BZ2
    229 class BZip2Compressor : public Compressor {
    230  public:
    231   BZip2Compressor() : output_(NULL) {}
    232   virtual ~BZip2Compressor() {
    233     delete output_;
    234   }
    235   virtual bool Compress(i::Vector<char> input) {
    236     delete output_;
    237     output_ = new i::ScopedVector<char>((input.length() * 101) / 100 + 1000);
    238     unsigned int output_length_ = output_->length();
    239     int result = BZ2_bzBuffToBuffCompress(output_->start(), &output_length_,
    240                                           input.start(), input.length(),
    241                                           9, 1, 0);
    242     if (result == BZ_OK) {
    243       output_->Truncate(output_length_);
    244       return true;
    245     } else {
    246       fprintf(stderr, "bzlib error code: %d\n", result);
    247       return false;
    248     }
    249   }
    250   virtual i::Vector<char>* output() { return output_; }
    251 
    252  private:
    253   i::ScopedVector<char>* output_;
    254 };
    255 
    256 
    257 class BZip2Decompressor : public StartupDataDecompressor {
    258  public:
    259   virtual ~BZip2Decompressor() { }
    260 
    261  protected:
    262   virtual int DecompressData(char* raw_data,
    263                              int* raw_data_size,
    264                              const char* compressed_data,
    265                              int compressed_data_size) {
    266     ASSERT_EQ(StartupData::kBZip2,
    267               V8::GetCompressedStartupDataAlgorithm());
    268     unsigned int decompressed_size = *raw_data_size;
    269     int result =
    270         BZ2_bzBuffToBuffDecompress(raw_data,
    271                                    &decompressed_size,
    272                                    const_cast<char*>(compressed_data),
    273                                    compressed_data_size,
    274                                    0, 1);
    275     if (result == BZ_OK) {
    276       *raw_data_size = decompressed_size;
    277     }
    278     return result;
    279   }
    280 };
    281 #endif
    282 
    283 
    284 int main(int argc, char** argv) {
    285   // By default, log code create information in the snapshot.
    286   i::FLAG_log_code = true;
    287 
    288   // Print the usage if an error occurs when parsing the command line
    289   // flags or if the help flag is set.
    290   int result = i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
    291   if (result > 0 || argc != 2 || i::FLAG_help) {
    292     ::printf("Usage: %s [flag] ... outfile\n", argv[0]);
    293     i::FlagList::PrintHelp();
    294     return !i::FLAG_help;
    295   }
    296 #ifdef COMPRESS_STARTUP_DATA_BZ2
    297   BZip2Decompressor natives_decompressor;
    298   int bz2_result = natives_decompressor.Decompress();
    299   if (bz2_result != BZ_OK) {
    300     fprintf(stderr, "bzip error code: %d\n", bz2_result);
    301     exit(1);
    302   }
    303 #endif
    304   i::Serializer::Enable();
    305   Persistent<Context> context = v8::Context::New();
    306   ASSERT(!context.IsEmpty());
    307   // Make sure all builtin scripts are cached.
    308   { HandleScope scope;
    309     for (int i = 0; i < i::Natives::GetBuiltinsCount(); i++) {
    310       i::Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
    311     }
    312   }
    313   // If we don't do this then we end up with a stray root pointing at the
    314   // context even after we have disposed of the context.
    315   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags, "mksnapshot");
    316   i::Object* raw_context = *(v8::Utils::OpenHandle(*context));
    317   context.Dispose();
    318   CppByteSink sink(argv[1]);
    319   // This results in a somewhat smaller snapshot, probably because it gets rid
    320   // of some things that are cached between garbage collections.
    321   i::StartupSerializer ser(&sink);
    322   ser.SerializeStrongReferences();
    323 
    324   i::PartialSerializer partial_ser(&ser, sink.partial_sink());
    325   partial_ser.Serialize(&raw_context);
    326 
    327   ser.SerializeWeakReferences();
    328 
    329 #ifdef COMPRESS_STARTUP_DATA_BZ2
    330   BZip2Compressor compressor;
    331   if (!sink.Compress(&compressor))
    332     return 1;
    333   if (!sink.partial_sink()->Compress(&compressor))
    334     return 1;
    335 #endif
    336   sink.WriteSnapshot();
    337   sink.WritePartialSnapshot();
    338 
    339   sink.WriteSpaceUsed(
    340       partial_ser.CurrentAllocationAddress(i::NEW_SPACE),
    341       partial_ser.CurrentAllocationAddress(i::OLD_POINTER_SPACE),
    342       partial_ser.CurrentAllocationAddress(i::OLD_DATA_SPACE),
    343       partial_ser.CurrentAllocationAddress(i::CODE_SPACE),
    344       partial_ser.CurrentAllocationAddress(i::MAP_SPACE),
    345       partial_ser.CurrentAllocationAddress(i::CELL_SPACE),
    346       partial_ser.CurrentAllocationAddress(i::LO_SPACE));
    347   return 0;
    348 }
    349