Add V8 snapshot support
authorKent Hansen <kent.hansen@nokia.com>
Fri, 18 Nov 2011 08:48:54 +0000 (09:48 +0100)
committerQt by Nokia <qt-info@nokia.com>
Tue, 22 Nov 2011 12:10:56 +0000 (13:10 +0100)
A V8 snapshot is a serialized representation of the JavaScript heap.
Using a snapshot can vastly speed up V8 initialization.

This commit introduces a new tool, mkv8snapshot. mkv8snapshot is
automatically invoked as part of building QtV8, and generates a .cpp
file which is compiled into the QtV8 library.

Because mkv8snapshot itself needs to initialize the V8 environment
the non-snapshot way (i.e., by evaluating thousands of lines of
JavaScript), it needs to build all of V8. This means that V8 is
effectively built twice when snapshots are enabled.

When cross-compiling, only host=i386 and target=arm is supported,
since that's the only relevant case for which V8 currently
supports a simulator. mkv8snapshot is built and run as a host tool
(using the simulator), and generates a snapshot that will be used
on the target.

Task-number: QTBUG-21152
Change-Id: I9270652f129505508f78db8b0a39fbf57dc8b86d
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
.gitignore
configure
src/tools/mkv8snapshot/mkv8snapshot.pro [new file with mode: 0644]
src/tools/tools.pro
src/v8/v8.pri
src/v8/v8.pro
tools/configure/configureapp.cpp

index 6cc7f6d..03883f6 100644 (file)
@@ -64,6 +64,7 @@ bin/linguist*
 bin/lrelease*
 bin/lupdate*
 bin/lconvert*
+bin/mkv8snapshot*
 bin/moc*
 bin/makeqpf*
 bin/pixeltool*
index 1d3e4d9..f6b629a 100755 (executable)
--- a/configure
+++ b/configure
@@ -705,6 +705,7 @@ CFG_MULTIMEDIA=auto
 CFG_AUDIO_BACKEND=auto
 CFG_SVG=auto
 CFG_V8=auto
+CFG_V8SNAPSHOT=auto
 CFG_DECLARATIVE=auto
 CFG_DECLARATIVE_DEBUG=yes
 CFG_WEBKIT=auto # (yes|no|auto|debug)
@@ -7270,6 +7271,7 @@ canBuildQtXmlPatterns="yes"
 canBuildWebKit="$HAVE_STL"
 canBuildQtConcurrent="yes"
 canBuildV8="yes"
+canUseV8Snapshot="yes"
 
 # WebKit requires stdint.h
 "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/unix/stdint "Stdint" $L_FLAGS $I_FLAGS $l_FLAGS
@@ -7502,6 +7504,25 @@ if [ "$CFG_V8" = "no" ]; then
     QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_V8"
 else
     QT_CONFIG="$QT_CONFIG v8"
+    # Detect snapshot support
+    if [ "$CFG_ARCH" != "$CFG_HOST_ARCH" ]; then
+        case "$CFG_HOST_ARCH,$CFG_ARCH" in
+            i386,arm)
+            ;;
+        *) canUseV8Snapshot="no"
+            ;;
+        esac
+    fi
+    if [ "$CFG_V8SNAPSHOT" = "auto" ]; then
+        CFG_V8SNAPSHOT="$canUseV8Snapshot"
+    fi
+    if [ "$CFG_V8SNAPSHOT" = "yes" -a "$canUseV8Snapshot" = "no" ]; then
+        echo "Error: V8 snapshot was requested, but is not supported on this platform."
+        exit 1
+    fi
+    if [ "$CFG_V8SNAPSHOT" = "yes" ]; then
+        QT_CONFIG="$QT_CONFIG v8snapshot"
+    fi
 fi
 
 if [ "$CFG_DECLARATIVE" = "yes" ]; then
@@ -8666,6 +8687,13 @@ for file in .projects .projects.3; do
         *examples/activeqt/*) continue ;;
         */qmake/qmake.pro) continue ;;
         *tools/bootstrap*|*tools/moc*|*tools/rcc*|*tools/uic*|*linguist/lrelease*) SPEC=$QMAKESPEC ;;
