mksnapshot.cc revision 402d937239b0e2fd11bf2f4fe972ad78aa9fd481
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 41namespace i = v8::internal; 42using namespace v8; 43 44static const unsigned int kMaxCounters = 256; 45 46// A single counter in a counter collection. 47class 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 67class 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 90static CounterCollection local_counters; 91 92 93typedef std::map<std::string, int*> CounterMap; 94typedef std::map<std::string, int*>::iterator CounterMapIterator; 95static CounterMap counter_table_; 96 97 98class 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 207int 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::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 i::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