1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <errno.h> 6 #include <signal.h> 7 #include <stdio.h> 8 9 #include "include/libplatform/libplatform.h" 10 #include "src/assembler.h" 11 #include "src/base/platform/platform.h" 12 #include "src/flags.h" 13 #include "src/list.h" 14 #include "src/snapshot/natives.h" 15 #include "src/snapshot/partial-serializer.h" 16 #include "src/snapshot/startup-serializer.h" 17 18 using namespace v8; 19 20 class SnapshotWriter { 21 public: 22 SnapshotWriter() : fp_(NULL), startup_blob_file_(NULL) {} 23 24 ~SnapshotWriter() { 25 if (fp_) fclose(fp_); 26 if (startup_blob_file_) fclose(startup_blob_file_); 27 } 28 29 void SetSnapshotFile(const char* snapshot_file) { 30 if (snapshot_file != NULL) fp_ = GetFileDescriptorOrDie(snapshot_file); 31 } 32 33 void SetStartupBlobFile(const char* startup_blob_file) { 34 if (startup_blob_file != NULL) 35 startup_blob_file_ = GetFileDescriptorOrDie(startup_blob_file); 36 } 37 38 void WriteSnapshot(v8::StartupData blob) const { 39 i::Vector<const i::byte> blob_vector( 40 reinterpret_cast<const i::byte*>(blob.data), blob.raw_size); 41 MaybeWriteSnapshotFile(blob_vector); 42 MaybeWriteStartupBlob(blob_vector); 43 } 44 45 private: 46 void MaybeWriteStartupBlob(const i::Vector<const i::byte>& blob) const { 47 if (!startup_blob_file_) return; 48 49 size_t written = fwrite(blob.begin(), 1, blob.length(), startup_blob_file_); 50 if (written != static_cast<size_t>(blob.length())) { 51 i::PrintF("Writing snapshot file failed.. Aborting.\n"); 52 exit(1); 53 } 54 } 55 56 void MaybeWriteSnapshotFile(const i::Vector<const i::byte>& blob) const { 57 if (!fp_) return; 58 59 WriteFilePrefix(); 60 WriteData(blob); 61 WriteFileSuffix(); 62 } 63 64 void WriteFilePrefix() const { 65 fprintf(fp_, "// Autogenerated snapshot file. Do not edit.\n\n"); 66 fprintf(fp_, "#include \"src/v8.h\"\n"); 67 fprintf(fp_, "#include \"src/base/platform/platform.h\"\n\n"); 68 fprintf(fp_, "#include \"src/snapshot/snapshot.h\"\n\n"); 69 fprintf(fp_, "namespace v8 {\n"); 70 fprintf(fp_, "namespace internal {\n\n"); 71 } 72 73 void WriteFileSuffix() const { 74 fprintf(fp_, "const v8::StartupData* Snapshot::DefaultSnapshotBlob() {\n"); 75 fprintf(fp_, " return &blob;\n"); 76 fprintf(fp_, "}\n\n"); 77 fprintf(fp_, "} // namespace internal\n"); 78 fprintf(fp_, "} // namespace v8\n"); 79 } 80 81 void WriteData(const i::Vector<const i::byte>& blob) const { 82 fprintf(fp_, "static const byte blob_data[] = {\n"); 83 WriteSnapshotData(blob); 84 fprintf(fp_, "};\n"); 85 fprintf(fp_, "static const int blob_size = %d;\n", blob.length()); 86 fprintf(fp_, "static const v8::StartupData blob =\n"); 87 fprintf(fp_, "{ (const char*) blob_data, blob_size };\n"); 88 } 89 90 void WriteSnapshotData(const i::Vector<const i::byte>& blob) const { 91 for (int i = 0; i < blob.length(); i++) { 92 if ((i & 0x1f) == 0x1f) fprintf(fp_, "\n"); 93 if (i > 0) fprintf(fp_, ","); 94 fprintf(fp_, "%u", static_cast<unsigned char>(blob.at(i))); 95 } 96 fprintf(fp_, "\n"); 97 } 98 99 FILE* GetFileDescriptorOrDie(const char* filename) { 100 FILE* fp = base::OS::FOpen(filename, "wb"); 101 if (fp == NULL) { 102 i::PrintF("Unable to open file \"%s\" for writing.\n", filename); 103 exit(1); 104 } 105 return fp; 106 } 107 108 FILE* fp_; 109 FILE* startup_blob_file_; 110 }; 111 112 char* GetExtraCode(char* filename, const char* description) { 113 if (filename == NULL || strlen(filename) == 0) return NULL; 114 ::printf("Loading script for %s: %s\n", description, filename); 115 FILE* file = base::OS::FOpen(filename, "rb"); 116 if (file == NULL) { 117 fprintf(stderr, "Failed to open '%s': errno %d\n", filename, errno); 118 exit(1); 119 } 120 fseek(file, 0, SEEK_END); 121 size_t size = ftell(file); 122 rewind(file); 123 char* chars = new char[size + 1]; 124 chars[size] = '\0'; 125 for (size_t i = 0; i < size;) { 126 size_t read = fread(&chars[i], 1, size - i, file); 127 if (ferror(file)) { 128 fprintf(stderr, "Failed to read '%s': errno %d\n", filename, errno); 129 exit(1); 130 } 131 i += read; 132 } 133 fclose(file); 134 return chars; 135 } 136 137 138 int main(int argc, char** argv) { 139 // Make mksnapshot runs predictable to create reproducible snapshots. 140 i::FLAG_predictable = true; 141 142 // Print the usage if an error occurs when parsing the command line 143 // flags or if the help flag is set. 144 int result = i::FlagList::SetFlagsFromCommandLine(&argc, argv, true); 145 if (result > 0 || (argc > 3) || i::FLAG_help) { 146 ::printf("Usage: %s --startup_src=... --startup_blob=... [extras]\n", 147 argv[0]); 148 i::FlagList::PrintHelp(); 149 return !i::FLAG_help; 150 } 151 152 i::CpuFeatures::Probe(true); 153 V8::InitializeICUDefaultLocation(argv[0]); 154 v8::Platform* platform = v8::platform::CreateDefaultPlatform(); 155 v8::V8::InitializePlatform(platform); 156 v8::V8::Initialize(); 157 158 { 159 SnapshotWriter writer; 160 if (i::FLAG_startup_src) writer.SetSnapshotFile(i::FLAG_startup_src); 161 if (i::FLAG_startup_blob) writer.SetStartupBlobFile(i::FLAG_startup_blob); 162 163 char* embed_script = GetExtraCode(argc >= 2 ? argv[1] : NULL, "embedding"); 164 StartupData blob = v8::V8::CreateSnapshotDataBlob(embed_script); 165 delete[] embed_script; 166 167 char* warmup_script = GetExtraCode(argc >= 3 ? argv[2] : NULL, "warm up"); 168 if (warmup_script) { 169 StartupData cold = blob; 170 blob = v8::V8::WarmUpSnapshotDataBlob(cold, warmup_script); 171 delete[] cold.data; 172 delete[] warmup_script; 173 } 174 175 CHECK(blob.data); 176 writer.WriteSnapshot(blob); 177 delete[] blob.data; 178 } 179 180 V8::Dispose(); 181 V8::ShutdownPlatform(); 182 delete platform; 183 return 0; 184 } 185