+        *tools/mkv8snapshot/*)
+            if [ "$CFG_V8" = "yes" -a "$CFG_V8SNAPSHOT" = "yes" ]; then
+                SPEC=$QMAKESPEC
+            else
+                continue
+            fi
+            ;;
         *) if [ "$CFG_NOPROCESS" = "yes" ]; then
               continue
            else
diff --git a/src/tools/mkv8snapshot/mkv8snapshot.pro b/src/tools/mkv8snapshot/mkv8snapshot.pro
new file mode 100644 (file)
index 0000000..8e80ce2
--- /dev/null
@@ -0,0 +1,30 @@
+TEMPLATE        = app
+TARGET          = mkv8snapshot
+QT              =
+CONFIG          -= app_bundle
+CONFIG          -= qt
+CONFIG          += console
+
+DESTDIR         = ../../../bin
+INCLUDEPATH     += .
+DEPENDPATH      += .
+LIBS            =
+OBJECTS_DIR     = .
+
+cross_compile {
+    equals(QT_ARCH, arm): V8_TARGET_ARCH = arm
+}
+
+include(../../v8/v8.pri)
+
+cross_compile {
+    equals(V8_TARGET_ARCH, arm): SOURCES += $$V8SRC/arm/simulator-arm.cc
+}
+
+SOURCES += \
+    $$V8SRC/snapshot-empty.cc \
+    $$V8SRC/mksnapshot.cc
+
+unix:LIBS += -lpthread
+
+# We don't need to install this tool, it's only used for building v8.
index 5cbe923..89ce0be 100644 (file)
@@ -2,6 +2,7 @@ TEMPLATE = subdirs
 
 TOOLS_SUBDIRS = src_tools_bootstrap src_tools_moc src_tools_rcc
 !contains(QT_CONFIG, no-gui): TOOLS_SUBDIRS += src_tools_uic
+contains(QT_CONFIG, v8):contains(QT_CONFIG, v8snapshot): TOOLS_SUBDIRS += src_tools_mkv8snapshot
 # Set subdir and respective target name
 src_tools_bootstrap.subdir = $$QT_SOURCE_TREE/src/tools/bootstrap
 src_tools_bootstrap.target = sub-tools-bootstrap
@@ -11,6 +12,8 @@ src_tools_rcc.subdir = $$QT_SOURCE_TREE/src/tools/rcc
 src_tools_rcc.target = sub-rcc
 src_tools_uic.subdir = $$QT_SOURCE_TREE/src/tools/uic
 src_tools_uic.target = sub-uic
+src_tools_mkv8snapshot.subdir = $$QT_SOURCE_TREE/src/tools/mkv8snapshot
+src_tools_mkv8snapshot.target = sub-mkv8snapshot
 
 !wince*:!ordered {
     # Set dependencies for each subdir
index 868bbad..26feca9 100644 (file)
@@ -5,16 +5,19 @@ isEmpty(QT_ARCH) {
     load(qt_config)
 }
 
-equals(QT_ARCH, x86_64)|contains(CONFIG, x86_64):CONFIG += arch_x86_64
-else:equals(QT_ARCH, "i386"):CONFIG += arch_i386
-else:equals(QT_ARCH, "arm"):CONFIG += arch_arm
-else:equals(QMAKE_HOST.arch, armv7l):CONFIG += arch_arm
-else:equals(QMAKE_HOST.arch, armv5tel):CONFIG += arch_arm
-else:equals(QMAKE_HOST.arch, x86_64):CONFIG += arch_x86_64
-else:equals(QMAKE_HOST.arch, x86):CONFIG += arch_i386
-else:equals(QMAKE_HOST.arch, i386):CONFIG += arch_i386
-else:equals(QMAKE_HOST.arch, i686):CONFIG += arch_i386
-else:error("Couldn't detect supported architecture ($$QMAKE_HOST.arch/$$QT_ARCH). Currently supported architectures are: x64, x86 and arm")
+isEmpty(V8_TARGET_ARCH) {
+    # Detect target
+    equals(QT_ARCH, x86_64)|contains(CONFIG, x86_64):V8_TARGET_ARCH = x64
+    else:equals(QT_ARCH, "i386"):                    V8_TARGET_ARCH = ia32
+    else:equals(QT_ARCH, "arm"):                     V8_TARGET_ARCH = arm
+    else:equals(QMAKE_HOST.arch, armv7l):            V8_TARGET_ARCH = arm
+    else:equals(QMAKE_HOST.arch, armv5tel):          V8_TARGET_ARCH = arm
+    else:equals(QMAKE_HOST.arch, x86_64):            V8_TARGET_ARCH = x64
+    else:equals(QMAKE_HOST.arch, x86):               V8_TARGET_ARCH = ia32
+    else:equals(QMAKE_HOST.arch, i386):              V8_TARGET_ARCH = ia32
+    else:equals(QMAKE_HOST.arch, i686):              V8_TARGET_ARCH = ia32
+    else:error("Couldn't detect supported v8 architecture ($$QMAKE_HOST.arch/$$QT_ARCH). Currently supported architectures are: x64, x86 and arm")
+}
 
 include($$PWD/v8base.pri)
 
@@ -23,8 +26,6 @@ include($$PWD/v8base.pri)
 CONFIG(debug, debug|release):V8_GENERATED_SOURCES_DIR = generated-debug
 else:                        V8_GENERATED_SOURCES_DIR = generated-release
 
-!contains(QT_CONFIG, static): DEFINES += V8_SHARED BUILDING_V8_SHARED
-
 # this maybe removed in future
 DEFINES += ENABLE_DEBUGGER_SUPPORT
 
@@ -145,10 +146,7 @@ SOURCES += \
     $$V8SRC/extensions/gc-extension.cc \
     $$V8SRC/extensions/externalize-string-extension.cc
 
-SOURCES += \
-    $$V8SRC/snapshot-empty.cc \
-
-arch_arm {
+equals(V8_TARGET_ARCH, arm) {
 DEFINES += V8_TARGET_ARCH_ARM
 SOURCES += \
     $$V8SRC/arm/builtins-arm.cc \
@@ -169,9 +167,7 @@ SOURCES += \
     $$V8SRC/arm/regexp-macro-assembler-arm.cc \
     $$V8SRC/arm/stub-cache-arm.cc \
     $$V8SRC/arm/assembler-arm.cc
-}
-
-arch_i386 {
+} else:equals(V8_TARGET_ARCH, ia32) {
 DEFINES += V8_TARGET_ARCH_IA32
 SOURCES += \
     $$V8SRC/ia32/assembler-ia32.cc \
@@ -191,10 +187,8 @@ SOURCES += \
     $$V8SRC/ia32/macro-assembler-ia32.cc \
     $$V8SRC/ia32/regexp-macro-assembler-ia32.cc \
     $$V8SRC/ia32/stub-cache-ia32.cc
-}
-
-# FIXME Should we use QT_CONFIG instead? What about 32 bit Macs?
-arch_x86_64 {
+} else:equals(V8_TARGET_ARCH, x64) {
+# FIXME What about 32-bit Macs?
 DEFINES += V8_TARGET_ARCH_X64
 SOURCES += \
     $$V8SRC/x64/assembler-x64.cc \
index ae43f24..1bc542e 100644 (file)
@@ -22,4 +22,20 @@ INCLUDEPATH -= $$MODULE_INCLUDES $$MODULE_INCLUDES/..
 
 HEADERS += $$QT_SOURCE_TREE/src/v8/qtv8version.h
 
+!contains(QT_CONFIG, static): DEFINES += V8_SHARED BUILDING_V8_SHARED
+
 include(v8.pri)
+
+contains(QT_CONFIG, v8snapshot) {
+    mkv8snapshot.commands = ../../bin/mkv8snapshot ${QMAKE_FILE_OUT}
+    DUMMY_FILE = v8.pro
+    mkv8snapshot.input = DUMMY_FILE
+    mkv8snapshot.output = $$V8_GENERATED_SOURCES_DIR/snapshot.cpp
+    mkv8snapshot.variable_out = SOURCES
+    mkv8snapshot.dependency_type = TYPE_C
+    mkv8snapshot.name = generating[v8] ${QMAKE_FILE_IN}
+    silent:mkv8snapshot.commands = @echo generating[v8] ${QMAKE_FILE_IN} && $$mkv8snapshot.commands
+    QMAKE_EXTRA_COMPILERS += mkv8snapshot
+} else {
+    SOURCES += $$V8SRC/snapshot-empty.cc
+}
index 2bd1291..1048512 100644 (file)
@@ -255,6 +255,7 @@ Configure::Configure(int& argc, char** argv)
     dictionary[ "DIRECTSHOW" ]      = "no";
     dictionary[ "WEBKIT" ]          = "auto";
     dictionary[ "V8" ]              = "yes";
+    dictionary[ "V8SNAPSHOT" ]      = "auto";
     dictionary[ "DECLARATIVE" ]     = "auto";
     dictionary[ "DECLARATIVE_DEBUG" ]= "yes";
     dictionary[ "PLUGIN_MANIFESTS" ] = "yes";
@@ -2057,6 +2058,8 @@ bool Configure::checkAvailability(const QString &part)
         available = findFile("wmsdk.h");
     } else if (part == "MULTIMEDIA" || part == "SCRIPT" || part == "SCRIPTTOOLS" || part == "V8" || part == "DECLARATIVE") {
         available = true;
+    } else if (part == "V8SNAPSHOT") {
+        available = true;
     } else if (part == "WEBKIT") {
         available = (dictionary.value("QMAKESPEC") == "win32-msvc2005") || (dictionary.value("QMAKESPEC") == "win32-msvc2008") || (dictionary.value("QMAKESPEC") == "win32-msvc2010") || (dictionary.value("QMAKESPEC") == "win32-g++");
         if (dictionary[ "SHARED" ] == "no") {
@@ -2156,6 +2159,8 @@ void Configure::autoDetection()
         dictionary["WEBKIT"] = checkAvailability("WEBKIT") ? "yes" : "no";
     if (dictionary["V8"] == "auto")
         dictionary["V8"] = checkAvailability("V8") ? "yes" : "no";
+    if (dictionary["V8SNAPSHOT"] == "auto")
+        dictionary["V8SNAPSHOT"] = (dictionary["V8"] == "yes") && checkAvailability("V8SNAPSHOT") ? "yes" : "no";
     if (dictionary["DECLARATIVE"] == "auto")
         dictionary["DECLARATIVE"] = dictionary["V8"] == "yes" ? "yes" : "no";
     if (dictionary["DECLARATIVE_DEBUG"] == "auto")
@@ -2545,8 +2550,11 @@ void Configure::generateOutputVars()
     // We currently have no switch for QtSvg, so add it unconditionally.
     qtConfig += "svg";
 
-    if (dictionary[ "V8" ] == "yes")
+    if (dictionary[ "V8" ] == "yes") {
         qtConfig += "v8";
+        if (dictionary[ "V8SNAPSHOT" ] == "yes")
+            qtConfig += "v8snapshot";
+    }
 
     // Add config levels --------------------------------------------
     QStringList possible_configs = QStringList()