Initial push.
diff --git a/tools/apk-masseur.py b/tools/apk-masseur.py
new file mode 100755
index 0000000..b0c990f
--- /dev/null
+++ b/tools/apk-masseur.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import glob
+import optparse
+import os
+import shutil
+import subprocess
+import sys
+import utils
+
+USAGE = 'usage: %prog [options] <apk>'
+
+def parse_options():
+  parser = optparse.OptionParser(usage=USAGE)
+  parser.add_option('--dex',
+                    help='directory with dex files to use instead of those in the apk',
+                    default=None)
+  parser.add_option('--out',
+                    help='output file (default ./$(basename <apk>))',
+                    default=None)
+  parser.add_option('--keystore',
+                    help='keystore file (default ~/.android/app.keystore)',
+                    default=None)
+  (options, args) = parser.parse_args()
+  if len(args) != 1:
+    parser.error('Expected <apk> argument, got: ' + ' '.join(args))
+  apk = args[0]
+  if not options.out:
+    options.out = os.path.basename(apk)
+  if not options.keystore:
+    options.keystore = findKeystore()
+  return (options, apk)
+
+def findKeystore():
+  return os.path.join(os.getenv('HOME'), '.android', 'app.keystore')
+
+def repack(processed_out, original_apk, temp):
+  processed_apk = os.path.join(temp, 'processed.apk')
+  shutil.copyfile(original_apk, processed_apk)
+  if not processed_out:
+    print 'Using original APK as is'
+    return processed_apk
+  print 'Repacking APK with dex files from', processed_apk
+  with utils.ChangedWorkingDirectory(temp):
+    cmd = ['zip', '-d', 'processed.apk', '*.dex']
+    utils.PrintCmd(cmd)
+    subprocess.check_call(cmd)
+  if processed_out.endswith('.zip') or processed_out.endswith('.jar'):
+    cmd = ['unzip', processed_out, '-d', temp]
+    utils.PrintCmd(cmd)
+    subprocess.check_call(cmd)
+    processed_out = temp
+  with utils.ChangedWorkingDirectory(processed_out):
+    dex = glob.glob('*.dex')
+    cmd = ['zip', '-u', '-9', processed_apk] + dex
+    utils.PrintCmd(cmd)
+    subprocess.check_call(cmd)
+  return processed_apk
+
+def sign(unsigned_apk, keystore, temp):
+  print 'Signing (ignore the warnings)'
+  cmd = ['zip', '-d', unsigned_apk, 'META-INF/*']
+  utils.PrintCmd(cmd)
+  subprocess.call(cmd)
+  signed_apk = os.path.join(temp, 'unaligned.apk')
+  cmd = [
+    'jarsigner',
+    '-sigalg', 'SHA1withRSA',
+    '-digestalg', 'SHA1',
+    '-keystore', keystore,
+    '-storepass', 'android',
+    '-signedjar', signed_apk,
+    unsigned_apk,
+    'androiddebugkey'
+  ]
+  utils.PrintCmd(cmd)
+  subprocess.check_call(cmd)
+  return signed_apk
+
+def align(signed_apk, temp):
+  print 'Aligning'
+  aligned_apk = os.path.join(temp, 'aligned.apk')
+  cmd = ['zipalign', '-f', '4', signed_apk, aligned_apk]
+  print ' '.join(cmd)
+  subprocess.check_call(cmd)
+  return signed_apk
+
+def main():
+  (options, apk) = parse_options()
+  with utils.TempDir() as temp:
+    processed_apk = None
+    if options.dex:
+      processed_apk = repack(options.dex, apk, temp)
+    else:
+      print 'Signing original APK without modifying dex files'
+      processed_apk = os.path.join(temp, 'processed.apk')
+      shutil.copyfile(apk, processed_apk)
+    signed_apk = sign(processed_apk, options.keystore, temp)
+    aligned_apk = align(signed_apk, temp)
+    print 'Writing result to', options.out
+    shutil.copyfile(aligned_apk, options.out)
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/benchmarks/android-sdk-linux.tar.gz.sha1 b/tools/benchmarks/android-sdk-linux.tar.gz.sha1
new file mode 100644
index 0000000..fb3189e
--- /dev/null
+++ b/tools/benchmarks/android-sdk-linux.tar.gz.sha1
@@ -0,0 +1 @@
+3ac4b26ffd445020e5927331dfe7f8268efa6696
diff --git a/tools/benchmarks/get_deps.py b/tools/benchmarks/get_deps.py
new file mode 100644
index 0000000..cd28efe
--- /dev/null
+++ b/tools/benchmarks/get_deps.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import os
+import sys
+
+import main_utils
+utils = main_utils.GetUtils();
+
+ANDROID_EMULATORS = os.path.join(utils.TOOLS_DIR, 'benchmarks',
+                                 'android-sdk-linux.tar.gz.sha1')
+
+def Main():
+  utils.DownloadFromGoogleCloudStorage(ANDROID_EMULATORS)
+
+if __name__ == '__main__':
+  sys.exit(Main())
+
+
diff --git a/tools/benchmarks/main_utils.py b/tools/benchmarks/main_utils.py
new file mode 100644
index 0000000..b3ea703
--- /dev/null
+++ b/tools/benchmarks/main_utils.py
@@ -0,0 +1,13 @@
+# Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import imp
+import os
+
+TOOLS_DIR = os.path.abspath(
+    os.path.normpath(os.path.join(__file__, '..', '..')))
+
+def GetUtils():
+  '''Dynamically load the tools/utils.py python module.'''
+  return imp.load_source('utils', os.path.join(TOOLS_DIR, 'utils.py'))
diff --git a/tools/bisect.py b/tools/bisect.py
new file mode 100755
index 0000000..c8d1501
--- /dev/null
+++ b/tools/bisect.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import gradle
+import os
+import subprocess
+import sys
+import utils
+
+JAR = os.path.join(utils.REPO_ROOT, 'build', 'libs', 'bisect.jar')
+
+def run(args, build, debug):
+  if build:
+    gradle.RunGradle(['bisect'])
+  cmd = ['java']
+  if debug:
+    cmd.append('-ea')
+  cmd.extend(['-jar', JAR])
+  cmd.extend(args)
+  subprocess.check_call(cmd)
+
+def main():
+  build = True
+  args = []
+  for arg in sys.argv[1:]:
+    if arg in ("--build", "--no-build"):
+      build = arg == "--build"
+    else:
+      args.append(arg)
+  run(args, build, True)
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/d8.py b/tools/d8.py
new file mode 100755
index 0000000..cb0c841
--- /dev/null
+++ b/tools/d8.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import gradle
+import os
+import subprocess
+import sys
+import utils
+
+D8_JAR = os.path.join(utils.REPO_ROOT, 'build', 'libs', 'd8.jar')
+
+def run(args, build = True, debug = True, profile = False, track_memory_file=None):
+  if build:
+    gradle.RunGradle(['D8'])
+  cmd = []
+  if track_memory_file:
+    cmd.extend(['tools/track_memory.sh', track_memory_file])
+  cmd.append('java')
+  if debug:
+    cmd.append('-ea')
+  if profile:
+    cmd.append('-agentlib:hprof=cpu=samples,interval=1,depth=8')
+  cmd.extend(['-jar', D8_JAR])
+  cmd.extend(args)
+  subprocess.check_call(cmd)
+
+def main():
+  build = True
+  args = []
+  for arg in sys.argv[1:]:
+    if arg in ("--build", "--no-build"):
+      build = arg == "--build"
+    else:
+      args.append(arg)
+  run(args, build)
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/docker/README.md b/tools/docker/README.md
new file mode 100644
index 0000000..bd9257e
--- /dev/null
+++ b/tools/docker/README.md
@@ -0,0 +1,5 @@
+To create the Docker image to run Art on non-Linux platforms cd into the `image` directory and run:
+
+```
+docker build -t r8 .
+```
diff --git a/tools/docker/image/Dockerfile b/tools/docker/image/Dockerfile
new file mode 100644
index 0000000..a308e46
--- /dev/null
+++ b/tools/docker/image/Dockerfile
@@ -0,0 +1,39 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+FROM debian:jessie
+
+RUN echo deb http://http.debian.net/debian jessie-backports main >> /etc/apt/sources.list
+
+RUN apt-get update && apt-get install -y \
+	bzip2 \
+	g++ \
+	gcc \
+	git \
+	nano \
+	python \
+	python-dev \
+	sed \
+	texinfo \
+	unzip \
+	wget \
+    sudo
+
+# Install OpenJDK 8 dependencies from jessi-backports (see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=851667)
+RUN apt-get install -y -t jessie-backports openjdk-8-jre-headless ca-certificates-java
+RUN apt-get install -y openjdk-8-jdk
+
+# Set the timezone.
+RUN echo "Europe/Copenhagen" > /etc/timezone && \
+    dpkg-reconfigure -f noninteractive tzdata
+
+ENV user r8
+
+# Create user without password and sudo access.
+RUN useradd -m -G dialout,sudo $user && \
+    echo "$user ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers.d/$user && \
+    chmod 440 /etc/sudoers.d/$user
+
+USER $user
+
+CMD (cd /home/$user && /bin/bash)
diff --git a/tools/docker/run.sh b/tools/docker/run.sh
new file mode 100755
index 0000000..7746b87
--- /dev/null
+++ b/tools/docker/run.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+PROG_NAME="$(follow_links $0)"
+PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+R8_ROOT=$PROG_DIR/../..
+
+CONTAINER_NAME=r8
+HOST_SHARE=$(cd "$R8_ROOT" ; pwd -P)
+CONTAINER_USER=r8
+CONTAINER_HOME=/home/$CONTAINER_USER
+CONTAINER_SHARE=$CONTAINER_HOME/share
+
+ARGS=$@
+
+docker run \
+  --volume $HOST_SHARE:$CONTAINER_SHARE \
+  --rm \
+  --workdir "$CONTAINER_SHARE" \
+  r8 \
+  bash -c "$ARGS"
+
diff --git a/tools/download_from_x20.py b/tools/download_from_x20.py
new file mode 100755
index 0000000..401fa53
--- /dev/null
+++ b/tools/download_from_x20.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+# Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Script for downloading from x20 a dependency in the same way we use cloud
+# storage.
+
+import optparse
+import os
+import shutil
+import subprocess
+import sys
+import tarfile
+import utils
+
+GMSCORE_DEPS = '/google/data/ro/teams/gmscore-size/deps'
+
+def parse_options():
+  return optparse.OptionParser().parse_args()
+
+def extract_dir(filename):
+  return filename[0:len(filename) - len('.tar.gz')]
+
+def unpack_archive(filename):
+  dest_dir = extract_dir(filename)
+  if os.path.exists(dest_dir):
+    print 'Deleting existing dir %s' % dest_dir
+    shutil.rmtree(dest_dir)
+  dirname = os.path.dirname(os.path.abspath(filename))
+  with tarfile.open(filename, 'r:gz') as tar:
+    tar.extractall(path=dirname)
+
+def Main():
+  (options, args) = parse_options()
+  assert len(args) == 1
+  sha1_file = args[0]
+  dest = sha1_file[:-5]
+  print 'Ensuring %s' % dest
+  with open(sha1_file, 'r') as input_sha:
+    sha1 = input_sha.readline()
+  if os.path.exists(dest) and utils.get_sha1(dest) == sha1:
+    print 'sha1 matches, not downloading'
+    dest_dir = extract_dir(dest)
+    if os.path.exists(dest_dir):
+      print 'destination directory exists, no extraction'
+    else:
+      unpack_archive(dest)
+    return
+  src = os.path.join(GMSCORE_DEPS, sha1)
+  if not os.path.exists(src):
+    print 'File (%s) does not exist on x20' % src
+  print 'Downloading %s to %s' % (src, dest)
+  shutil.copyfile(src, dest)
+  unpack_archive(dest)
+
+if __name__ == '__main__':
+  sys.exit(Main())
diff --git a/tools/gmscore_data.py b/tools/gmscore_data.py
new file mode 100644
index 0000000..4b9c430
--- /dev/null
+++ b/tools/gmscore_data.py
@@ -0,0 +1,101 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import glob
+import os
+import utils
+
+THIRD_PARTY = os.path.join(utils.REPO_ROOT, 'third_party')
+BASE = os.path.join(THIRD_PARTY, 'gmscore')
+
+V4_BASE = os.path.join(BASE, 'v4')
+V5_BASE = os.path.join(BASE, 'v5')
+V6_BASE = os.path.join(BASE, 'v6')
+V7_BASE = os.path.join(BASE, 'v7')
+V8_BASE = os.path.join(BASE, 'v8')
+
+V9_BASE = os.path.join(BASE, 'gmscore_v9')
+V9_PREFIX = os.path.join(V9_BASE, 'GmsCore_prod_alldpi_release_all_locales')
+
+V10_BASE = os.path.join(BASE, 'gmscore_v10')
+V10_PREFIX = os.path.join(V10_BASE, 'GmsCore_prod_alldpi_release_all_locales')
+
+# NOTE: we always use android.jar for SDK v25, later we might want to revise it
+#       to use proper android.jar version for each of gmscore version separately.
+ANDROID_JAR = os.path.join(THIRD_PARTY, 'android_jar', 'lib-v25', 'android.jar')
+
+VERSIONS = {
+  'v4': {
+    'dex' : {
+      'inputs' : glob.glob(os.path.join(V4_BASE, '*.dex')),
+      'pgmap' : os.path.join(V4_BASE, 'proguard.map'),
+      'libraries' : [ANDROID_JAR],
+      'r8-flags': '--ignore-missing-classes',
+    }
+  },
+  'v5': {
+    'dex' : {
+      'inputs' : glob.glob(os.path.join(V5_BASE, '*.dex')),
+      'pgmap' : os.path.join(V5_BASE, 'proguard.map'),
+      'libraries' : [ANDROID_JAR],
+      'r8-flags': '--ignore-missing-classes',
+    }
+  },
+  'v6': {
+    'dex' : {
+      'inputs' : glob.glob(os.path.join(V6_BASE, '*.dex')),
+      'pgmap' : os.path.join(V6_BASE, 'proguard.map'),
+      'libraries' : [ANDROID_JAR],
+      'r8-flags': '--ignore-missing-classes',
+    }
+  },
+  'v7': {
+    'dex' : {
+      'inputs' : glob.glob(os.path.join(V7_BASE, '*.dex')),
+      'pgmap' : os.path.join(V7_BASE, 'proguard.map'),
+      'libraries' : [ANDROID_JAR],
+      'r8-flags': '--ignore-missing-classes',
+    }
+  },
+  'v8': {
+    'dex' : {
+      'inputs' : glob.glob(os.path.join(V8_BASE, '*.dex')),
+      'pgmap' : os.path.join(V8_BASE, 'proguard.map'),
+      'libraries' : [ANDROID_JAR],
+      'r8-flags': '--ignore-missing-classes',
+    }
+  },
+  'v9': {
+    'dex' : {
+      'inputs': [os.path.join(V9_BASE, 'armv7_GmsCore_prod_alldpi_release.apk')],
+      'pgmap': '%s_proguard.map' % V9_PREFIX,
+      'libraries' : [ANDROID_JAR],
+      'r8-flags': '--ignore-missing-classes',
+    },
+    'deploy' : {
+      'pgconf': ['%s_proguard.config' % V9_PREFIX],
+      'inputs': ['%s_deploy.jar' % V9_PREFIX]
+    },
+    'proguarded' : {
+      'inputs': ['%s_proguard.jar' % V9_PREFIX],
+      'pgmap': '%s_proguard.map' % V9_PREFIX
+    }
+  },
+  'v10': {
+    'dex' : {
+      'inputs': [os.path.join(V10_BASE, 'armv7_GmsCore_prod_alldpi_release.apk')],
+      'pgmap': '%s_proguard.map' % V10_PREFIX,
+      'libraries' : [ANDROID_JAR],
+      'r8-flags': '--ignore-missing-classes',
+    },
+    'deploy' : {
+      'inputs': ['%s_deploy.jar' % V10_PREFIX],
+      'pgconf': ['%s_proguard.config' % V10_PREFIX],
+    },
+    'proguarded' : {
+      'inputs': ['%s_proguard.jar' % V10_PREFIX],
+      'pgmap': '%s_proguard.map' % V10_PREFIX
+    }
+  },
+}
diff --git a/tools/gradle.py b/tools/gradle.py
new file mode 100755
index 0000000..1945557
--- /dev/null
+++ b/tools/gradle.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Wrapper script for running gradle.
+# Will make sure we pulled down gradle before running, and will use the pulled
+# down version to have a consistent developer experience.
+
+import os
+import subprocess
+import sys
+import utils
+
+GRADLE_DIR = os.path.join(utils.REPO_ROOT, 'third_party', 'gradle')
+GRADLE_SHA1 = os.path.join(GRADLE_DIR, 'gradle.tar.gz.sha1')
+GRADLE = os.path.join(GRADLE_DIR, 'gradle', 'bin', 'gradle')
+
+def PrintCmd(s):
+  if type(s) is list:
+    s = ' '.join(s)
+  print 'Running: %s' % s
+  # I know this will hit os on windows eventually if we don't do this.
+  sys.stdout.flush()
+
+def EnsureGradle():
+  if not os.path.exists(GRADLE):
+    # Bootstrap gradle, everything else is controlled using gradle.
+    utils.DownloadFromGoogleCloudStorage(GRADLE_SHA1)
+  else:
+    print 'gradle.py: Gradle binary present'
+
+def RunGradle(args):
+  EnsureGradle()
+  cmd = [GRADLE]
+  cmd.extend(args)
+  utils.PrintCmd(cmd)
+  with utils.ChangedWorkingDirectory(utils.REPO_ROOT):
+    subprocess.check_call(cmd)
+
+def Main():
+  RunGradle(sys.argv[1:])
+
+if __name__ == '__main__':
+  sys.exit(Main())
diff --git a/tools/java2smali.sh b/tools/java2smali.sh
new file mode 100755
index 0000000..3b118c9
--- /dev/null
+++ b/tools/java2smali.sh
@@ -0,0 +1,39 @@
+# Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Rudmentary script for generating smali files from a Java file
+# compiled with both javac/dx and jack.
+
+# This requires a Android checkout in $HOME/android/master with the
+# art host test tools build:
+#
+#    source build/envsetup.sh
+#    lunch <some configuration, e.g. aosp_bullhead-userdebug>
+#    m -j30 test-art-host
+#
+# It also requires a checkout of https://github.com/JesusFreke/smali
+# in $HOME/smali build by running "gradle build" in that directory.
+#
+# The output from javac/dx is placed in classes_dx, and the output from
+# Jack is placed in classes_jack.
+
+set -e
+
+JAVA_FILE=Test.java
+
+ANDROID_HOME="$HOME/android/master"
+SMALI_HOME="$HOME/smali"
+
+# Build with javac/dx and decompile dex file.
+mkdir -p classes_dx
+javac -d classes_dx -target 1.7 -source 1.7 $JAVA_FILE
+tools/linux/dx/bin/dx --dex --output classes_dx/classes.dex classes_dx
+java -jar "$SMALI_HOME/baksmali/build/libs/baksmali.jar" --output classes_dx classes_dx/classes.dex
+
+# Build with Jack and decompile dex file.
+mkdir -p classes_jack
+JACK_JAVA_LIBRARIES="$ANDROID_HOME/out/host/common/obj/JAVA_LIBRARIES"
+JACK="$ANDROID_HOME/out/host/linux-x86/bin/jack -cp $JACK_JAVA_LIBRARIES/core-libart-hostdex_intermediates/classes.jack:$JACK_JAVA_LIBRARIES/core-oj-hostdex_intermediates/classes.jack"
+$JACK $JAVA_FILE --output-dex classes_jack
+java -jar $SMALI_HOME/baksmali/build/libs/baksmali.jar --output classes_jack classes_jack/classes.dex
diff --git a/tools/linux/README.art-versions b/tools/linux/README.art-versions
new file mode 100644
index 0000000..acca426
--- /dev/null
+++ b/tools/linux/README.art-versions
@@ -0,0 +1,82 @@
+Art versions in the directory, and where they were build from
+-------------------------------------------------------------
+
+See https://source.android.com/source/build-numbers.html for build numbers.
+
+Device names:
+
+  angler: Nexus 6P
+  mako: Nexus 4
+
+art (default)
+---------
+Build from branch master with art
+
+  mkdir master
+  cd master
+  repo init -u https://android.googlesource.com/platform/manifest -b master
+  repo sync -cq -j24
+  source build/envsetup.sh
+  lunch aosp_angler-eng
+  m -j24
+  m -j24 build-art
+  m -j24 test-art-host
+
+Collected into tools/linux/art
+
+  scripts/update-host-art.sh --android-checkout ~/android/master --art-dir art
+
+
+art-7.0.0
+---------
+Build from branch android-7.0.0_r21.
+
+  mkdir 7.0.0_r21
+  cd 7.0.0_r21
+  repo init -u https://android.googlesource.com/platform/manifest -b android-7.0.0_r21
+  repo sync
+  source build/envsetup.sh
+  lunch aosp_angler-userdebug
+  m -j24
+  m -j24 build-art
+  m -j24 test-art-host
+
+Collected into tools/linux/art-7.0.0.
+
+  scripts/update-host-art.sh --android-checkout ~/android/7.0.0_r21 --art-dir art-7.0.0
+
+art-6.0.1
+---------
+Build from branch android-6.0.1_r66.
+
+  mkdir 6.0.1_r66
+  cd 6.0.1_r66
+  repo init -u https://android.googlesource.com/platform/manifest -b android-6.0.1_r66
+  repo sync
+  source build/envsetup.sh
+  lunch aosp_angler-userdebug
+  m -j24
+  m -j24 build-art
+  m -j24 test-art-host
+
+Collected into tools/linux/art-6.0.1.
+
+  scripts/update-host-art.sh --android-checkout ~/android/6.0.1_r66 --art-dir art-6.0.1
+
+art-5.1.1
+---------
+Build from branch 5.1.1_r19.
+
+  mkdir 5.1.1_r19
+  cd 5.1.1_r19
+  repo init -u https://android.googlesource.com/platform/manifest -b android-5.1.1_r19
+  repo sync
+  source build/envsetup.sh
+  lunch aosp_mako-userdebug
+  m -j24
+  m -j24 build-art
+  m -j24 test-art-host
+
+Collected into tools/linux/art-5.1.1.
+
+  scripts/update-host-art.sh --android-checkout ~/android/5.1.1_r19 --art-dir art-5.1.1 --android-product mako
\ No newline at end of file
diff --git a/tools/linux/README.dalvik b/tools/linux/README.dalvik
new file mode 100644
index 0000000..ecd0286
--- /dev/null
+++ b/tools/linux/README.dalvik
@@ -0,0 +1,18 @@
+Build from branch android-4.4.4_r1
+
+mkdir kitkat
+cd kitkat
+repo init -u https://android.googlesource.com/platform/manifest -b  android-4.4.4_r1
+repo sync
+source build/envsetup.sh
+lunch aosp_x86-eng
+m -j24
+m -j24 dalvik
+m -j24 dalvikvm
+
+Collect
+ bin
+ framework
+ lib
+ usr
+into tools/linux/dalvik
diff --git a/tools/linux/art-5.1.1.tar.gz.sha1 b/tools/linux/art-5.1.1.tar.gz.sha1
new file mode 100644
index 0000000..86fef95
--- /dev/null
+++ b/tools/linux/art-5.1.1.tar.gz.sha1
@@ -0,0 +1 @@
+f19d1c9b77d34a1294301eeb9ef0f31c7cabae17
\ No newline at end of file
diff --git a/tools/linux/art-6.0.1.tar.gz.sha1 b/tools/linux/art-6.0.1.tar.gz.sha1
new file mode 100644
index 0000000..40391f2
--- /dev/null
+++ b/tools/linux/art-6.0.1.tar.gz.sha1
@@ -0,0 +1 @@
+cb65dc9c52727ea0f5a60f6145a83dc07ed06ecf
\ No newline at end of file
diff --git a/tools/linux/art-7.0.0.tar.gz.sha1 b/tools/linux/art-7.0.0.tar.gz.sha1
new file mode 100644
index 0000000..55f7b1c
--- /dev/null
+++ b/tools/linux/art-7.0.0.tar.gz.sha1
@@ -0,0 +1 @@
+6c2200d6ccca3bef135858736cd1eb0fa336bf65
\ No newline at end of file
diff --git a/tools/linux/art.tar.gz.sha1 b/tools/linux/art.tar.gz.sha1
new file mode 100644
index 0000000..3ad91fc
--- /dev/null
+++ b/tools/linux/art.tar.gz.sha1
@@ -0,0 +1 @@
+d82de0af429ec884d487efa2d4b41f4b522c9ecd
\ No newline at end of file
diff --git a/tools/linux/dalvik.tar.gz.sha1 b/tools/linux/dalvik.tar.gz.sha1
new file mode 100644
index 0000000..3aea456
--- /dev/null
+++ b/tools/linux/dalvik.tar.gz.sha1
@@ -0,0 +1 @@
+8350b21e7d340f44929d40ec26f7610cd45513f7
\ No newline at end of file
diff --git a/tools/linux/dx.tar.gz.sha1 b/tools/linux/dx.tar.gz.sha1
new file mode 100644
index 0000000..f13e394
--- /dev/null
+++ b/tools/linux/dx.tar.gz.sha1
@@ -0,0 +1 @@
+6976e6a1768527b2388b1fdda5868dfa6b80d844
\ No newline at end of file
diff --git a/tools/mac/art.tar.gz.sha1 b/tools/mac/art.tar.gz.sha1
new file mode 100644
index 0000000..16f98f3
--- /dev/null
+++ b/tools/mac/art.tar.gz.sha1
@@ -0,0 +1 @@
+70c71d3edd913372da5f33db05dba996d389c276
\ No newline at end of file
diff --git a/tools/mac/dx.tar.gz.sha1 b/tools/mac/dx.tar.gz.sha1
new file mode 100644
index 0000000..402acab
--- /dev/null
+++ b/tools/mac/dx.tar.gz.sha1
@@ -0,0 +1 @@
+5baa69bf12d60f4d3edf890e75b70c8a0df63a17
\ No newline at end of file
diff --git a/tools/r8.py b/tools/r8.py
new file mode 100755
index 0000000..b453227
--- /dev/null
+++ b/tools/r8.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import gradle
+import os
+import subprocess
+import sys
+import utils
+
+R8_JAR = os.path.join(utils.REPO_ROOT, 'build', 'libs', 'r8.jar')
+
+def run(args, build = True, debug = True, profile = False, track_memory_file=None):
+  if build:
+    gradle.RunGradle(['r8'])
+  cmd = []
+  if track_memory_file:
+    cmd.extend(['tools/track_memory.sh', track_memory_file])
+  cmd.append('java')
+  if debug:
+    cmd.append('-ea')
+  if profile:
+    cmd.append('-agentlib:hprof=cpu=samples,interval=1,depth=8')
+  cmd.extend(['-jar', R8_JAR])
+  cmd.extend(args)
+  utils.PrintCmd(cmd)
+  subprocess.check_call(cmd)
+
+def main():
+  build = True
+  args = []
+  for arg in sys.argv[1:]:
+    if arg in ("--build", "--no-build"):
+      build = arg == "--build"
+    else:
+      args.append(arg)
+  run(args, build)
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/run-d8-on-gmscore.py b/tools/run-d8-on-gmscore.py
new file mode 100755
index 0000000..e150278
--- /dev/null
+++ b/tools/run-d8-on-gmscore.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import d8
+import gmscore_data
+import optparse
+import os
+import sys
+
+def ParseOptions():
+  result = optparse.OptionParser()
+  result.add_option('--out',
+                    help = '',
+                    default = os.getcwd())
+  result.add_option('--no-build',
+                    help = '',
+                    default = False,
+                    action = 'store_true')
+  result.add_option('--no-debug',
+                    help = 'Run without debug asserts.',
+                    default = False,
+                    action = 'store_true')
+  result.add_option('--version',
+                    help = '',
+                    default = 'v9',
+                    choices = ['v9', 'v10'])
+  result.add_option('--type',
+                    help = '',
+                    default = 'proguarded',
+                    choices = ['proguarded', 'deploy'])
+  result.add_option('--d8-flags',
+                    help = 'Additional option(s) for D8. ' +
+                         'If passing several options use a quoted string.')
+  result.add_option('--track-memory-to-file',
+                    help = 'Track how much memory the jvm is using while ' +
+                    ' compiling. Output to the specified file.')
+  result.add_option('--profile',
+                    help = 'Profile D8 run.',
+                    default = False,
+                    action = 'store_true')
+  result.add_option('--dump-args-file',
+                    help = 'Dump a file with the arguments for the specified ' +
+                    'configuration. For use as a @<file> argument to perform ' +
+                    'the run.')
+  return result.parse_args()
+
+def main():
+  (options, args) = ParseOptions()
+  outdir = options.out
+  version = gmscore_data.VERSIONS[options.version]
+  values = version[options.type]
+  inputs = values['inputs']
+
+  args.extend(['--output', outdir])
+
+  if not os.path.exists(outdir):
+    os.makedirs(outdir)
+
+  if options.d8_flags:
+    args.extend(options.d8_flags.split(' '))
+
+  args.extend(inputs)
+
+  if options.dump_args_file:
+    with open(options.dump_args_file, 'w') as args_file:
+      args_file.writelines([arg + os.linesep for arg in args])
+  else:
+    d8.run(args, not options.no_build, not options.no_debug, options.profile,
+           options.track_memory_to_file)
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/run-jdwp-tests.py b/tools/run-jdwp-tests.py
new file mode 100755
index 0000000..d561e7e
--- /dev/null
+++ b/tools/run-jdwp-tests.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import os
+import subprocess
+import sys
+import utils
+
+DEFAULT_TEST = 'org.apache.harmony.jpda.tests.share.AllTests'
+
+TEST_RUNNER = 'org.junit.runner.JUnitCore'
+TEST_PACKAGE = 'org.apache.harmony.jpda.tests.jdwp'
+
+VERSIONS = [
+  'default',
+  '7.0.0',
+  '6.0.1',
+  '5.1.1',
+]
+
+BOOT_LIBS = [
+  'core-libart-hostdex.jar',
+  'core-oj-hostdex.jar',
+  'apache-xml-hostdex.jar',
+]
+
+JUNIT_HOSTDEX = os.path.join(
+  utils.REPO_ROOT,
+  'third_party', 'jdwp-tests', 'junit-hostdex.jar')
+
+JDWP_TESTS_HOSTDEX = os.path.join(
+  utils.REPO_ROOT,
+  'third_party', 'jdwp-tests', 'apache-harmony-jdwp-tests-hostdex.jar')
+
+IMAGE='/system/non/existent/jdwp/image.art'
+
+# Timeout in ms
+TIMEOUT=10000
+
+DEBUGGER_EXTRA_FLAGS = [
+  '-Xjnigreflimit:2000',
+  '-Duser.language=en',
+  '-Duser.region=US',
+  '-Djpda.settings.verbose=true',
+  '-Djpda.settings.transportAddress=127.0.0.1:55107',
+  '-Djpda.settings.timeout=%d' % TIMEOUT,
+  '-Djpda.settings.waitingTime=%d' % TIMEOUT
+]
+
+DEBUGGEE_EXTRA_FLAGS = [
+]
+
+def get_art_dir(version):
+  art_dir = version == 'default' and 'art' or 'art-%s' % version
+  return os.path.join(utils.REPO_ROOT, 'tools', 'linux', art_dir)
+
+def get_lib_dir(version):
+  return os.path.join(get_art_dir(version), 'lib')
+
+def get_fw_dir(version):
+  return os.path.join(get_art_dir(version), 'framework')
+
+def get_vm(version):
+  return os.path.join(get_art_dir(version), 'bin', 'dalvikvm64')
+
+def setup_environment(version):
+  art_dir = get_art_dir(version)
+  lib_dir = get_lib_dir(version)
+  android_data = os.path.join(utils.REPO_ROOT, 'build', 'tmp', version)
+  if not os.path.isdir(android_data):
+    os.mkdir(android_data)
+  os.environ['ANDROID_DATA'] = android_data
+  os.environ['ANDROID_ROOT'] = art_dir
+  os.environ['LD_LIBRARY_PATH'] = lib_dir
+  os.environ['DYLD_LIBRARY_PATH'] = lib_dir
+  os.environ['LD_USE_LOAD_BIAS'] = '1'
+
+def get_boot_libs(version):
+  return [os.path.join(get_fw_dir(version), lib) for lib in BOOT_LIBS]
+
+def get_common_flags(version):
+  flags = ['-Ximage:%s' % IMAGE]
+  if version != '5.1.1':
+    flags.extend(['-Xcompiler-option', '--debuggable'])
+    if version != '6.0.1':
+      flags.extend(['-Xcompiler-option', '--compiler-filter=interpret-only'])
+  return flags
+
+def get_debuggee_flags(version):
+  return get_common_flags(version) + DEBUGGEE_EXTRA_FLAGS
+
+def get_debugger_flags(version):
+  return get_common_flags(version) + DEBUGGER_EXTRA_FLAGS
+
+def runDebuggee(version, args):
+  art_dir = get_art_dir(version)
+  lib_dir = get_lib_dir(version)
+  fw_dir = get_fw_dir(version)
+  cmd = [get_vm(version)]
+  cmd.append('-Xbootclasspath:%s' % ':'.join(get_boot_libs(version)))
+  cmd.extend(get_debuggee_flags(version))
+  cmd.extend(args)
+  setup_environment(version)
+  print "Running debuggee as:", cmd
+  return subprocess.check_call(cmd)
+
+def runDebugger(version, classpath, args):
+  art_dir = get_art_dir(version)
+  lib_dir = get_lib_dir(version)
+  fw_dir = get_fw_dir(version)
+  dalvikvm = os.path.join(art_dir, 'bin', 'dalvikvm64')
+  cmd = [dalvikvm]
+  cmd.extend(['-classpath', '%s:%s' % (classpath, JUNIT_HOSTDEX)])
+  cmd.append('-Xbootclasspath:%s' % ':'.join(get_boot_libs(version)))
+  cmd.extend(get_debugger_flags(version))
+  cmd.append('-Djpda.settings.debuggeeJavaPath=%s %s' %\
+             (dalvikvm, ' '.join(get_debuggee_flags(version))))
+  cmd.extend(args)
+  setup_environment(version)
+  print "Running debugger as:", cmd
+  return subprocess.check_call(cmd)
+
+def usage():
+  print "Usage: %s [--debuggee] [--version=<version>] [--classpath=<classpath>] <args>" % (sys.argv[0])
+  print "where <version> is one of:", ', '.join(VERSIONS)
+  print "  and <classpath> is optional classpath (default: %s)" % JDWP_TESTS_HOSTDEX
+  print "  and <args> will be passed on as arguments to the art runtime."
+
+def main():
+  version = 'default'
+  debuggee = False
+  args = []
+  classpath = JDWP_TESTS_HOSTDEX
+  for arg in sys.argv[1:]:
+    if arg == '--help':
+      usage()
+      return 0
+    elif arg.startswith('--version='):
+      version = arg[len('--version='):]
+    elif arg.startswith('--classpath='):
+      classpath = arg[len('--classpath='):]
+    else:
+      args.append(arg)
+  if version not in VERSIONS:
+    print "Invalid version", version
+    usage()
+    return 1
+  if not debuggee and len(args) == 0:
+    args.append(DEFAULT_TEST)
+  if debuggee:
+    return runDebuggee(version, args)
+  else:
+    if len(args) == 0:
+      args.append(DEFAULT_TEST)
+    elif len(args) == 1:
+      args = [TEST_RUNNER, '%s.%s' % (TEST_PACKAGE, args[0])]
+    return runDebugger(version, classpath, args)
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/run-r8-on-gmscore.py b/tools/run-r8-on-gmscore.py
new file mode 100755
index 0000000..c00a58d
--- /dev/null
+++ b/tools/run-r8-on-gmscore.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import sys
+
+import run_r8_on_app
+
+if __name__ == '__main__':
+  sys.exit(run_r8_on_app.main())
diff --git a/tools/run_r8_on_app.py b/tools/run_r8_on_app.py
new file mode 100755
index 0000000..736d428
--- /dev/null
+++ b/tools/run_r8_on_app.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import optparse
+import os
+import r8
+import sys
+
+import gmscore_data
+import youtube_data
+
+TYPES = ['dex', 'deploy', 'proguarded']
+APPS = ['gmscore', 'youtube']
+
+def ParseOptions():
+  result = optparse.OptionParser()
+  result.add_option('--app',
+                    help='',
+                    default='gmscore',
+                    choices=APPS)
+  result.add_option('--type',
+                    help='',
+                    default='deploy',
+                    choices=TYPES)
+  result.add_option('--out',
+                    help='',
+                    default=os.getcwd())
+  result.add_option('--no-build',
+                    help='',
+                    default=False,
+                    action='store_true')
+  result.add_option('--no-libraries',
+                    help='',
+                    default=False,
+                    action='store_true')
+  result.add_option('--no-debug',
+                    help='Run without debug asserts.',
+                    default=False,
+                    action='store_true')
+  result.add_option('--version',
+                    help='')
+  result.add_option('-k',
+                    help='Override the default ProGuard keep rules')
+  result.add_option('--r8-flags',
+                    help='Additional option(s) for R8. ' +
+                         'If passing several options use a quoted string.')
+  result.add_option('--track-memory-to-file',
+                    help='Track how much memory the jvm is using while ' +
+                    ' compiling. Output to the specified file.')
+  result.add_option('--profile',
+                    help='Profile R8 run.',
+                    default=False,
+                    action='store_true')
+  result.add_option('--dump-args-file',
+                    help='Dump a file with the arguments for the specified ' +
+                    'configuration. For use as a @<file> argument to perform ' +
+                    'the run.')
+  return result.parse_args()
+
+def main():
+  (options, args) = ParseOptions()
+  outdir = options.out
+  data = None
+  if options.app == 'gmscore':
+    options.version = options.version or 'v9'
+    data = gmscore_data
+  elif options.app == 'youtube':
+    options.version = options.version or '12.10'
+    data = youtube_data
+  else:
+    raise 'Unexpected'
+
+  if not options.version in data.VERSIONS.keys():
+    print 'No version %s for application %s' % (options.version, options.app)
+    print 'Valid versions are %s' % data.VERSIONS.keys()
+    return 1
+
+  version = data.VERSIONS[options.version]
+
+  if options.type not in version:
+    print 'No type %s for version %s' % (options.type, options.version)
+    print 'Valid types are %s' % version.keys()
+    return 1
+  values = version[options.type]
+  inputs = None
+  # For 'deploy' the JAR is located using the Proguard configuration -injars option.
+  if 'inputs' in values and options.type != 'deploy':
+    inputs = values['inputs']
+
+  args.extend(['--output', outdir])
+  if 'pgmap' in values:
+    args.extend(['--pg-map', values['pgmap']])
+  if 'pgconf' in values and not options.k:
+    for pgconf in values['pgconf']:
+      args.extend(['--pg-conf', pgconf])
+  if options.k:
+    args.extend(['--pg-conf', options.k])
+  if not options.no_libraries and 'libraries' in values:
+    for lib in values['libraries']:
+      args.extend(['--lib', lib])
+
+  if not outdir.endswith('.zip') and not outdir.endswith('.jar') and not os.path.exists(outdir):
+    os.makedirs(outdir)
+
+  if 'r8-flags' in values:
+    args.extend(values['r8-flags'].split(' '))
+  if options.r8_flags:
+    args.extend(options.r8_flags.split(' '))
+
+  if inputs:
+    args.extend(inputs)
+
+  if options.dump_args_file:
+    with open(options.dump_args_file, 'w') as args_file:
+      args_file.writelines([arg + os.linesep for arg in args])
+  else:
+    r8.run(args, not options.no_build, not options.no_debug, options.profile,
+           options.track_memory_to_file)
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/test.py b/tools/test.py
new file mode 100755
index 0000000..2f5baf8
--- /dev/null
+++ b/tools/test.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+# Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Convenience script for running tests. If no argument is given run all tests,
+# if an argument is given, run only tests with that pattern. This script will
+# force the tests to run, even if no input changed.
+
+import gradle
+import optparse
+import sys
+
+ALL_ART_VMS = ["default", "7.0.0", "6.0.1", "5.1.1"]
+
+def ParseOptions():
+  result = optparse.OptionParser()
+  result.add_option('--no_internal',
+      help='Do not run Google internal tests.',
+      default=False, action='store_true')
+  result.add_option('--only_internal',
+      help='Only run Google internal tests.',
+      default=False, action='store_true')
+  result.add_option('--all_tests',
+      help='Run tests in all configurations.',
+      default=False, action='store_true')
+  result.add_option('-v', '--verbose',
+      help='Print test stdout to, well, stdout.',
+      default=False, action='store_true')
+  result.add_option('--dex_vm',
+      help='The android version of the vm to use. "all" will run the tests on '
+           'all art vm versions (stopping after first failed execution)',
+      default="default",
+      choices=ALL_ART_VMS + ["all"])
+  result.add_option('--one_line_per_test',
+      help='Print a line before a tests starts and after it ends to stdout.',
+      default=False, action='store_true')
+  result.add_option('--tool',
+      help='Tool to run ART tests with: "r8" (default) or "d8". Ignored if "--all_tests" enabled.',
+      default=None, choices=["r8", "d8"])
+  result.add_option('--jctf',
+      help='Run JCTF tests with: "r8" (default) or "d8".',
+      default=False, action='store_true')
+  result.add_option('--only_jctf',
+      help='Run only JCTF tests with: "r8" (default) or "d8".',
+      default=False, action='store_true')
+  result.add_option('--jctf_compile_only',
+      help="Don't run, only compile JCTF tests.",
+      default=False, action='store_true')
+
+  return result.parse_args()
+
+def Main():
+  (options, args) = ParseOptions()
+  gradle_args = ['cleanTest', 'test']
+  if len(args) > 1:
+    print("test.py takes at most one argument, the pattern for tests to run")
+    return -1
+  if options.verbose:
+    gradle_args.append('-Pprint_test_stdout')
+  if options.no_internal:
+    gradle_args.append('-Pno_internal')
+  if options.only_internal:
+    gradle_args.append('-Ponly_internal')
+  if options.all_tests:
+    gradle_args.append('-Pall_tests')
+  if options.tool:
+    gradle_args.append('-Ptool=%s' % options.tool)
+  if options.one_line_per_test:
+    gradle_args.append('-Pone_line_per_test')
+  if options.jctf:
+    gradle_args.append('-Pjctf')
+  if options.only_jctf:
+    gradle_args.append('-Ponly_jctf')
+  if options.jctf_compile_only:
+    gradle_args.append('-Pjctf_compile_only')
+  if len(args) > 0:
+    gradle_args.append('--tests')
+    gradle_args.append(args[0])
+
+  vms_to_test = [options.dex_vm] if options.dex_vm != "all" else ALL_ART_VMS
+  for art_vm in vms_to_test:
+    gradle.RunGradle(gradle_args + ['-Pdex_vm=%s' % art_vm])
+
+if __name__ == '__main__':
+  sys.exit(Main())
+
+
diff --git a/tools/track_memory.sh b/tools/track_memory.sh
new file mode 100755
index 0000000..c0b4716
--- /dev/null
+++ b/tools/track_memory.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+#
+# Tracks the peak resident memory being used by running the supplied command.
+# The output is written to the first argument of the script every second.
+
+function Logger() {
+  output="$1"
+  while sleep 1
+  do
+    grep "VmHWM\|Threads" /proc/$pid/status >> $output
+  done
+}
+
+function Exit {
+  kill $lid
+  exit 0
+}
+
+function Kill {
+  kill $lid
+  kill -9 $pid
+  exit -1
+}
+
+if [ $# -lt 2 ]; then
+   echo "Takes at least two arguments"
+   exit 1
+fi
+OUTPUT_FILE=$1
+shift 1
+
+$* &
+pid=$!
+
+Logger $OUTPUT_FILE &
+lid=$!
+
+trap "Exit" EXIT
+trap "Kill" SIGINT
+wait $pid
diff --git a/tools/upload_to_x20.py b/tools/upload_to_x20.py
new file mode 100755
index 0000000..fd7a072
--- /dev/null
+++ b/tools/upload_to_x20.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Script for uploading to x20 as a dependency in the same way we use cloud
+# storage.
+
+import optparse
+import os
+import shutil
+import stat
+import subprocess
+import sys
+import tarfile
+import utils
+
+GMSCORE_DEPS = '/google/data/rw/teams/gmscore-size/deps'
+
+def parse_options():
+  return optparse.OptionParser().parse_args()
+
+def create_archive(name):
+  tarname = '%s.tar.gz' % name
+  with tarfile.open(tarname, 'w:gz') as tar:
+    tar.add(name)
+  return tarname
+
+def Main():
+  (options, args) = parse_options()
+  assert len(args) == 1
+  name = args[0]
+  print 'Creating archive for %s' % name
+  if not name in os.listdir('.'):
+    print 'You must be standing directly below the directory you are uploading'
+    return 1
+  filename = create_archive(name)
+  sha1 = utils.get_sha1(filename)
+  dest = os.path.join(GMSCORE_DEPS, sha1)
+  print 'Uploading to %s' % dest
+  shutil.copyfile(filename, dest)
+  os.chmod(dest, stat.S_IRWXU | stat.S_IROTH | stat.S_IXOTH | stat.S_IRWXG)
+  sha1_file = '%s.sha1' % filename
+  with open(sha1_file, 'w') as output:
+    output.write(sha1)
+  print 'Sha (%s) written to: %s' % (sha1, sha1_file)
+
+if __name__ == '__main__':
+  sys.exit(Main())
diff --git a/tools/utils.py b/tools/utils.py
new file mode 100644
index 0000000..d5d27ca
--- /dev/null
+++ b/tools/utils.py
@@ -0,0 +1,64 @@
+# Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Different utility functions used accross scripts
+
+import hashlib
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+
+TOOLS_DIR = os.path.abspath(os.path.normpath(os.path.join(__file__, '..')))
+REPO_ROOT = os.path.realpath(os.path.join(TOOLS_DIR, '..'))
+DOWNLOAD_DEPS = os.path.join(REPO_ROOT, 'scripts', 'download-deps.sh')
+
+def PrintCmd(s):
+  if type(s) is list:
+    s = ' '.join(s)
+  print 'Running: %s' % s
+  # I know this will hit os on windows eventually if we don't do this.
+  sys.stdout.flush()
+
+def DownloadFromGoogleCloudStorage(sha1_file, bucket='r8-deps'):
+  cmd = ["download_from_google_storage", "-n", "-b", bucket, "-u", "-s",
+         sha1_file]
+  PrintCmd(cmd)
+  subprocess.check_call(cmd)
+
+def get_sha1(filename):
+  sha1 = hashlib.sha1()
+  with open(filename, 'rb') as f:
+    while True:
+      chunk = f.read(1024*1024)
+      if not chunk:
+        break
+      sha1.update(chunk)
+  return sha1.hexdigest()
+
+class TempDir(object):
+ def __init__(self, prefix=''):
+   self._temp_dir = None
+   self._prefix = prefix
+
+ def __enter__(self):
+   self._temp_dir = tempfile.mkdtemp(self._prefix)
+   return self._temp_dir
+
+ def __exit__(self, *_):
+   shutil.rmtree(self._temp_dir, ignore_errors=True)
+
+class ChangedWorkingDirectory(object):
+ def __init__(self, working_directory):
+   self._working_directory = working_directory
+
+ def __enter__(self):
+   self._old_cwd = os.getcwd()
+   print "Enter directory = ", self._working_directory
+   os.chdir(self._working_directory)
+
+ def __exit__(self, *_):
+   print "Enter directory = ", self._old_cwd
+   os.chdir(self._old_cwd)
diff --git a/tools/youtube_data.py b/tools/youtube_data.py
new file mode 100644
index 0000000..0fb39e3
--- /dev/null
+++ b/tools/youtube_data.py
@@ -0,0 +1,77 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import glob
+import os
+import utils
+
+THIRD_PARTY = os.path.join(utils.REPO_ROOT, 'third_party')
+BASE = os.path.join(THIRD_PARTY, 'youtube')
+
+V11_47_BASE = os.path.join(BASE, 'youtube.android_11.47')
+V11_47_PREFIX = os.path.join(V11_47_BASE, 'YouTubeRelease')
+
+V12_10_BASE = os.path.join(BASE, 'youtube.android_12.10')
+V12_10_PREFIX = os.path.join(V12_10_BASE, 'YouTubeRelease')
+
+V12_17_BASE = os.path.join(BASE, 'youtube.android_12.17')
+V12_17_PREFIX = os.path.join(V12_17_BASE, 'YouTubeRelease')
+
+# NOTE: we always use android.jar for SDK v25, later we might want to revise it
+#       to use proper android.jar version for each of youtube version separately.
+ANDROID_JAR = os.path.join(THIRD_PARTY, 'android_jar', 'lib-v25', 'android.jar')
+
+VERSIONS = {
+  '11.47': {
+    'dex' : {
+      'inputs': [os.path.join(V11_47_BASE, 'YouTubeRelease_unsigned.apk')],
+      'pgmap': '%s_proguard.map' % V11_47_PREFIX,
+      'libraries' : [ANDROID_JAR],
+      'r8-flags': '--ignore-missing-classes',
+    },
+    'deploy' : {
+      'inputs': ['%s_deploy.jar' % V11_47_PREFIX],
+      'pgconf': ['%s_proguard.config' % V11_47_PREFIX,
+                 '%s/proguardsettings/YouTubeRelease_proguard.config' % THIRD_PARTY],
+    },
+    'proguarded' : {
+      'inputs': ['%s_proguard.jar' % V11_47_PREFIX],
+      'pgmap': '%s_proguard.map' % V11_47_PREFIX
+    }
+  },
+  '12.10': {
+    'dex' : {
+      'inputs': [os.path.join(V12_10_BASE, 'YouTubeRelease_unsigned.apk')],
+      'pgmap': '%s_proguard.map' % V12_10_PREFIX,
+      'libraries' : [ANDROID_JAR],
+      'r8-flags': '--ignore-missing-classes',
+    },
+    'deploy' : {
+      'inputs': ['%s_deploy.jar' % V12_10_PREFIX],
+      'pgconf': ['%s_proguard.config' % V12_10_PREFIX,
+                 '%s/proguardsettings/YouTubeRelease_proguard.config' % THIRD_PARTY],
+    },
+    'proguarded' : {
+      'inputs': ['%s_proguard.jar' % V12_10_PREFIX],
+      'pgmap': '%s_proguard.map' % V12_10_PREFIX
+    }
+  },
+  '12.17': {
+    'dex' : {
+      'inputs': [os.path.join(V12_17_BASE, 'YouTubeRelease_unsigned.apk')],
+      'pgmap': '%s_proguard.map' % V12_17_PREFIX,
+      'libraries' : [ANDROID_JAR],
+      'r8-flags': '--ignore-missing-classes',
+    },
+    'deploy' : {
+      'inputs': ['%s_deploy.jar' % V12_17_PREFIX],
+      'pgconf': ['%s_proguard.config' % V12_17_PREFIX,
+                 '%s/proguardsettings/YouTubeRelease_proguard.config' % THIRD_PARTY],
+    },
+    'proguarded' : {
+      'inputs': ['%s_proguard.jar' % V12_17_PREFIX],
+      'pgmap': '%s_proguard.map' % V12_17_PREFIX
+    }
+  },
+}