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 #include <signal.h>
     29 #include <string>
     30 #include <map>
     31 
     32 #include "v8.h"
     33 
     34 #include "bootstrapper.h"
     35 #include "natives.h"
     36 #include "platform.h"
     37 #include "serialize.h"
     38 #include "list.h"
     39 
     40 // use explicit namespace to avoid clashing with types in namespace v8
     41 namespace i = v8::internal;
     42 using namespace v8;
     43 
     44 static const unsigned int kMaxCounters = 256;
     45 
     46 // A single counter in a counter collection.
     47 class Counter {
     48  public:
     49   static const int kMaxNameSize = 64;
     50   int32_t* Bind(const char* name) {
     51     int i;
     52     for (i = 0; i < kMaxNameSize - 1 && name[i]; i++) {
     53       name_[i] = name[i];
     54     }
     55     name_[i] = '\0';
     56     return &counter_;
     57   }
     58  private:
     59   int32_t counter_;
     60   uint8_t name_[kMaxNameSize];
     61 };
     62 
     63 
     64 // A set of counters and associated information.  An instance of this
     65 // class is stored directly in the memory-mapped counters file if
     66 // the --save-counters options is used
     67 class CounterCollection {
     68  public:
     69   CounterCollection() {
     70     magic_number_ = 0xDEADFACE;
     71     max_counters_ = kMaxCounters;
     72     max_name_size_ = Counter::kMaxNameSize;
     73     counters_in_use_ = 0;
     74   }
     75   Counter* GetNextCounter() {
     76     if (counters_in_use_ == kMaxCounters) return NULL;
     77     return &counters_[counters_in_use_++];
     78   }
     79  private:
     80   uint32_t magic_number_;
     81   uint32_t max_counters_;
     82   uint32_t max_name_size_;
     83   uint32_t counters_in_use_;
     84   Counter counters_[kMaxCounters];
     85 };
     86 
     87 
     88 // We statically allocate a set of local counters to be used if we
     89 // don't want to store the stats in a memory-mapped file
     90 static CounterCollection local_counters;
     91 
     92 
     93 typedef std::map<std::string, int*> CounterMap;
     94 typedef std::map<std::string, int*>::iterator CounterMapIterator;
     95 static CounterMap counter_table_;
     96 
     97 
     98 class CppByteSink : public i::SnapshotByteSink {
     99  public:
    100   explicit CppByteSink(const char* snapshot_file)
    101       : bytes_written_(0),
    102         partial_sink_(this) {
    103     fp_ = i::OS::FOpen(snapshot_file, "wb");
    104     if (fp_ == NULL) {
    105       i::PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file);
    106       exit(1);
    107     }
    108     fprintf(fp_, "// Autogenerated snapshot file. Do not edit.\n\n");
    109     fprintf(fp_, "#include \"v8.h\"\n");
    110     fprintf(fp_, "#include \"platform.h\"\n\n");
    111     fprintf(fp_, "#include \"snapshot.h\"\n\n");
    112     fprintf(fp_, "namespace v8 {\nnamespace internal {\n\n");
    113     fprintf(fp_, "const byte Snapshot::data_[] = {");
    114   }
    115 
    116   virtual ~CppByteSink() {
    117     fprintf(fp_, "const int Snapshot::size_ = %d;\n\n", bytes_written_);
    118     fprintf(fp_, "} }  // namespace v8::internal\n");
    119     fclose(fp_);
    120   }
    121 
    122   void WriteSpaceUsed(
    123       int new_space_used,
    124       int pointer_space_used,
    125       int data_space_used,
    126       int code_space_used,
    127       int map_space_used,
    128       int cell_space_used,
    129       int large_space_used) {
    130     fprintf(fp_, "};\n\n");
    131     fprintf(fp_, "const int Snapshot::new_space_used_ = %d;\n", new_space_used);
    132     fprintf(fp_,
    133             "const int Snapshot::pointer_space_used_ = %d;\n",
    134             pointer_space_used);
    135     fprintf(fp_,
    136             "const int Snapshot::data_space_used_ = %d;\n",
    137             data_space_used);
    138     fprintf(fp_,
    139             "const int Snapshot::code_space_used_ = %d;\n",
    140             code_space_used);
    141     fprintf(fp_, "const int Snapshot::map_space_used_ = %d;\n", map_space_used);
    142     fprintf(fp_,
    143             "const int Snapshot::cell_space_used_ = %d;\n",
    144             cell_space_used);
    145     fprintf(fp_,
    146             "const int Snapshot::large_space_used_ = %d;\n",
    147             large_space_used);
    148   }
    149 
    150   void WritePartialSnapshot() {
    151     int length = partial_sink_.Position();
    152     fprintf(fp_, "};\n\n");
    153     fprintf(fp_, "const int Snapshot::context_size_ = %d;\n",  length);
    154     fprintf(fp_, "const byte Snapshot::context_data_[] = {\n");
    155     for (int j = 0; j < length; j++) {
    156       if ((j & 0x1f) == 0x1f) {
    157         fprintf(fp_, "\n");
    158       }
    159       char byte = partial_sink_.at(j);
    160       if (j != 0) {
    161         fprintf(fp_, ",");
    162       }
    163       fprintf(fp_, "%d", byte);
    164     }
    165   }
    166 
    167   virtual void Put(int byte, const char* description) {
    168     if (bytes_written_ != 0) {
    169       fprintf(fp_, ",");
    170     }
    171     fprintf(fp_, "%d", byte);
    172     bytes_written_++;
    173     if ((bytes_written_ & 0x1f) == 0) {
    174       fprintf(fp_, "\n");
    175     }
    176   }
    177 
    178   virtual int Position() {
    179     return bytes_written_;
    180   }
    181 
    182   i::SnapshotByteSink* partial_sink() { return &partial_sink_; }
    183 
    184   class PartialSnapshotSink : public i::SnapshotByteSink {
    185    public:
    186     explicit PartialSnapshotSink(CppByteSink* parent)
    187         : parent_(parent),
    188           data_() { }
    189     virtual ~PartialSnapshotSink() { data_.Free(); }
    190     virtual void Put(int byte, const char* description) {
    191       data_.Add(byte);
    192     }
    193     virtual int Position() { return data_.length(); }
    194     char at(int i) { return data_[i]; }
    195    private:
    196     CppByteSink* parent_;
    197     i::List<char> data_;
    198   };
    199 
    200  private:
    201   FILE* fp_;
    202   int bytes_written_;
    203   PartialSnapshotSink partial_sink_;
    204 };
    205 
    206 
    207 int main(int argc, char** argv) {
    208 #ifdef ENABLE_LOGGING_AND_PROFILING
    209   // By default, log code create information in the snapshot.
    210   i::FLAG_log_code = true;
    211 #endif
    212   // Print the usage if an error occurs when parsing the command line
    213   // flags or if the help flag is set.
    214   int result = i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
    215   if (result > 0 || argc != 2 || i::FLAG_help) {
    216     ::printf("Usage: %s [flag] ... outfile\n", argv[0]);
    217     i::FlagList::PrintHelp();
    218     return !i::FLAG_help;
    219   }
    220   i::Serializer::Enable();
    221   Persistent<Context> context = v8::Context::New();
    222   ASSERT(!context.IsEmpty());
    223   // Make sure all builtin scripts are cached.
    224   { HandleScope scope;
    225     for (int i = 0; i < i::Natives::GetBuiltinsCount(); i++) {
    226       i::Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
    227     }
    228   }
    229   // If we don't do this then we end up with a stray root pointing at the
    230   // context even after we have disposed of the context.
    231   HEAP->CollectAllGarbage(true);
    232   i::Object* raw_context = *(v8::Utils::OpenHandle(*context));
    233   context.Dispose();
    234   CppByteSink sink(argv[1]);
    235   // This results in a somewhat smaller snapshot, probably because it gets rid
    236   // of some things that are cached between garbage collections.
    237   i::StartupSerializer ser(&sink);
    238   ser.SerializeStrongReferences();
    239 
    240   i::PartialSerializer partial_ser(&ser, sink.partial_sink());
    241   partial_ser.Serialize(&raw_context);
    242 
    243   ser.SerializeWeakReferences();
    244 
    245   sink.WritePartialSnapshot();
    246 
    247   sink.WriteSpaceUsed(
    248       partial_ser.CurrentAllocationAddress(i::NEW_SPACE),
    249       partial_ser.CurrentAllocationAddress(i::OLD_POINTER_SPACE),
    250       partial_ser.CurrentAllocationAddress(i::OLD_DATA_SPACE),
    251       partial_ser.CurrentAllocationAddress(i::CODE_SPACE),
    252       partial_ser.CurrentAllocationAddress(i::MAP_SPACE),
    253       partial_ser.CurrentAllocationAddress(i::CELL_SPACE),
    254       partial_ser.CurrentAllocationAddress(i::LO_SPACE));
    255   return 0;
    256 }
    257