},
'gdbjit:on': {
'CPPDEFINES': ['ENABLE_GDB_JIT_INTERFACE']
+ },
+ 'compress_startup_data:bz2': {
+ 'CPPDEFINES': ['COMPRESS_STARTUP_DATA_BZ2']
}
},
'msvc': {
'os:win32': {
'LIBS': ['winmm', 'ws2_32'],
},
+ 'compress_startup_data:bz2': {
+ 'os:linux': {
+ 'LIBS': ['bz2']
+ }
+ },
},
'msvc': {
'all': {
'CCFLAGS': ['-g', '-O0'],
'CPPDEFINES': ['DEBUG']
},
+ 'compress_startup_data:bz2': {
+ 'CPPDEFINES': ['COMPRESS_STARTUP_DATA_BZ2'],
+ 'os:linux': {
+ 'LIBS': ['bz2']
+ }
+ },
},
'msvc': {
'all': {
'values': ['mips32r2', 'mips32r1'],
'default': 'mips32r2',
'help': 'mips variant'
- }
+ },
+ 'compress_startup_data': {
+ 'values': ['off', 'bz2'],
+ 'default': 'off',
+ 'help': 'compress startup data (snapshot) [Linux only]'
+ },
}
ALL_OPTIONS = dict(PLATFORM_OPTIONS, **SIMPLE_OPTIONS)
print env['arch']
print env['simulator']
Abort("Option unalignedaccesses only supported for the ARM architecture.")
+ if env['os'] != 'linux' and env['compress_startup_data'] != 'off':
+ Abort("Startup data compression is only available on Linux")
for (name, option) in ALL_OPTIONS.iteritems():
if (not name in env):
message = ("A value for option %s must be specified (%s)." %
};
+class StartupData {
+ public:
+ enum CompressionAlgorithm {
+ kUncompressed,
+ kBZip2
+ };
+
+ const char* data;
+ int compressed_size;
+ int raw_size;
+};
+
/**
* Container class for static utility functions.
*/
static bool IsDead();
/**
+ * The following 4 functions are to be used when V8 is built with
+ * the 'compress_startup_data' flag enabled. In this case, the
+ * embedder must decompress startup data prior to initializing V8.
+ *
+ * This is how interaction with V8 should look like:
+ * int compressed_data_count = v8::V8::GetCompressedStartupDataCount();
+ * v8::StartupData* compressed_data =
+ * new v8::StartupData[compressed_data_count];
+ * v8::V8::GetCompressedStartupData(compressed_data);
+ * ... decompress data (compressed_data can be updated in-place) ...
+ * v8::V8::SetDecompressedStartupData(compressed_data);
+ * ... now V8 can be initialized
+ * ... make sure the decompressed data stays valid until V8 shutdown
+ */
+ static StartupData::CompressionAlgorithm GetCompressedStartupDataAlgorithm();
+ static int GetCompressedStartupDataCount();
+ static void GetCompressedStartupData(StartupData* compressed_data);
+ static void SetDecompressedStartupData(StartupData* decompressed_data);
+
+ /**
* Adds a message listener.
*
* The same message listener can be added more than once and it that
#include <string>
#include <map>
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+#error Using compressed startup data is not supported for this sample
+#endif
+
using namespace std;
using namespace v8;
#include <v8.h>
#include <v8-testing.h>
#include <assert.h>
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+#include <bzlib.h>
+#endif
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
}
}
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+ ASSERT_EQ(v8::StartupData::kBZip2,
+ v8::V8::GetCompressedStartupDataAlgorithm());
+ int compressed_data_count = v8::V8::GetCompressedStartupDataCount();
+ v8::StartupData* compressed_data = new v8::StartupData[compressed_data_count];
+ v8::V8::GetCompressedStartupData(compressed_data);
+ for (int i = 0; i < compressed_data_count; ++i) {
+ char* decompressed = new char[compressed_data[i].raw_size];
+ unsigned int decompressed_size = compressed_data[i].raw_size;
+ int result =
+ BZ2_bzBuffToBuffDecompress(decompressed,
+ &decompressed_size,
+ const_cast<char*>(compressed_data[i].data),
+ compressed_data[i].compressed_size,
+ 0, 1);
+ if (result != BZ_OK) {
+ fprintf(stderr, "bzip error code: %d\n", result);
+ exit(1);
+ }
+ compressed_data[i].data = decompressed;
+ compressed_data[i].raw_size = decompressed_size;
+ }
+ v8::V8::SetDecompressedStartupData(compressed_data);
+#endif // COMPRESS_STARTUP_DATA_BZ2
+
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
int result = 0;
if (FLAG_stress_opt || FLAG_stress_deopt) {
result = RunMain(argc, argv);
}
v8::V8::Dispose();
+
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+ for (int i = 0; i < compressed_data_count; ++i) {
+ delete[] compressed_data[i].data;
+ }
+ delete[] compressed_data;
+#endif // COMPRESS_STARTUP_DATA_BZ2
+
return result;
}
}
+StartupData::CompressionAlgorithm V8::GetCompressedStartupDataAlgorithm() {
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+ return StartupData::kBZip2;
+#else
+ return StartupData::kUncompressed;
+#endif
+}
+
+
+enum CompressedStartupDataItems {
+ kSnapshot = 0,
+ kSnapshotContext,
+ kCompressedStartupDataCount
+};
+
+int V8::GetCompressedStartupDataCount() {
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+ return kCompressedStartupDataCount;
+#else
+ return 0;
+#endif
+}
+
+
+void V8::GetCompressedStartupData(StartupData* compressed_data) {
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+ compressed_data[kSnapshot].data =
+ reinterpret_cast<const char*>(i::Snapshot::data());
+ compressed_data[kSnapshot].compressed_size = i::Snapshot::size();
+ compressed_data[kSnapshot].raw_size = i::Snapshot::raw_size();
+
+ compressed_data[kSnapshotContext].data =
+ reinterpret_cast<const char*>(i::Snapshot::context_data());
+ compressed_data[kSnapshotContext].compressed_size =
+ i::Snapshot::context_size();
+ compressed_data[kSnapshotContext].raw_size = i::Snapshot::context_raw_size();
+#endif
+}
+
+
+void V8::SetDecompressedStartupData(StartupData* decompressed_data) {
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+ ASSERT_EQ(i::Snapshot::raw_size(), decompressed_data[kSnapshot].raw_size);
+ i::Snapshot::set_raw_data(
+ reinterpret_cast<const i::byte*>(decompressed_data[kSnapshot].data));
+
+ ASSERT_EQ(i::Snapshot::context_raw_size(),
+ decompressed_data[kSnapshotContext].raw_size);
+ i::Snapshot::set_context_raw_data(
+ reinterpret_cast<const i::byte*>(
+ decompressed_data[kSnapshotContext].data));
+#endif
+}
+
+
void V8::SetFatalErrorHandler(FatalErrorCallback that) {
i::Isolate* isolate = EnterIsolateIfNeeded();
isolate->set_exception_behavior(that);
#include "v8.h"
#include "hashmap.h"
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+#error Using compressed startup data is not supported for D8
+#endif
namespace v8 {
template<typename T, class P>
void List<T, P>::AddAll(const List<T, P>& other) {
- int result_length = length_ + other.length_;
+ AddAll(other.ToVector());
+}
+
+
+template<typename T, class P>
+void List<T, P>::AddAll(const Vector<T>& other) {
+ int result_length = length_ + other.length();
if (capacity_ < result_length) Resize(result_length);
- for (int i = 0; i < other.length_; i++) {
- data_[length_ + i] = other.data_[i];
+ for (int i = 0; i < other.length(); i++) {
+ data_[length_ + i] = other.at(i);
}
length_ = result_length;
}
INLINE(int length() const) { return length_; }
INLINE(int capacity() const) { return capacity_; }
- Vector<T> ToVector() { return Vector<T>(data_, length_); }
+ Vector<T> ToVector() const { return Vector<T>(data_, length_); }
Vector<const T> ToConstVector() { return Vector<const T>(data_, length_); }
// Add all the elements from the argument list to this list.
void AddAll(const List<T, P>& other);
+ // Add all the elements from the vector to this list.
+ void AddAll(const Vector<T>& other);
+
// Inserts the element at the specific index.
void InsertAt(int index, const T& element);
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+#include <bzlib.h>
+#endif
#include <signal.h>
#include <string>
#include <map>
static CounterMap counter_table_;
-class CppByteSink : public i::SnapshotByteSink {
+class Compressor {
public:
- explicit CppByteSink(const char* snapshot_file)
- : bytes_written_(0),
- partial_sink_(this) {
+ virtual ~Compressor() {}
+ virtual bool Compress(i::Vector<char> input) = 0;
+ virtual i::Vector<char>* 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, "%d", 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<char> 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);
}
virtual ~CppByteSink() {
- fprintf(fp_, "const int Snapshot::size_ = %d;\n\n", bytes_written_);
+ 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_);
}
int map_space_used,
int cell_space_used,
int large_space_used) {
- fprintf(fp_, "};\n\n");
fprintf(fp_, "const int Snapshot::new_space_used_ = %d;\n", new_space_used);
fprintf(fp_,
"const int Snapshot::pointer_space_used_ = %d;\n",
int length = partial_sink_.Position();
fprintf(fp_, "};\n\n");
fprintf(fp_, "const int Snapshot::context_size_ = %d;\n", length);
+ fprintf(fp_,
+ "const int Snapshot::context_raw_size_ = %d;\n",
+ partial_sink_.raw_size());
fprintf(fp_, "const byte Snapshot::context_data_[] = {\n");
- for (int j = 0; j < length; j++) {
- if ((j & 0x1f) == 0x1f) {
- fprintf(fp_, "\n");
- }
- char byte = partial_sink_.at(j);
- if (j != 0) {
- fprintf(fp_, ",");
- }
- fprintf(fp_, "%d", byte);
- }
+ 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
}
- virtual void Put(int byte, const char* description) {
- if (bytes_written_ != 0) {
- fprintf(fp_, ",");
- }
- fprintf(fp_, "%d", byte);
- bytes_written_++;
- if ((bytes_written_ & 0x1f) == 0) {
- fprintf(fp_, "\n");
- }
+ void WriteSnapshot() {
+ Print(fp_);
}
- virtual int Position() {
- return bytes_written_;
- }
+ PartialSnapshotSink* partial_sink() { return &partial_sink_; }
+
+ private:
+ FILE* fp_;
+ PartialSnapshotSink partial_sink_;
+};
- i::SnapshotByteSink* partial_sink() { return &partial_sink_; }
- class PartialSnapshotSink : public i::SnapshotByteSink {
- public:
- explicit PartialSnapshotSink(CppByteSink* parent)
- : parent_(parent),
- data_() { }
- virtual ~PartialSnapshotSink() { data_.Free(); }
- virtual void Put(int byte, const char* description) {
- data_.Add(byte);
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+class BZip2Compressor : public Compressor {
+ public:
+ BZip2Compressor() : output_(NULL) {}
+ virtual ~BZip2Compressor() {
+ delete output_;
+ }
+ virtual bool Compress(i::Vector<char> input) {
+ delete output_;
+ output_ = new i::ScopedVector<char>((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 int Position() { return data_.length(); }
- char at(int i) { return data_[i]; }
- private:
- CppByteSink* parent_;
- i::List<char> data_;
- };
+ }
+ virtual i::Vector<char>* output() { return output_; }
private:
- FILE* fp_;
- int bytes_written_;
- PartialSnapshotSink partial_sink_;
+ i::ScopedVector<char>* output_;
};
+#endif
int main(int argc, char** argv) {
ser.SerializeWeakReferences();
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+ BZip2Compressor compressor;
+ if (!sink.Compress(&compressor))
+ return 1;
+ if (!sink.partial_sink()->Compress(&compressor))
+ return 1;
+#endif
+ sink.WriteSnapshot();
sink.WritePartialSnapshot();
sink.WriteSpaceUsed(
DeleteArray(str);
return true;
} else if (size_ > 0) {
- Deserialize(data_, size_);
+ Deserialize(raw_data_, raw_size_);
return true;
}
return false;
map_space_used_,
cell_space_used_,
large_space_used_);
- SnapshotByteSource source(context_data_, context_size_);
+ SnapshotByteSource source(context_raw_data_,
+ context_raw_size_);
Deserializer deserializer(&source);
Object* root;
deserializer.DeserializePartial(&root);
namespace internal {
const byte Snapshot::data_[] = { 0 };
+const byte* Snapshot::raw_data_ = NULL;
const int Snapshot::size_ = 0;
+const int Snapshot::raw_size_ = 0;
const byte Snapshot::context_data_[] = { 0 };
+const byte* Snapshot::context_raw_data_ = NULL;
const int Snapshot::context_size_ = 0;
+const int Snapshot::context_raw_size_ = 0;
const int Snapshot::new_space_used_ = 0;
const int Snapshot::pointer_space_used_ = 0;
// successfully.
static bool WriteToFile(const char* snapshot_file);
+ static const byte* data() { return data_; }
+ static int size() { return size_; }
+ static int raw_size() { return raw_size_; }
+ static void set_raw_data(const byte* raw_data) {
+ raw_data_ = raw_data;
+ }
+ static const byte* context_data() { return context_data_; }
+ static int context_size() { return context_size_; }
+ static int context_raw_size() { return context_raw_size_; }
+ static void set_context_raw_data(
+ const byte* context_raw_data) {
+ context_raw_data_ = context_raw_data;
+ }
+
private:
static const byte data_[];
+ static const byte* raw_data_;
static const byte context_data_[];
+ static const byte* context_raw_data_;
static const int new_space_used_;
static const int pointer_space_used_;
static const int data_space_used_;
static const int cell_space_used_;
static const int large_space_used_;
static const int size_;
+ static const int raw_size_;
static const int context_size_;
+ static const int context_raw_size_;
static bool Deserialize(const byte* content, int len);
'use_system_v8%': 0,
'msvs_use_common_release': 0,
'gcc_version%': 'unknown',
+ 'v8_compress_startup_data%': 'false',
'v8_target_arch%': '<(target_arch)',
'v8_use_snapshot%': 'true',
'v8_use_liveobjectlist%': 'false',
'LIVEOBJECTLIST',
],
}],
+ ['v8_compress_startup_data=="bz2"', {
+ 'defines': [
+ 'COMPRESS_STARTUP_DATA_BZ2',
+ ],
+ }],
],
'configurations': {
'Debug': {
'libraries': [
# Needed for clock_gettime() used by src/platform-linux.cc.
'-lrt',
- ]},
+ ],
+ 'conditions': [
+ ['v8_compress_startup_data=="bz2"', {
+ 'libraries': [
+ '-lbz2',
+ ]}],
+ ],
+ },
'sources': [
'../../src/platform-linux.cc',
'../../src/platform-posix.cc'
['v8_target_arch=="arm" and host_arch=="x64" and _toolset=="host"', {
'cflags': ['-m32'],
'ldflags': ['-m32'],
- }]
+ }],
+ ['v8_compress_startup_data=="bz2"', {
+ 'libraries': [
+ '-lbz2',
+ ]}],
]
},
{
# This could be gotten by not setting chromium_code, if that's OK.
'defines': ['_CRT_SECURE_NO_WARNINGS'],
}],
+ ['v8_compress_startup_data=="bz2"', {
+ 'libraries': [
+ '-lbz2',
+ ]}],
],
},
],